summaryrefslogtreecommitdiffstats
path: root/wizards/source
diff options
context:
space:
mode:
Diffstat (limited to 'wizards/source')
-rw-r--r--wizards/source/access2base/Application.xba1869
-rw-r--r--wizards/source/access2base/Collect.xba399
-rw-r--r--wizards/source/access2base/CommandBar.xba396
-rw-r--r--wizards/source/access2base/CommandBarControl.xba339
-rw-r--r--wizards/source/access2base/Control.xba2501
-rw-r--r--wizards/source/access2base/DataDef.xba598
-rw-r--r--wizards/source/access2base/Database.xba1889
-rw-r--r--wizards/source/access2base/Dialog.xba818
-rw-r--r--wizards/source/access2base/DoCmd.xba2662
-rw-r--r--wizards/source/access2base/Event.xba493
-rw-r--r--wizards/source/access2base/Field.xba923
-rw-r--r--wizards/source/access2base/Form.xba1129
-rw-r--r--wizards/source/access2base/L10N.xba540
-rw-r--r--wizards/source/access2base/Methods.xba300
-rw-r--r--wizards/source/access2base/Module.xba722
-rw-r--r--wizards/source/access2base/OptionGroup.xba315
-rw-r--r--wizards/source/access2base/PropertiesGet.xba1120
-rw-r--r--wizards/source/access2base/PropertiesSet.xba577
-rw-r--r--wizards/source/access2base/Property.xba152
-rw-r--r--wizards/source/access2base/Python.xba613
-rw-r--r--wizards/source/access2base/Recordset.xba1274
-rw-r--r--wizards/source/access2base/Root_.xba311
-rw-r--r--wizards/source/access2base/SubForm.xba757
-rw-r--r--wizards/source/access2base/TempVar.xba195
-rw-r--r--wizards/source/access2base/Test.xba14
-rw-r--r--wizards/source/access2base/Trace.xba438
-rw-r--r--wizards/source/access2base/UtilProperty.xba331
-rw-r--r--wizards/source/access2base/Utils.xba1308
-rw-r--r--wizards/source/access2base/_License.xba25
-rw-r--r--wizards/source/access2base/acConstants.xba395
-rw-r--r--wizards/source/access2base/access2base.py1473
-rw-r--r--wizards/source/access2base/dialog.xlb6
-rw-r--r--wizards/source/access2base/dlgFormat.xdl19
-rw-r--r--wizards/source/access2base/dlgTrace.xdl33
-rw-r--r--wizards/source/access2base/script.xlb34
-rw-r--r--wizards/source/config/dialog.xlc5
-rw-r--r--wizards/source/config/script.xlc5
-rw-r--r--wizards/source/configshare/dialog.xlc19
-rw-r--r--wizards/source/configshare/script.xlc19
-rw-r--r--wizards/source/depot/CommonLang.xba368
-rw-r--r--wizards/source/depot/Currency.xba195
-rw-r--r--wizards/source/depot/Depot.xba517
-rw-r--r--wizards/source/depot/Dialog2.xdl53
-rw-r--r--wizards/source/depot/Dialog3.xdl62
-rw-r--r--wizards/source/depot/Dialog4.xdl34
-rw-r--r--wizards/source/depot/Internet.xba356
-rw-r--r--wizards/source/depot/Lang_de.xba175
-rw-r--r--wizards/source/depot/Lang_en.xba175
-rw-r--r--wizards/source/depot/Lang_es.xba175
-rw-r--r--wizards/source/depot/Lang_fr.xba175
-rw-r--r--wizards/source/depot/Lang_it.xba175
-rw-r--r--wizards/source/depot/Lang_ja.xba175
-rw-r--r--wizards/source/depot/Lang_ko.xba175
-rw-r--r--wizards/source/depot/Lang_sv.xba174
-rw-r--r--wizards/source/depot/Lang_tw.xba175
-rw-r--r--wizards/source/depot/Lang_zh.xba175
-rw-r--r--wizards/source/depot/dialog.xlb7
-rw-r--r--wizards/source/depot/script.xlb19
-rw-r--r--wizards/source/depot/tools.xba217
-rw-r--r--wizards/source/euro/AutoPilotRun.xba415
-rw-r--r--wizards/source/euro/Common.xba289
-rw-r--r--wizards/source/euro/ConvertRun.xba334
-rw-r--r--wizards/source/euro/DlgConvert.xdl94
-rw-r--r--wizards/source/euro/DlgPassword.xdl32
-rw-r--r--wizards/source/euro/Hard.xba246
-rw-r--r--wizards/source/euro/Init.xba667
-rw-r--r--wizards/source/euro/Protect.xba192
-rw-r--r--wizards/source/euro/Soft.xba256
-rw-r--r--wizards/source/euro/Writer.xba89
-rw-r--r--wizards/source/euro/dialog.xlb6
-rw-r--r--wizards/source/euro/script.xlb12
-rw-r--r--wizards/source/formwizard/DBMeta.xba347
-rw-r--r--wizards/source/formwizard/DlgFormDB.xdl111
-rw-r--r--wizards/source/formwizard/FormWizard.xba440
-rw-r--r--wizards/source/formwizard/Language.xba297
-rw-r--r--wizards/source/formwizard/Layouter.xba397
-rw-r--r--wizards/source/formwizard/develop.xba550
-rw-r--r--wizards/source/formwizard/dialog.xlb5
-rw-r--r--wizards/source/formwizard/script.xlb10
-rw-r--r--wizards/source/formwizard/tools.xba363
-rw-r--r--wizards/source/gimmicks/AutoText.xba114
-rw-r--r--wizards/source/gimmicks/ChangeAllChars.xba92
-rw-r--r--wizards/source/gimmicks/GetTexts.xba536
-rw-r--r--wizards/source/gimmicks/ReadDir.xba322
-rw-r--r--wizards/source/gimmicks/ReadFolderDlg.xdl39
-rw-r--r--wizards/source/gimmicks/UserfieldDlg.xdl66
-rw-r--r--wizards/source/gimmicks/Userfields.xba236
-rw-r--r--wizards/source/gimmicks/dialog.xlb6
-rw-r--r--wizards/source/gimmicks/readdirs.dlgbin0 -> 3180 bytes
-rw-r--r--wizards/source/gimmicks/script.xlb9
-rw-r--r--wizards/source/imagelists/imagelists.ilst7
-rw-r--r--wizards/source/importwizard/API.xba216
-rw-r--r--wizards/source/importwizard/DialogModul.xba484
-rw-r--r--wizards/source/importwizard/FilesModul.xba783
-rw-r--r--wizards/source/importwizard/ImportDialog.xdl97
-rw-r--r--wizards/source/importwizard/Language.xba150
-rw-r--r--wizards/source/importwizard/Main.xba291
-rw-r--r--wizards/source/importwizard/dialog.xlb5
-rw-r--r--wizards/source/importwizard/script.xlb9
-rw-r--r--wizards/source/resources/resources_en_US.properties579
-rw-r--r--wizards/source/scriptforge/SF_Array.xba2608
-rw-r--r--wizards/source/scriptforge/SF_Dictionary.xba959
-rw-r--r--wizards/source/scriptforge/SF_Exception.xba1381
-rw-r--r--wizards/source/scriptforge/SF_FileSystem.xba2128
-rw-r--r--wizards/source/scriptforge/SF_L10N.xba825
-rw-r--r--wizards/source/scriptforge/SF_Platform.xba451
-rw-r--r--wizards/source/scriptforge/SF_PythonHelper.xba967
-rw-r--r--wizards/source/scriptforge/SF_Region.xba861
-rw-r--r--wizards/source/scriptforge/SF_Root.xba1070
-rw-r--r--wizards/source/scriptforge/SF_Services.xba639
-rw-r--r--wizards/source/scriptforge/SF_Session.xba1076
-rw-r--r--wizards/source/scriptforge/SF_String.xba2734
-rw-r--r--wizards/source/scriptforge/SF_TextStream.xba702
-rw-r--r--wizards/source/scriptforge/SF_Timer.xba466
-rw-r--r--wizards/source/scriptforge/SF_UI.xba1350
-rw-r--r--wizards/source/scriptforge/SF_Utils.xba1113
-rw-r--r--wizards/source/scriptforge/_CodingConventions.xba100
-rw-r--r--wizards/source/scriptforge/_ModuleModel.xba221
-rw-r--r--wizards/source/scriptforge/__License.xba25
-rw-r--r--wizards/source/scriptforge/dialog.xlb6
-rw-r--r--wizards/source/scriptforge/dlgConsole.xdl14
-rw-r--r--wizards/source/scriptforge/dlgProgress.xdl11
-rw-r--r--wizards/source/scriptforge/po/ScriptForge.pot975
-rw-r--r--wizards/source/scriptforge/po/en.po975
-rw-r--r--wizards/source/scriptforge/po/pt.po1141
-rw-r--r--wizards/source/scriptforge/python/ScriptForgeHelper.py317
-rw-r--r--wizards/source/scriptforge/python/scriptforge.py2539
-rw-r--r--wizards/source/scriptforge/script.xlb23
-rw-r--r--wizards/source/sfdatabases/SF_Database.xba825
-rw-r--r--wizards/source/sfdatabases/SF_Register.xba195
-rw-r--r--wizards/source/sfdatabases/__License.xba26
-rw-r--r--wizards/source/sfdatabases/dialog.xlb3
-rw-r--r--wizards/source/sfdatabases/script.xlb7
-rw-r--r--wizards/source/sfdialogs/SF_Dialog.xba1111
-rw-r--r--wizards/source/sfdialogs/SF_DialogControl.xba2084
-rw-r--r--wizards/source/sfdialogs/SF_DialogListener.xba113
-rw-r--r--wizards/source/sfdialogs/SF_Register.xba348
-rw-r--r--wizards/source/sfdialogs/__License.xba26
-rw-r--r--wizards/source/sfdialogs/dialog.xlb3
-rw-r--r--wizards/source/sfdialogs/script.xlb9
-rw-r--r--wizards/source/sfdocuments/SF_Base.xba993
-rw-r--r--wizards/source/sfdocuments/SF_Calc.xba4501
-rw-r--r--wizards/source/sfdocuments/SF_Chart.xba814
-rw-r--r--wizards/source/sfdocuments/SF_Document.xba1504
-rw-r--r--wizards/source/sfdocuments/SF_DocumentListener.xba114
-rw-r--r--wizards/source/sfdocuments/SF_Form.xba1535
-rw-r--r--wizards/source/sfdocuments/SF_FormControl.xba1888
-rw-r--r--wizards/source/sfdocuments/SF_Register.xba546
-rw-r--r--wizards/source/sfdocuments/SF_Writer.xba635
-rw-r--r--wizards/source/sfdocuments/__License.xba26
-rw-r--r--wizards/source/sfdocuments/dialog.xlb3
-rw-r--r--wizards/source/sfdocuments/script.xlb14
-rw-r--r--wizards/source/sfunittests/SF_Register.xba202
-rw-r--r--wizards/source/sfunittests/SF_UnitTest.xba1818
-rw-r--r--wizards/source/sfunittests/__License.xba26
-rw-r--r--wizards/source/sfunittests/dialog.xlb3
-rw-r--r--wizards/source/sfunittests/script.xlb7
-rw-r--r--wizards/source/sfwidgets/SF_Menu.xba590
-rw-r--r--wizards/source/sfwidgets/SF_MenuListener.xba129
-rw-r--r--wizards/source/sfwidgets/SF_PopupMenu.xba801
-rw-r--r--wizards/source/sfwidgets/SF_Register.xba184
-rw-r--r--wizards/source/sfwidgets/__License.xba26
-rw-r--r--wizards/source/sfwidgets/dialog.xlb3
-rw-r--r--wizards/source/sfwidgets/script.xlb9
-rw-r--r--wizards/source/standard/Module1.xba24
-rw-r--r--wizards/source/standard/dialog.xlb3
-rw-r--r--wizards/source/standard/script.xlb5
-rw-r--r--wizards/source/template/Autotext.xba190
-rw-r--r--wizards/source/template/Correspondence.xba303
-rw-r--r--wizards/source/template/DialogStyles.xdl32
-rw-r--r--wizards/source/template/ModuleAgenda.xba220
-rw-r--r--wizards/source/template/Samples.xba168
-rw-r--r--wizards/source/template/TemplateDialog.xdl46
-rw-r--r--wizards/source/template/dialog.xlb7
-rw-r--r--wizards/source/template/script.xlb8
-rw-r--r--wizards/source/tools/Debug.xba253
-rw-r--r--wizards/source/tools/DlgOverwriteAll.xdl34
-rw-r--r--wizards/source/tools/Listbox.xba370
-rw-r--r--wizards/source/tools/Misc.xba834
-rw-r--r--wizards/source/tools/ModuleControls.xba387
-rw-r--r--wizards/source/tools/Strings.xba469
-rw-r--r--wizards/source/tools/UCB.xba311
-rw-r--r--wizards/source/tools/dialog.xlb5
-rw-r--r--wizards/source/tools/script.xlb10
-rw-r--r--wizards/source/tutorials/Functions.xba385
-rw-r--r--wizards/source/tutorials/RoadMap.xba134
-rw-r--r--wizards/source/tutorials/ShowInfoDialog.xba322
-rw-r--r--wizards/source/tutorials/TutorialClose.xba32
-rw-r--r--wizards/source/tutorials/TutorialCloseDialog.xdl31
-rw-r--r--wizards/source/tutorials/TutorialCreator.xba27
-rw-r--r--wizards/source/tutorials/TutorialOpen.xba113
-rw-r--r--wizards/source/tutorials/TutorialOpenDialog.xdl38
-rw-r--r--wizards/source/tutorials/TutorialsDialog.xdl43
-rw-r--r--wizards/source/tutorials/dialog.xlb7
-rw-r--r--wizards/source/tutorials/script.xlb10
195 files changed, 89405 insertions, 0 deletions
diff --git a/wizards/source/access2base/Application.xba b/wizards/source/access2base/Application.xba
new file mode 100644
index 000000000..74bb43558
--- /dev/null
+++ b/wizards/source/access2base/Application.xba
@@ -0,0 +1,1869 @@
+<?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="Application" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const TRACEDEBUG = &quot;DEBUG&quot; &apos; To report values of variables
+Global Const TRACEINFO = &quot;INFO&quot; &apos; To report any event
+Global Const TRACEWARNING = &quot;WARNING&quot; &apos; To report some abnormal event
+Global Const TRACEERRORS = &quot;ERROR&quot; &apos; To report user errors - Default value
+Global Const TRACEFATAL = &quot;FATAL&quot; &apos; To report programmer errors - f.i. Wrong argument
+Global Const TRACEABORT = &quot;ABORT&quot; &apos; To report Access2Base internal errors
+Global Const TRACEANY = &quot;===&gt;&quot; &apos; Always reported
+ &apos; ERRORs, FATALs and ABORTs are also displayed in a MsgBox (except on specific request)
+ &apos; FATALs and ABORTs interrupt the program execution
+
+Global Const ERRINIT = 1500
+Global Const ERRDBNOTCONNECTED = 1501
+Global Const ERRMISSINGARGUMENTS = 1502
+Global Const ERRWRONGARGUMENT = 1503
+Global Const ERRMAINFORM = 1504
+Global Const ERRMETHOD = 1505
+Global Const ERRFILEACCESS = 1506
+Global Const ERRFORMNOTIDENTIFIED = 1507
+Global Const ERRFORMNOTFOUND = 1508
+Global Const ERRFORMNOTOPEN = 1509
+Global Const ERRDFUNCTION = 1510
+Global Const ERROPENFORM = 1511
+Global Const ERRPROPERTY = 1512
+Global Const ERRPROPERTYVALUE = 1513
+Global Const ERRINDEXVALUE = 1514
+Global Const ERRCOLLECTION = 1515
+Global Const ERRPROPERTYNOTARRAY = 1516
+Global Const ERRCONTROLNOTFOUND = 1517
+Global Const ERRNOACTIVEFORM = 1518
+Global Const ERRDATABASEFORM = 1519
+Global Const ERRFOCUSINGRID = 1520
+Global Const ERRNOGRIDINFORM = 1521
+Global Const ERRFINDRECORD = 1522
+Global Const ERRSQLSTATEMENT = 1523
+Global Const ERROBJECTNOTFOUND = 1524
+Global Const ERROPENOBJECT = 1525
+Global Const ERRCLOSEOBJECT = 1526
+Global Const ERRMETHOD = 1527
+Global Const ERRACTION = 1528
+Global Const ERRSENDMAIL = 1529
+Global Const ERRFORMYETOPEN = 1530
+Global Const ERRPROPERTYINIT = 1531
+Global Const ERRFILENOTCREATED = 1532
+Global Const ERRDIALOGNOTFOUND = 1533
+Global Const ERRDIALOGUNDEFINED = 1534
+Global Const ERRDIALOGSTARTED = 1535
+Global Const ERRDIALOGNOTSTARTED = 1536
+Global Const ERRRECORDSETNODATA = 1537
+Global Const ERRRECORDSETCLOSED = 1538
+Global Const ERRRECORDSETRANGE = 1539
+Global Const ERRRECORDSETFORWARD = 1540
+Global Const ERRFIELDNULL = 1541
+Global Const ERROVERFLOW = 1542
+Global Const ERRNOTACTIONQUERY = 1543
+Global Const ERRNOTUPDATABLE = 1544
+Global Const ERRUPDATESEQUENCE = 1545
+Global Const ERRNOTNULLABLE = 1546
+Global Const ERRROWDELETED = 1547
+Global Const ERRRECORDSETCLONE = 1548
+Global Const ERRQUERYDEFDELETED = 1549
+Global Const ERRTABLEDEFDELETED = 1550
+Global Const ERRTABLECREATION = 1551
+Global Const ERRFIELDCREATION = 1552
+Global Const ERRSUBFORMNOTFOUND = 1553
+Global Const ERRWINDOW = 1554
+Global Const ERRCOMPATIBILITY = 1555
+Global Const ERRPRECISION = 1556
+Global Const ERRMODULENOTFOUND = 1557
+Global Const ERRPROCEDURENOTFOUND = 1558
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const DBCONNECTBASE = 1 &apos; Connection from Base document (OpenConnection)
+Global Const DBCONNECTFORM = 2 &apos; Connection from a database-aware form (OpenConnection)
+Global Const DBCONNECTANY = 3 &apos; Connection from any document for data access only (OpenDatabase)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const DBMS_UNKNOWN = 0
+Global Const DBMS_HSQLDB1 = 1
+Global Const DBMS_HSQLDB2 = 2
+Global Const DBMS_FIREBIRD = 3
+Global Const DBMS_MSACCESS2003 = 4
+Global Const DBMS_MSACCESS2007 = 5
+Global Const DBMS_MYSQL = 6
+Global Const DBMS_POSTGRES = 7
+Global Const DBMS_SQLITE = 8
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const COLLALLDIALOGS = &quot;ALLDIALOGS&quot;
+Global Const COLLALLFORMS = &quot;ALLFORMS&quot;
+Global Const COLLALLMODULES = &quot;ALLMODULES&quot;
+Global Const COLLCOMMANDBARS = &quot;COMMANDBARS&quot;
+Global Const COLLCOMMANDBARCONTROLS = &quot;COMMANDBARCONTROLS&quot;
+Global Const COLLCONTROLS = &quot;CONTROLS&quot;
+Global Const COLLFORMS = &quot;FORMS&quot;
+Global Const COLLFIELDS = &quot;FIELDS&quot;
+Global Const COLLPROPERTIES = &quot;PROPERTIES&quot;
+Global Const COLLQUERYDEFS = &quot;QUERYDEFS&quot;
+Global Const COLLRECORDSETS = &quot;RECORDSETS&quot;
+Global Const COLLTABLEDEFS = &quot;TABLEDEFS&quot;
+Global Const COLLTEMPVARS = &quot;TEMPVARS&quot;
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const OBJAPPLICATION = &quot;APPLICATION&quot;
+Global Const OBJCOLLECTION = &quot;COLLECTION&quot;
+Global Const OBJCOMMANDBAR = &quot;COMMANDBAR&quot;
+Global Const OBJCOMMANDBARCONTROL = &quot;COMMANDBARCONTROL&quot;
+Global Const OBJCONTROL = &quot;CONTROL&quot;
+Global Const OBJDATABASE = &quot;DATABASE&quot;
+Global Const OBJDIALOG = &quot;DIALOG&quot;
+Global Const OBJEVENT = &quot;EVENT&quot;
+Global Const OBJFIELD = &quot;FIELD&quot;
+Global Const OBJFORM = &quot;FORM&quot;
+Global Const OBJMODULE = &quot;MODULE&quot;
+Global Const OBJOPTIONGROUP = &quot;OPTIONGROUP&quot;
+Global Const OBJPROPERTY = &quot;PROPERTY&quot;
+Global Const OBJQUERYDEF = &quot;QUERYDEF&quot;
+Global Const OBJRECORDSET = &quot;RECORDSET&quot;
+Global Const OBJSUBFORM = &quot;SUBFORM&quot;
+Global Const OBJTABLEDEF = &quot;TABLEDEF&quot;
+Global Const OBJTEMPVAR = &quot;TEMPVAR&quot;
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const CTLCONTROL = &quot;CONTROL&quot; &apos; ClassId
+Global Const CTLCHECKBOX = &quot;CHECKBOX&quot; &apos; 5
+Global Const CTLCOMBOBOX = &quot;COMBOBOX&quot; &apos; 7
+Global Const CTLCOMMANDBUTTON = &quot;COMMANDBUTTON&quot; &apos; 2
+Global Const CTLCURRENCYFIELD = &quot;CURRENCYFIELD&quot; &apos; 18
+Global Const CTLDATEFIELD = &quot;DATEFIELD&quot; &apos; 15
+Global Const CTLFILECONTROL = &quot;FILECONTROL&quot; &apos; 12
+Global Const CTLFIXEDTEXT = &quot;FIXEDTEXT&quot; &apos; 10
+Global Const CTLGRIDCONTROL = &quot;GRIDCONTROL&quot; &apos; 11
+Global Const CTLGROUPBOX = &quot;GROUPBOX&quot; &apos; 8
+Global Const CTLHIDDENCONTROL = &quot;HIDDENCONTROL&quot; &apos; 13
+Global Const CTLIMAGEBUTTON = &quot;IMAGEBUTTON&quot; &apos; 4
+Global Const CTLIMAGECONTROL = &quot;IMAGECONTROL&quot; &apos; 14
+Global Const CTLLISTBOX = &quot;LISTBOX&quot; &apos; 6
+Global Const CTLNAVIGATIONBAR = &quot;NAVIGATIONBAR&quot; &apos; 22
+Global Const CTLNUMERICFIELD = &quot;NUMERICFIELD&quot; &apos; 17
+Global Const CTLPATTERNFIELD = &quot;PATTERNFIELD&quot; &apos; 19
+Global Const CTLRADIOBUTTON = &quot;RADIOBUTTON&quot; &apos; 3
+Global Const CTLSCROLLBAR = &quot;SCROLLBAR&quot; &apos; 20
+Global Const CTLSPINBUTTON = &quot;SPINBUTTON&quot; &apos; 21
+Global Const CTLTEXTFIELD = &quot;TEXTFIELD&quot; &apos; 9
+Global Const CTLTIMEFIELD = &quot;TIMEFIELD&quot; &apos; 16
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const CTLFORMATTEDFIELD = &quot;FORMATTEDFIELD&quot; &apos; 9 (idem TextField)
+Global Const CTLFIXEDLINE = &quot;FIXEDLINE&quot; &apos; 24 (forced)
+Global Const CTLPROGRESSBAR = &quot;PROGRESSBAR&quot; &apos; 23 (forced)
+Global Const CTLSUBFORM = &quot;SUBFORMCONTROL&quot; &apos; None
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const CTLPARENTISFORM = &quot;FORM&quot;
+Global Const CTLPARENTISDIALOG = &quot;DIALOG&quot;
+Global Const CTLPARENTISSUBFORM = &quot;SUBFORM&quot;
+Global Const CTLPARENTISGRID = &quot;GRID&quot;
+Global Const CTLPARENTISGROUP = &quot;OPTIONGROUP&quot;
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Global Const MODDOCUMENT = &quot;DOCUMENT&quot;
+Global Const MODGLOBAL = &quot;GLOBAL&quot;
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Type DocContainer
+ Document As Object &apos; com.sun.star.comp.dba.ODatabaseDocument or SwXTextDocument or ScModelObj
+ Active As Boolean
+ DbConnect As Integer &apos; DBCONNECTxxx constants
+ URL As String
+ DbContainers() As Variant &apos; One entry by (data-aware) form
+End Type
+
+Type DbContainer
+ FormName As String &apos; name of data-aware form
+ Database As Object &apos; Database type
+End Type
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- Next variable is initialized to empty at each macro execution start ---
+REM --- Items in both lists correspond one by one ---
+Public vFormNamesList As Variant &apos; (0) Buffer of hierarchical form names =&gt; &quot;\;&quot; separated values
+ &apos; (1) Buffer of persistent form names =&gt; &quot;\;&quot; separated values
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AllDialogs(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return either a Collection or a Dialog object
+&apos; The dialogs are selected only if library is loaded
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;AllDialogs&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iMode As Integer, vDialogs() As Variant, i As Integer, j As Integer, iCount As Integer
+Dim oMacLibraries As Object, vAllDialogs As Variant, oLibrary As Object, vNames() As Variant, bFound As Boolean
+Dim oLibDialog As Object, sLibrary As String, oDocLibraries As Object, bLocalStorage As Boolean
+Dim vLibraries() As Variant, vMacLibraries() As Variant, vDocLibraries() As Variant, oDocMacLib As Object
+Dim vCurrentDocument As Variant
+Const cstCount = 0
+Const cstByIndex = 1
+Const cstByName = 2
+Const cstSepar = &quot;!&quot;
+
+ If IsMissing(pvIndex) Then
+ iMode = cstCount
+ Else
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ If VarType(pvIndex) = vbString Then iMode = cstByName Else iMode = cstByIndex
+ End If
+
+ Set vAllDialogs = Nothing
+
+ Set vCurrentDocument = Nothing
+ If Not IsNull(_A2B_.CurrentDocument) Then
+ Set vCurrentDocument = _A2B_.CurrentDocument.Document
+ ElseIf Not IsNull(ThisComponent) Then
+ Set vCurrentDocument = ThisComponent
+ End If
+ If IsNull(vCurrentDocument) Then
+ Set oDocLibraries = Nothing
+ vDocLibraries = Array()
+ Else
+ Set oDocLibraries = vCurrentDocument.DialogLibraries
+ vDocLibraries = oDocLibraries.getElementNames()
+ End If
+ Set oMacLibraries = GlobalScope.DialogLibraries
+ vMacLibraries = oMacLibraries.getElementNames()
+ &apos;Remove Access2Base from the list
+ If _A2B_.ExcludeA2B Then
+ For i = 0 To UBound(vMacLibraries)
+ If Left(vMacLibraries(i), 11) = &quot;Access2Base&quot; Then vMacLibraries(i) = &quot;&quot;
+ Next i
+ End If
+ vMacLibraries = Utils._TrimArray(vMacLibraries)
+
+ If UBound(vDocLibraries) + UBound(vMacLibraries) &lt; 0 Then &apos; No library
+ Set vAllDialogs = New Collect
+ Set vAllDialogs._This = vAllDialogs
+ vAllDialogs._CollType = COLLALLDIALOGS
+ vAllDialogs._Count = 0
+ Goto Exit_Function
+ End If
+
+ vNames = Array()
+ iCount = 0
+ For i = 0 To UBound(vDocLibraries) + UBound(vMacLibraries) + 1
+ bFound = False
+ If i &lt;= UBound(vDocLibraries) Then
+ sLibrary = vDocLibraries(i)
+ bLocalStorage = True
+ Set oDocMacLib = oDocLibraries
+ &apos; Sometimes library not loaded as should ??
+ If Not oDocMacLib.IsLibraryLoaded(sLibrary) Then oDocMacLib.loadLibrary(sLibrary)
+ Else
+ sLibrary = vMacLibraries(i - UBound(vDocLibraries) - 1)
+ bLocalStorage = False
+ Set oDocMacLib = oMacLibraries
+ End If
+ If oDocMacLib.IsLibraryLoaded(sLibrary) Then
+ Set oLibrary = oDocMacLib.getByName(sLibrary)
+ If oLibrary.hasElements() Then
+ vDialogs = oLibrary.getElementNames()
+ Select Case iMode
+ Case cstCount
+ iCount = iCount + UBound(vDialogs) + 1
+ Case cstByIndex, cstByName
+ For j = 0 To UBound(vDialogs)
+ If iMode = cstByIndex Then
+ If pvIndex = iCount Then bFound = True
+ iCount = iCount + 1
+ Else
+ If UCase(pvIndex) = UCase(vDialogs(j)) Then bFound = True
+ End If
+ If bFound Then
+ Set oLibDialog = oLibrary.getByName(vDialogs(j)) &apos; Create Dialog object
+ Exit For
+ End If
+ Next j
+ End Select
+ End If
+ End If
+ If bFound Then Exit For
+ Next i
+
+ If iMode = cstCount Then
+ Set vAllDialogs = New Collect
+ Set vAllDialogs._This = vAllDialogs
+ vAllDialogs._CollType = COLLALLDIALOGS
+ vAllDialogs._Count = iCount
+ Else
+ If Not bFound Then
+ If iMode = cstByIndex Then Goto Trace_Error_Index Else Goto Trace_Not_Found
+ End If
+ Set vAllDialogs = New Dialog
+ With vAllDialogs
+ ._This = vAllDialogs
+ ._Name = vDialogs(j)
+ ._Shortcut = &quot;Dialogs!&quot; &amp; vDialogs(j)
+ Set ._Dialog = oLibDialog
+ ._Library = sLibrary
+ ._Storage = Iif(bLocalStorage, &quot;DOCUMENT&quot;, &quot;GLOBAL&quot;)
+ End With
+ End If
+
+Exit_Function:
+ Set AllDialogs = vAllDialogs
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Not_Found:
+ TraceError(TRACEFATAL, ERRDIALOGNOTFOUND, Utils._CalledSub(), 0, , pvIndex)
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set vDialogs = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Set vDialogs = Nothing
+ GoTo Exit_Function
+End Function &apos; AllDialogs V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AllForms(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return an object of type Form indicated by either its index (integer) or its name (NOT CASE-SENSITIVE string)
+&apos; Easiest use for standalone forms: AllForms(0)
+&apos; If no argument, return a Collection type
+
+Const cstThisSub = &quot;AllForms&quot;
+Dim iIndex As Integer, vReturn As Variant
+Dim iCurrentDoc As Integer, vCurrentDoc As Variant, oForms As Variant, oCounter As Variant, oFormsCollection As Object
+Dim ofForm As Object
+Dim vAllForms As Variant, i As Integer, vName As Variant, oDatabase As Object, bFound As Boolean
+Const cstSeparator = &quot;\;&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ Set vReturn = Nothing
+
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ Select Case VarType(pvIndex)
+ Case vbString
+ iIndex = -1
+ Case Else
+ iIndex = pvIndex
+ End Select
+ End If
+
+ iCurrentDoc = _A2B_.CurrentDocIndex()
+ If iCurrentDoc &gt;= 0 Then
+ vCurrentDoc = _A2B_.CurrentDocument(iCurrentDoc)
+ Else
+ Goto Exit_Function
+ End If
+
+&apos; Load complete list of hierarchical and persistent names when Base document
+ If vCurrentDoc.DbConnect = DBCONNECTBASE Then vAllForms = _GetAllHierarchicalNames()
+
+&apos; Process when NO ARGUMENT
+ If IsMissing(pvIndex) Then &apos; No argument
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLALLFORMS
+ If vCurrentDoc.DbConnect = DBCONNECTFORM Then oCounter._Count = UBound(vCurrentDoc.DbContainers) + 1 Else oCounter._Count = UBound(vAllForms) + 1
+ Set vReturn = oCounter
+ Goto Exit_Function
+ End If
+
+&apos; Process when ARGUMENT = STRING or INDEX =&gt; Initialize form object
+ Set ofForm = New Form
+ Set ofForm._This = ofForm
+ Select Case vCurrentDoc.DbConnect
+ Case DBCONNECTBASE
+ ofForm._DocEntry = 0
+ ofForm._DbEntry = 0
+ If iIndex= -1 Then &apos; String argument
+ vName = Utils._InList(Utils._Trim(pvIndex), vAllForms, True)
+ If vName = False Then Goto Trace_Not_Found
+ ofForm._Initialize(vName)
+ Else
+ If iIndex &gt; UBound(vAllForms) Or iIndex &lt; 0 Then Goto Trace_Error_Index &apos; Numeric argument OK but value nonsense
+ ofForm._Initialize(vAllForms(iIndex))
+ End If
+ Case DBCONNECTFORM
+ With vCurrentDoc
+ If iIndex = -1 Then
+ bFound = False
+ For i = 0 To UBound(vCurrentDoc.DbContainers)
+ Set oDatabase = vCurrentDoc.DbContainers(i).Database
+ If UCase(Utils._Trim(pvIndex)) = UCase(oDatabase.FormName) Then
+ bFound = True
+ ofForm._DbEntry = i
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_Not_Found
+ ElseIf iIndex &lt; 0 Or iIndex &gt; UBound(vCurrentDoc.DbContainers) Then
+ Goto Trace_Error_Index
+ Else
+ ofForm._DbEntry = iIndex
+ Set oDatabase = vCurrentDoc.DbContainers(iIndex).Database
+ End If
+ End With
+ vName = oDatabase.FormName
+ ofForm._DocEntry = iCurrentDoc
+ ofForm._Initialize(vName)
+ End Select
+
+ Set vReturn = ofForm
+
+Exit_Function:
+ Set AllForms = vReturn
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Not_Found:
+ TraceError(TRACEFATAL, ERRFORMNOTFOUND, Utils._CalledSub(), 0, , pvIndex)
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set vReturn = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Set vReturn = Nothing
+ GoTo Exit_Function
+End Function &apos; AllForms V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AllModules(ByVal Optional pvIndex As Variant, ByVal Optional pbAllModules As Boolean) As Variant
+&apos; Return either a Collection or a Module object
+&apos; The modules are selected only if library is loaded
+&apos; (UNPUBLISHED) pbAllModules = False collects only the modules located in the currently open document
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;AllModules&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iMode As Integer, vModules() As Variant, i As Integer, j As Integer, iCount As Integer
+Dim oMacLibraries As Object, vAllModules As Variant, oLibrary As Object, vNames() As Variant, bFound As Boolean
+Dim sScript As String, sLibrary As String, oDocLibraries As Object, sStorage As String
+Dim vLibraries() As Variant, vMacLibraries() As Variant, vDocLibraries() As Variant, oDocMacLib As Object
+Const cstCount = 0, cstByIndex = 1, cstByName = 2
+Const cstDot = &quot;.&quot;
+
+ If IsMissing(pvIndex) Then
+ iMode = cstCount
+ Else
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ If VarType(pvIndex) = vbString Then
+ iMode = cstByName
+ &apos; Determine full name STORAGE.LIBRARY.MODULE
+ vNames = Split(pvIndex, cstDot)
+ If UBound(vNames) = 2 Then
+ ElseIf UBound(vNames) = 1 Then
+ pvIndex = MODDOCUMENT &amp; cstDot &amp; pvIndex
+ ElseIf UBound(vNames) = 0 Then
+ pvIndex = MODDOCUMENT &amp; cstDot &amp; &quot;STANDARD&quot; &amp; cstDot &amp; pvIndex
+ Else
+ GoTo Trace_Not_Found
+ End If
+ Else
+ iMode = cstByIndex
+ End If
+ End If
+
+ If IsMissing(pbAllModules) Then pbAllModules = True
+ If Not Utils._CheckArgument(pbAllModules, 2, vbBoolean) Then Goto Exit_Function
+
+ Set vAllModules = Nothing
+
+ Set oDocLibraries = _A2B_.CurrentDocument.Document.BasicLibraries &apos; ThisComponent.BasicLibraries
+ vDocLibraries = oDocLibraries.getElementNames()
+ If pbAllModules Then
+ Set oMacLibraries = GlobalScope.BasicLibraries
+ vMacLibraries = oMacLibraries.getElementNames()
+ &apos;Remove Access2Base from the list
+ If _A2B_.ExcludeA2B Then
+ For i = 0 To UBound(vMacLibraries)
+ If Left(vMacLibraries(i), 11) = &quot;Access2Base&quot; Then vMacLibraries(i) = &quot;&quot;
+ Next i
+ End If
+ vMacLibraries = Utils._TrimArray(vMacLibraries)
+ End If
+
+ If UBound(vDocLibraries) + UBound(vMacLibraries) &lt; 0 Then &apos; No library
+ Set vAllModules = New Collect
+ Set vAllModules._This = vAllModules
+ vAllModules._CollType = COLLALLMODULES
+ vAllModules._Count = 0
+ Goto Exit_Function
+ End If
+
+ iCount = 0
+ For i = 0 To UBound(vDocLibraries) + UBound(vMacLibraries) + 1
+ bFound = False
+ If i &lt;= UBound(vDocLibraries) Then
+ sLibrary = vDocLibraries(i)
+ sStorage = MODDOCUMENT
+ Set oDocMacLib = oDocLibraries
+ &apos; Sometimes library not loaded as should ??
+ If Not oDocMacLib.IsLibraryLoaded(sLibrary) Then oDocMacLib.loadLibrary(sLibrary)
+ Else
+ sLibrary = vMacLibraries(i - UBound(vDocLibraries) - 1)
+ sStorage = MODGLOBAL
+ Set oDocMacLib = oMacLibraries
+ End If
+ If oDocMacLib.IsLibraryLoaded(sLibrary) Then
+ Set oLibrary = oDocMacLib.getByName(sLibrary)
+ If oLibrary.hasElements() Then
+ vModules = oLibrary.getElementNames()
+ Select Case iMode
+ Case cstCount
+ iCount = iCount + UBound(vModules) + 1
+ Case cstByIndex, cstByName
+ For j = 0 To UBound(vModules)
+ If iMode = cstByIndex Then
+ If pvIndex = iCount Then bFound = True
+ iCount = iCount + 1
+ Else
+ If UCase(pvIndex) = UCase(sStorage &amp; cstDot &amp; sLibrary &amp; cstDot &amp; vModules(j)) Then bFound = True
+ End If
+ If bFound Then
+ sScript = oLibrary.getByName(vModules(j)) &apos; Initiate Module object
+ iCount = i
+ Exit For
+ End If
+ Next j
+ End Select
+ End If
+ End If
+ If bFound Then Exit For
+ Next i
+
+ If iMode = cstCount Then
+ Set vAllModules = New Collect
+ Set vAllModules._This =vAllModules
+ vAllModules._CollType = COLLALLMODULES
+ vAllModules._Count = iCount
+ Else
+ If Not bFound Then
+ If iMode = cstByIndex Then Goto Trace_Error_Index Else Goto Trace_Not_Found
+ End If
+ Set vAllModules = New Module
+ Set vAllModules._This = vAllModules
+ vAllModules._Name = vModules(j)
+ vAllModules._LibraryName = sLibrary
+ Set vAllModules._Library = oLibrary
+ vAllModules._Storage = sStorage
+ vAllModules._Script = sScript
+ vAllModules._Initialize()
+ End If
+
+Exit_Function:
+ Set AllModules = vAllModules
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Not_Found:
+ TraceError(TRACEFATAL, ERRMODULENOTFOUND, Utils._CalledSub(), 0, , pvIndex)
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set vModules = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Set vModules = Nothing
+ GoTo Exit_Function
+End Function &apos; AllModules V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub CloseConnection ()
+
+&apos; Close all connections established by current document to free memory.
+&apos; - if Base document =&gt; close the one concerned database connection
+&apos; - if non-Base documents =&gt; close the connections of each individual standalone form
+
+ If IsEmpty(_A2B_) Then Goto Exit_Sub
+
+Const cstThisSub = &quot;CloseConnection&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ Call _A2B_.CloseConnection()
+
+Exit_Sub:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Sub
+End Sub &apos; CloseConnection V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CommandBars(Optional ByVal pvIndex As Variant, Optional ByRef poWindow As Object) As Variant
+&apos; Return an object of type CommandBar indicated by its index or its name (CASE-INSENSITIVE string)
+&apos; If no pvIndex argument, return a Collection type
+&apos; (Unpublished) With poWindow, force the frame in which toolbars are detected
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;CommandBars&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iObjectsCount As Integer, sObjectName As String, oObject As Object
+Dim oWindow As Object, iWindowType As Integer
+Dim i As Integer, j As Integer, k As Integer, bFound As Boolean
+Dim sSupportedModules() As Variant, vModules() As Variant, oModuleUI As Object
+Dim oToolbar As Object, sToolbarName As String, vUIElements() As Variant, sToolbarFullName As String, iBuiltin As Integer
+
+Const cstCustom = &quot;CUSTOM&quot;
+
+ Set oObject = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+ iObjectsCount = 0
+ bFound = False
+
+ If IsMissing(poWindow) Then Set oWindow = _SelectWindow() Else Set oWindow = poWindow
+ If IsNull(oWindow.Frame) Then Goto Trace_WindowError
+
+ &apos; List of 21 modules
+ vModules = CreateUnoService(&quot;com.sun.star.frame.ModuleManager&quot;).getElementNames()
+
+ iWindowType = oWindow.WindowType
+ Select Case iWindowType &apos; Supported window types only
+ Case acForm
+ sSupportedModules = Array( &quot;com.sun.star.sdb.FormDesign&quot; )
+ Case acBasicIDE
+ sSupportedModules = Array( &quot;com.sun.star.script.BasicIDE&quot; )
+ Case acDatabaseWindow
+ sSupportedModules = Array( &quot;com.sun.star.sdb.OfficeDatabaseDocument&quot; )
+ Case acReport
+ sSupportedModules = Array( &quot;com.sun.star.sdb.TextReportDesign&quot; )
+ Case acDocument
+ Select Case oWindow.DocumentType
+ Case docCalc : sSupportedModules = Array( &quot;com.sun.star.sheet.SpreadsheetDocument&quot; )
+ Case docWriter : sSupportedModules = Array( &quot;com.sun.star.text.TextDocument&quot; )
+ Case docImpress : sSupportedModules = Array( &quot;com.sun.star.presentation.PresentationDocument&quot; )
+ Case docDraw : sSupportedModules = Array( &quot;com.sun.star.drawing.DrawingDocument&quot; )
+ Case docMath : sSupportedModules = Array( &quot;com.sun.star.formula.FormulaProperties&quot; )
+ Case Else : sSupportedModules = Array()
+ End Select
+ Case acTable, acQuery
+ sSupportedModules = Array( &quot;com.sun.star.sdb.DataSourceBrowser&quot; _
+ , &quot;com.sun.star.sdb.TableDataView&quot; _
+ )
+ Case acDiagram
+ sSupportedModules = Array( &quot;com.sun.star.sdb.RelationDesign&quot; )
+ Case acWelcome
+ sSupportedModules = Array( &quot;com.sun.star.frame.StartModule&quot; )
+ Case Else
+ sSupportedModules = Array()
+ End Select
+
+ &apos; Find all standard and custom toolbars stored in LibO/AOO Base
+ Set oModuleUI = CreateUnoService(&quot;com.sun.star.ui.ModuleUIConfigurationManagerSupplier&quot;)
+ For k = 0 To UBound(vModules)
+ For j = 0 To UBound(sSupportedModules)
+ iBuiltin = 1 &apos; Default = builtin
+ If vModules(k) = sSupportedModules(j) Then &apos; Supported modules only
+ Set oToolbar = oModuleUI.getUIConfigurationManager(vModules(k))
+ vUIElements() = oToolbar.getUIElementsInfo(0)
+ For i = 0 To UBound(vUIElements)
+ sToolbarFullName = _GetPropertyValue(vUIElements(i), &quot;ResourceURL&quot;)
+ sToolbarName = Split(sToolbarFullName, &quot;/&quot;)(2)
+ If _IsLeft(UCase(sToolbarName), UCase(cstCustom)) Then
+ sToolbarName = _GetPropertyValue(vUIElements(i), &quot;UIName&quot;)
+ iBuiltin = 2
+ End If
+
+ iObjectsCount = iObjectsCount + 1
+ Select Case True
+ Case IsMissing(pvIndex)
+ Case VarType(pvIndex) = vbString
+ If UCase(pvIndex) = UCase(sToolbarName) Then bFound = True
+ Case Else
+ If pvIndex &lt; 0 Then Goto Trace_IndexError
+ If pvIndex = iObjectsCount - 1 Then bFound = True
+ End Select
+
+ If bFound Then
+ Set oObject = _NewCommandBar(vModules(k), sToolbarName, sToolbarFullName, iBuiltin)
+ Set oObject._Window = oWindow.Frame
+ Set oObject._Toolbar = oToolbar
+ Goto Exit_Function
+ End If
+ Next i
+ End If
+ Next j
+ Next k
+
+ &apos; Find all (not builtin) toolbars stored in current document (typically forms)
+ iBuiltin = 3 &apos; Stored in form itself
+ Set oToolbar = oWindow.Frame.Controller.Model.getUIConfigurationManager
+ vUIElements() = oToolbar.getUIElementsInfo(0)
+ For i = 0 To UBound(vUIElements)
+ sToolbarFullName = _GetPropertyValue(vUIElements(i), &quot;ResourceURL&quot;)
+ sToolbarName = _GetPropertyValue(vUIElements(i), &quot;UIName&quot;)
+ iObjectsCount = iObjectsCount + 1
+ Select Case True
+ Case IsMissing(pvIndex)
+ Case VarType(pvIndex) = vbString
+ If UCase(pvIndex) = UCase(sToolbarName) Then bFound = True
+ Case Else
+ If pvIndex = iObjectsCount - 1 Then bFound = True
+ End Select
+ If bFound Then
+ Set oObject = _NewCommandBar(&quot;&quot;, sToolbarName, sToolbarFullName, iBuiltin)
+ Set oObject._Window = oWindow.Frame
+ Set oObject._Toolbar = oToolbar
+ Goto Exit_Function
+ End If
+ Next i
+
+ &apos; MISSING : CUSTOM POPUPS &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;
+
+ Select Case True
+ Case IsMissing(pvIndex)
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLCOMMANDBARS
+ oObject._Count = iObjectsCount
+ Case VarType(pvIndex) = vbString
+ Goto Trace_NotFound
+ Case Else &apos; pvIndex is numeric
+ Goto Trace_IndexError
+ End Select
+
+Exit_Function:
+ Set CommandBars = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;COMMANDBAR&quot;), pvIndex))
+ Goto Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Trace_WindowError:
+ TraceError(TRACEFATAL, ERRWINDOW, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; CommandBars V1,3,0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Controls(ByVal Optional pvObject As Variant, Optional ByVal pvIndex As Variant) As Variant
+&apos; Return an object of type Control indicated by either its index (integer) or its name (CASE-INSENSITIVE string)
+&apos; The 1st argument pvObject can be either
+&apos; an object of type FORM (1)
+&apos; a main form name as string
+&apos; an object of type SUBFORM (2)
+&apos; The Form property in the returned variant contains a SUBFORM type
+&apos; an object of type CONTROL and subtype GRIDCONTROL (3)
+&apos; an object of type OPTIONGROUP (4) 2nd argument, if any, must be numeric
+&apos; If no pvIndex argument, return a Collection type
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim vObject As Object
+Const cstThisSub = &quot;Controls&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ If IsMissing(pvObject) Then Call _TraceArguments()
+ If IsNull(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments()
+ Controls = EMPTY
+
+ If VarType(pvObject) = vbString Then
+ Set vObject = Forms(pvObject)
+ If IsNull(vObject) Then Goto Exit_Function
+ Else
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJFORM, OBJSUBFORM, OBJOPTIONGROUP, CTLGRIDCONTROL)) Then Goto Exit_Function
+ Set vObject = pvObject
+ End If
+
+ If IsMissing(pvIndex) Then
+ Controls = vObject.Controls()
+ Else
+ If Not Utils._CheckArgument(pvIndex, 2, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ Controls = vObject.Controls(pvIndex)
+ End If
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEERROR, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; Controls V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CurrentDb() As Object
+&apos; Returns _A2B_.CurrentDocument().Database as an object to allow access to its properties
+
+Const cstThisSub = &quot;CurrentDb&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ Set CurrentDb = Nothing
+ If IsEmpty(_A2B_) Then GoTo Exit_Function
+ Set CurrentDb = _A2B_.CurrentDb()
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; CurrentDb V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CurrentUser() As String
+
+Dim oPath As Object, sUser As String
+
+ Set oPath = CreateUnoService(&quot;com.sun.star.util.PathSubstitution&quot;)
+ sUser = oPath.getSubstituteVariableValue(&quot;$(username)&quot;) &apos; New since LibreOffice 5.2
+ CurrentUser = sUser
+
+End Function &apos; CurrentUser V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DAvg( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return average of scope
+Const cstThisSub = &quot;DAvg&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DAvg = Application._CurrentDb()._DFunction(&quot;AVG&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DAvg
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DCount( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return # of occurrences of scope
+Const cstThisSub = &quot;DCount&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DCount = Application._CurrentDb()._DFunction(&quot;COUNT&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DCount
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DLookup( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ , ByVal Optional pvOrderClause As Variant _
+ ) As Variant
+
+&apos; Return a value within a table
+ &apos;Arguments: psExpr: an SQL expression
+ &apos; psDomain: a table- or queryname
+ &apos; pvCriteria: an optional WHERE clause
+ &apos; pcOrderClause: an optional order clause incl. &quot;DESC&quot; if relevant
+ &apos;Return: Value of the psExpr if found, else Null.
+ &apos;Author: inspired from Allen Browne. http://allenbrowne.com/ser-42.html
+ &apos;Examples:
+ &apos; 1. To find the last value, include DESC in the OrderClause, e.g.:
+ &apos; DLookup(&quot;[Surname] &amp; [FirstName]&quot;, &quot;tblClient&quot;, , &quot;ClientID DESC&quot;)
+ &apos; 2. To find the lowest non-null value of a field, use the Criteria, e.g.:
+ &apos; DLookup(&quot;ClientID&quot;, &quot;tblClient&quot;, &quot;Surname Is Not Null&quot; , &quot;Surname&quot;)
+
+Const cstThisSub = &quot;DLookup&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DLookup = Application._CurrentDb()._DFunction(&quot;&quot;, psExpr, psDomain _
+ , Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria) _
+ , Iif(IsMissing(pvOrderClause), &quot;&quot;, pvOrderClause) _
+ )
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DLookup
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DMax( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return maximum of scope
+Const cstThisSub = &quot;DMax&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DMax = Application._CurrentDb()._DFunction(&quot;MAX&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DMax
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DMin( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return minimum of scope
+Const cstThisSub = &quot;DMin&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DMin = Application._CurrentDb()._DFunction(&quot;MIN&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DMin
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DStDev( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return standard deviation of scope
+Const cstThisSub = &quot;DStDev&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DStDev = Application._CurrentDb()._DFunction(&quot;STDDEV_SAMP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;) &apos; STDDEV not STDEV !
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DStDev
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DStDevP( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return standard deviation of scope
+Const cstThisSub = &quot;DStDevP&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DStDevP = Application._CurrentDb()._DFunction(&quot;STDDEV_POP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;) &apos; STDDEV not STDEV !
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DStDevP
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DSum( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return sum of scope
+Const cstThisSub = &quot;DSum&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DSum = Application._CurrentDb()._DFunction(&quot;SUM&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DSum
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DVar( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return variance of scope
+Const cstThisSub = &quot;DVar&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DVar = Application._CurrentDb()._DFunction(&quot;VAR_SAMP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DVar
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DVarP( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return variance of scope
+Const cstThisSub = &quot;DVarP&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DVarP = Application._CurrentDb()._DFunction(&quot;VAR_POP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DVarP
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Events(Optional poEvent As Variant) As Variant
+&apos; Return an event object corresponding with actual event
+
+Dim vEvent As Variant
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Events&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ Set vEvent = Nothing
+ If IsMissing(poEvent) Then Goto Exit_Function
+ If IsNull(poEvent) Then Goto Exit_Function
+
+ If Not Utils._CheckArgument(poEvent, 1, vbObject, , False) Then Goto Exit_Function &apos; No error handling in CheckArgument
+ If Not Utils._hasUNOProperty(poEvent, &quot;Source&quot;) Then Goto Trace_Error
+ Set vEvent = New Event
+ vEvent._Initialize(poEvent)
+
+Exit_Function:
+ Set Events = vEvent
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEWARNING, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_Error:
+ &apos; Errors are not displayed to avoid display infinite cycling
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, False, Array(1, Utils._CStr(poEvent)))
+ Set vEvent = Nothing
+ Goto Exit_Function
+End Function &apos; Events V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Forms(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return an object of type Form indicated by either its index (integer) or its name (NOT CASE-SENSITIVE string)
+&apos; The concerned form must be loaded.
+&apos; If no argument, return a Collection type
+
+Const cstThisSub = &quot;Forms&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Dim ofForm As Object, oCounter As Variant, vForms As Variant, oIndex As Object
+ Set vForms = Nothing
+
+Dim iCount As Integer
+ If IsMissing(pvIndex) Then
+ iCount = Application._CountOpenForms()
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLFORMS
+ oCounter._Count = iCount
+ Forms = oCounter
+ Exit Function
+ Else
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+ Select Case VarType(pvIndex)
+ Case vbString
+ Set ofForm = Application.AllForms(Utils._Trim(pvIndex))
+ Case Else
+ iCount = Application._CountOpenForms()
+ If iCount &lt;= pvIndex Then Goto Trace_Error_Index
+ Set ofForm = Application._CountOpenForms(pvIndex)
+ End Select
+
+ If IsNull(ofForm) Then Goto Trace_Error
+ If ofForm.IsLoaded Then
+ Set vForms = ofForm
+ Else
+ Set vForms = Nothing
+ TraceError(TRACEFATAL, ERRFORMNOTOPEN, Utils._CalledSub(), 0, , ofForm._Name)
+ Goto Exit_Function
+ End If
+
+Exit_Function:
+ Set Forms = vForms
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(1, pvIndex))
+ Set vForms = Nothing
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set vForms = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; Forms V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getObject(Optional pvShortcut As Variant) As Variant
+&apos; Return the object described by pvShortcut ignoring its final property
+&apos; Example: &quot;Forms!myForm!myControl.myProperty&quot; =&gt; Controls(Forms(&quot;myForm&quot;), &quot;myControl&quot;))
+
+Const cstEXCLAMATION = &quot;!&quot;
+Const cstDOT = &quot;.&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;getObject&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvShortcut) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvShortcut, 1, vbString) Then Goto Exit_Function
+
+Dim iCurrentIndex As Integer, vCurrentObject As Variant, sCurrentProperty As String
+Dim sComponents() As String, sSubComponents() As String, sDialog As String
+Dim oDoc As Object
+ Set vCurrentObject = Nothing
+ sComponents = Split(Trim(pvShortcut), cstEXCLAMATION)
+ If UBound(sComponents) = 0 Then Goto Trace_Error
+ If Not Utils._InList(UCase(sComponents(0)), Array(&quot;FORMS&quot;, &quot;DIALOGS&quot;, &quot;TEMPVARS&quot;)) Then Goto Trace_Error
+ If sComponents(1) = &quot;0&quot; Or Left(sComponents(1), 2) = &quot;0.&quot; Then
+ Set oDoc = _A2B_.CurrentDocument()
+ If oDoc.DbConnect = DBCONNECTFORM Then sComponents(1) = oDoc.DbContainers(0).FormName Else Goto Trace_Error
+ End If
+
+ sSubComponents = Split(sComponents(UBound(sComponents)), cstDOT)
+ sComponents(UBound(sComponents)) = sSubComponents(0) &apos; Ignore final property, if any
+
+ Set vCurrentObject = New Collect
+ Set vCurrentObject._This = vCurrentObject
+ Select Case UCase(sComponents(0))
+ Case &quot;FORMS&quot; : vCurrentObject._CollType = COLLFORMS
+ Case &quot;DIALOGS&quot; : vCurrentObject._CollType = COLLALLDIALOGS
+ Case &quot;TEMPVARS&quot; : vCurrentObject._CollType = COLLTEMPVARS
+ End Select
+ For iCurrentIndex = 1 To UBound(sComponents) &apos; Start parsing ...
+ sSubComponents = Split(sComponents(iCurrentIndex), cstDOT)
+ sComponents(iCurrentIndex) = Utils._Trim(sSubComponents(0))
+ Select Case UBound(sSubComponents)
+ Case 0
+ sCurrentProperty = &quot;&quot;
+ Case 1
+ sCurrentProperty = sSubComponents(1)
+ Case Else
+ Goto Trace_Error
+ End Select
+ Select Case vCurrentObject._Type
+ Case OBJCOLLECTION
+ Select Case vCurrentObject._CollType
+ Case COLLFORMS
+ vCurrentObject = Application.AllForms(sComponents(iCurrentIndex))
+ Case COLLALLDIALOGS
+ sDialog = UCase(sComponents(iCurrentIndex))
+ vCurrentObject = Application.AllDialogs(sDialog)
+ If Not vCurrentObject.IsLoaded Then Goto Trace_Error
+ Set vCurrentObject.UnoDialog = _A2B_.Dialogs.Item(sDialog)
+ Case COLLTEMPVARS
+ If UBound(sComponents) &gt; 1 Then Goto Trace_Error
+ vCurrentObject = Application.TempVars(sComponents(1))
+ &apos;Case Else
+ End Select
+ Case OBJFORM, OBJSUBFORM, OBJCONTROL, OBJDIALOG
+ vCurrentObject = vCurrentObject.Controls(sComponents(iCurrentIndex))
+ End Select
+ If sCurrentProperty &lt;&gt; &quot;&quot; Then vCurrentObject = vCurrentObject.getProperty(sCurrentProperty)
+ Next iCurrentIndex
+
+ Set getObject = vCurrentObject
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(1, pvShortcut))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; getObject V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getValue(Optional pvObject As Variant) As Variant
+&apos; getValue also interprets shortcut strings !!
+Dim vItem As Variant, sProperty As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getValue&quot;)
+ If VarType(pvObject) = vbString Then
+ Utils._SetCalledSub(&quot;getValue&quot;)
+ Set vItem = getObject(pvObject)
+ sProperty = Utils._FinalProperty(pvObject)
+ If sProperty = &quot;&quot; Then sProperty = &quot;Value&quot; &apos; Default value if final property in shortcut is absent
+ getValue = vItem.getProperty(sproperty)
+ Utils._ResetCalledSub(&quot;getValue&quot;)
+ Else
+ Set vItem = pvObject
+ getValue = vItem.getProperty(&quot;Value&quot;)
+ End If
+End Function &apos; getValue
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Function HtmlEncode(ByVal pvString As Variant, ByVal Optional pvLength As Variant) As String
+&apos; Converts a string to an HTML-encoded string.
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;HtmlEncode&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ HtmlEncode = &quot;&quot;
+
+Dim sOutput As String, l As Long, lLength As Long
+ If IsMissing(pvLength) Then pvLength = 0
+ If Not Utils._CheckArgument(pvString, 1, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvLength, 1, _AddNumeric()) Then Goto Exit_Function
+
+ sOutput = &quot;&quot;
+ lLength = CLng(pvLength)
+ If Len(pvString) &gt; 0 Then
+ For l = 1 To Len(pvString)
+ If lLength &gt; 0 And Len(sOutput) &gt; lLength Then Exit For
+ sOutput = sOutput &amp; Utils._UTF8Encode(Mid(pvString, l, 1))
+ Next l
+ End If
+
+ HtmlEncode = sOutput
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; HtmlEncode V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenConnection ( _
+ Optional pvComponent As Variant _
+ , ByVal Optional pvUser As Variant _
+ , ByVal Optional pvPassword As Variant _
+ ) As Object
+
+&apos; Establish connection with the database designated in the currently open front-end (.odb) document
+&apos; Call template:
+&apos; Call OpenConnection(ThisDatabaseDocument[, &quot;&quot;, &quot;&quot;])
+&apos; Call stored in the OpenDocument event of the front-end database document
+&apos;OR
+&apos; Initiates processing of a (standalone ?) Writer, Calc, ... document with 1 or more data-aware forms
+&apos; Call template:
+&apos; Call OpenConnection(ThisComponent[, &quot;&quot;, &quot;&quot;])
+&apos; Call stored in the OpenDocument event of the document
+&apos;
+&apos; User and Password arguments are obsolete (still tolerated)
+&apos; - because no mean has been found to connect protected db from .odb via API
+&apos; - because having multiple forms with multiple db&apos;s and multiple passwords is meaningless
+
+Dim oComponent As Object, oForms As Object, iCurrent As Integer
+Dim i As Integer, bFound As Boolean
+Dim vCurrentDoc() As Variant
+Dim oBaseContext As Object, sDbNames() As String, oBaseSource As Object
+Dim sDatabaseURL As String, oHandler As Object
+Dim vDbContainer As Variant, vDbContainers() As Variant, vDocContainer As Variant
+Dim sFormName As String
+
+ If IsEmpty(_A2B_) Then Call Application._RootInit() &apos; First use of Access2Base in current AOO/LibO session
+ Set OpenConnection = Nothing
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;OpenConnection&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvComponent) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvComponent, 1, vbObject) Then Goto Exit_Function
+ Set oComponent = pvComponent
+ If Not Utils._hasUNOProperty(oComponent, &quot;ImplementationName&quot;) Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(1, oComponent))
+ Exit Function
+ End If
+ If IsMissing(pvUser) Then pvUser = &quot;&quot;
+ If IsMissing(pvPassword) Then pvPassword = &quot;&quot;
+ If Not Utils._CheckArgument(pvUser, 2, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvPassword, 3, vbString) Then Goto Exit_Function
+
+ If Not IsArray(_A2B_.CurrentDoc) Then
+ vCurrentDoc() = Array()
+ Redim vCurrentDoc(0 To 0) &apos; Create at least one entry for database document
+ Else
+ vCurrentDoc() = _A2B_.CurrentDoc()
+ End If
+
+ &apos; Find index of entry to use for new connection
+ With oComponent
+ Select Case .ImplementationName
+ Case &quot;com.sun.star.comp.dba.ODatabaseDocument&quot;
+ iCurrent = 0
+ Case Else &apos; &quot;SwXTextDocument&quot;, &quot;ScModelObj&quot;
+ If UBound(vCurrentDoc) &lt;= 0 Then &apos; First Calc or Writer during current session
+ iCurrent = 1
+ Else &apos; Search entry already used earlier by same component
+ bFound = False
+ For i = 1 To UBound(vCurrentDoc)
+ If Not IsEmpty(vCurrentDoc(i)) Then
+ If vCurrentDoc(i).Active And vCurrentDoc(i).URL = .URL Then
+ iCurrent = i
+ bFound = True
+ Exit For
+ End If
+ End If
+ Next i
+ End If
+ If Not bFound Then
+ iCurrent = UBound(vCurrentDoc) + 1 &apos; No entry found, increment array
+ ReDim Preserve vCurrentDoc(0 To iCurrent)
+ End If
+ End Select
+ End With
+
+ &apos; Initialize future entry
+ Set vDocContainer = New DocContainer
+ Set vDocContainer.Document = oComponent
+ vDocContainer.Active = True
+ vDocContainer.URL = oComponent.URL
+ &apos; Initialize each DbContainer entry
+ vDbContainers() = Array()
+ TraceLog(TRACEANY, Utils._GetProductName() &amp; &quot; - &quot; &amp; Application.ProductCode(), False)
+ Select Case oComponent.ImplementationName
+ Case &quot;com.sun.star.comp.dba.ODatabaseDocument&quot; &apos; Ignore pvUser and pvPassword arguments
+ vDbContainer = New DbContainer
+ vDbContainer.FormName = &quot;&quot;
+ Set vDbContainer.Database = New Database
+ Set vDbContainer.Database._This = vDbContainer.Database
+ With vDbContainer.Database
+ If Not oComponent.CurrentController.IsConnected Then
+ Set oHandler = createUnoService(&quot;com.sun.star.sdb.InteractionHandler&quot;)
+ Set .Connection = oComponent.DataSource.connectWithCompletion(oHandler)
+ oComponent.CurrentController.connect()
+ Else
+ Set .Connection = oComponent.CurrentController.ActiveConnection
+ End If
+ vDocContainer.DbConnect = DBCONNECTBASE
+ ._DbConnect = DBCONNECTBASE
+ Set .MetaData = .Connection.MetaData
+ ._LoadMetadata()
+ If .MetaData.DatabaseProductName = &quot;MySQL&quot; Then
+ ._ReadOnly = .MetaData.isReadOnly()
+ Else
+ ._ReadOnly = .Connection.isReadOnly() &apos; Always True in Mysql ??
+ End If
+ Set .Document = oComponent
+ .Title = oComponent.Title
+ .URL = vDocContainer.URL
+ .Location = oComponent.Location
+ ReDim vDbContainers(0 To 0)
+ Set vDbContainers(0) = vDbContainer
+ TraceLog(TRACEANY, .Version, False)
+ TraceLog(TRACEANY, UCase(cstThisSub) &amp; &quot; &quot; &amp; .URL, False)
+ End With
+ Case Else
+ Set oForms = oComponent.CurrentController.Model.DrawPage.Forms
+ If oForms.Count &lt; 1 Then Goto Error_MainForm
+ ReDim vDbContainers(0 To oForms.Count - 1)
+ For i = 0 To oForms.Count - 1
+ vDbContainer = New DbContainer &apos; To make distinct entries !!
+ sFormName = oForms.ElementNames(i)
+ Set vDbContainer.Database = New Database
+ Set vDbContainer.Database._This = vDbContainer.Database
+ With vDbContainer.Database
+ .FormName = sFormName
+ vDbContainer.FormName = sFormName
+ Set .Form = oForms.getByName(sFormName)
+ Set .Connection = .Form.ActiveConnection &apos; Might be Nothing in Windows at AOO/LO startup (not met in Linux)
+ If Not IsNull(.Connection) Then
+ Set .MetaData = .Connection.MetaData
+ ._LoadMetadata()
+ ._ReadOnly = .Connection.isReadOnly()
+ TraceLog(TRACEANY, .MetaData.getDatabaseProductName() &amp; &quot; &quot; &amp; .MetaData.getDatabaseProductVersion, False)
+ End If
+ Set .Document = oComponent
+ .Title = oComponent.Title
+ .URL = .Form.DataSourceName
+ ._DbConnect = DBCONNECTFORM
+ Set vDbContainers(i) = vDbContainer
+ vDbContainers(i).FormName = sFormName
+ TraceLog(TRACEANY, UCase(cstThisSub) &amp; &quot; &quot; &amp; .URL &amp; &quot; Form=&quot; &amp; vDbContainer.FormName, False)
+ End With
+ Next i
+ vDocContainer.DbConnect = DBCONNECTFORM
+ End Select
+
+ vDocContainer.DbContainers() = vDbContainers()
+ Set vCurrentDoc(iCurrent) = vDocContainer
+
+ _A2B_.CurrentDoc = vCurrentDoc
+ Set OpenConnection = vDbContainers(0).Database
+
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Set _A2B_.CurrentDoc = Array()
+ GoTo Exit_Function
+Error_MainForm:
+ TraceError(TRACEFATAL, ERRMAINFORM, Utils._CalledSub(), False, ,oComponent.Title)
+ Set _A2B_.CurrentDoc = Array()
+ GoTo Exit_Function
+Trace_Error:
+ TraceError(TRACEABORT, ERRDBNOTCONNECTED, Utils._CalledSub(), 0,1)
+ Goto Exit_Function
+End Function &apos; OpenConnection V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenDatabase ( _
+ ByVal Optional pvDatabaseURL As Variant _
+ , ByVal Optional pvUser As Variant _
+ , ByVal Optional pvPassword As Variant _
+ , ByVal Optional pvReadOnly As Variant _
+ ) As Variant
+
+&apos; Return a database object based on input arguments:
+&apos; Call template:
+&apos; Call OpenDatabase(&quot;... databaseURL ...&quot;[, &quot;&quot;, &quot;&quot;, True/False])
+&apos; pvDatabaseURL may be the name of a registered database or the URL of the targeted .odb file
+&apos; Might be called from any AOO/LibO application, independently from OpenConnection
+
+Dim odbDatabase As Variant, oBaseContext As Object, sDbNames() As String, oBaseSource As Object
+Dim i As Integer, bFound As Boolean
+Dim sDatabaseURL As String
+
+ If IsEmpty(_A2B_) Then &apos; First use of Access2Base in current AOO/LibO session
+ Call Application._RootInit()
+ TraceLog(TRACEANY, Utils._GetProductName() &amp; &quot; - &quot; &amp; Application.ProductCode(), False)
+ End If
+ Set OpenDatabase = Nothing
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;OpenDatabase&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If Not Utils._CheckArgument(pvDatabaseURL, 1, vbString) Then Goto Exit_Function
+ If pvDatabaseURL = &quot;&quot; Then Call _TraceArguments()
+ If IsMissing(pvUser) Then pvUser = &quot;&quot;
+ If IsMissing(pvPassword) Then pvPassword = &quot;&quot;
+ If Not Utils._CheckArgument(pvUser, 2, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvPassword, 3, vbString) Then Goto Exit_Function
+ If IsMissing(pvReadOnly) Then pvReadOnly = False
+ If Not Utils._CheckArgument(pvReadOnly, 3, vbBoolean) Then Goto Exit_Function
+
+ Set odbDatabase = New Database
+ Set odbDatabase._This = odbDatabase
+ odbDatabase._DbConnect = DBCONNECTANY
+
+ Set oBaseContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+ sDbNames() = oBaseContext.getElementNames()
+ bFound = False
+ For i = 0 To UBound(sDbNames()) &apos; Enumerate registered databases and check non case-sensitive equality
+ If UCase(sDbNames(i)) = UCase(pvDatabaseURL) Then
+ sDatabaseURL = sDbNames(i)
+ Set oBaseSource = oBaseContext.getByName(sDatabaseURL)
+ odbDatabase.Location = oBaseContext.getDatabaseLocation(sDbNames(i))
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then
+ sDatabaseURL = ConvertToURL(pvDatabaseURL)
+ If UCase(Right(sDatabaseURL, 4)) &lt;&gt; &quot;.ODB&quot; Then Goto Trace_Error
+ If Not FileExists(sDatabaseURL) Then Goto Trace_Error
+ Set oBaseSource = oBaseContext.getByName(sDatabaseURL)
+ odbDatabase.Location = sDatabaseURL
+ End If
+
+ Set odbDatabase.Connection = oBaseSource.getConnection(pvUser, pvPassword)
+ If Not IsNull(odbDatabase.Connection) Then &apos; Null when standalone and target db does not exist
+ Set odbDatabase.MetaData = odbDatabase.Connection.MetaData
+ odbDatabase._LoadMetadata()
+ Else
+ Goto Trace_Error
+ End If
+
+ odbDatabase.URL = sDatabaseURL
+
+ If pvReadOnly Then
+ odbDatabase.Connection.isReadOnly = True
+ odbDatabase._ReadOnly = True
+ End If
+
+ Set OpenDatabase = odbDatabase
+
+ TraceLog(TRACEANY, odbDatabase.MetaData.getDatabaseProductName() &amp; &quot; &quot; &amp; odbDatabase.MetaData.getDatabaseProductVersion, False)
+ TraceLog(TRACEANY, UCase(cstThisSub) &amp; &quot; &quot; &amp; odbDatabase.URL, False)
+
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_Error:
+ TraceError(TRACEABORT, ERRDBNOTCONNECTED, Utils._CalledSub(), 0,1)
+ Goto Exit_Function
+End Function &apos; OpenDatabase V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ProductCode()
+ If IsEmpty(_A2B_) Then Call Application._RootInit() &apos; First use of Access2Base in current AOO/LibO session
+ ProductCode = &quot;Access2Base &quot; &amp; _A2B_.VersionNumber
+End Function &apos; ProductCode V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setValue(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; setValue also interprets shortcut strings !!
+Dim vItem As Variant, sProperty As String
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setValue&quot;)
+ If VarType(pvObject) = vbString Then
+ Utils._SetCalledSub(&quot;setValue&quot;)
+ Set vItem = getObject(pvObject)
+ sProperty = Utils._FinalProperty(pvObject)
+ If sProperty = &quot;&quot; Then sProperty = &quot;Value&quot;
+ setValue = vItem.setProperty(sProperty, pvValue)
+ Utils._ResetCalledSub(&quot;setValue&quot;)
+ Else
+ Set vItem = pvObject
+ setValue = vItem.setProperty(&quot;Value&quot;, pvValue)
+ End If
+End Function &apos; setValue
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SysCmd(Optional pvAction As Variant _
+ , Optional pvText As Variant _
+ , Optional pvValue As Variant _
+ ) As Variant
+&apos; Manage progress meter in the status bar
+&apos; Other values supported by MSAccess are ignored
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;SysCmd&quot;
+ Utils._SetCalledSub(cstThisSub)
+ SysCmd = False
+
+Const cstMissing = -1
+Const cstBarLength = 350
+ If IsMissing(pvAction) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvAction, 1, Utils._AddNumeric(), Array( _
+ acSysCmdAccessDir _
+ , acSysCmdAccessVer _
+ , acSysCmdClearHelpTopic _
+ , acSysCmdClearStatus _
+ , acSysCmdGetObjectState _
+ , acSysCmdGetWorkgroupFile _
+ , acSysCmdIniFile _
+ , acSysCmdInitMeter _
+ , acSysCmdProfile _
+ , acSysCmdRemoveMeter _
+ , acSysCmdRuntime _
+ , acSysCmdSetStatus _
+ , acSysCmdUpdateMeter _
+ )) Then Goto Exit_Function
+ If IsMissing(pvValue) Then pvValue = cstMissing
+ If Not Utils._CheckArgument(pvAction, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ Select Case pvAction
+ Case acSysCmdInitMeter, acSysCmdUpdateMeter, acSysCmdSetStatus
+ If IsMissing(pvText) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvText, 2, vbString) Then Goto Exit_Function
+ Case Else
+ End Select
+ If Not Utils._CheckArgument(pvValue, 3, Utils._AddNumeric()) Then Goto Exit_Function
+
+Dim vBar As Variant, iLen As Integer
+ Set vBar = _A2B_.StatusBar
+ Select Case pvAction
+ Case acSysCmdAccessVer
+ SysCmd = Application.Version()
+ Goto Exit_Function
+ Case acSysCmdSetStatus
+ If pvValue &lt;&gt; cstMissing Then Goto Error_Arg
+ iLen = Len(pvText)
+ vBar = _NewBar()
+ If Not IsNull(vBar) Then vBar.start(Iif(iLen &gt;= cstBarLength, pvText, pvText &amp; Space(cstBarLength - iLen)), 0)
+ Case acSysCmdClearStatus
+ If pvValue &lt;&gt; cstMissing Then Goto Error_Arg
+ If Not IsNull(vBar) Then
+ vBar.end()
+ Set _A2B_.StatusBar = Nothing
+ End If
+ Case acSysCmdInitMeter
+ If pvValue = cstMissing Then Call _TraceArguments()
+ vBar = _NewBar()
+ If Not IsNull(vBar) Then vBar.start(pvText, pvValue)
+ Case acSysCmdUpdateMeter
+ If pvValue = cstMissing Then Call _TraceArguments()
+ If Not IsNull(vBar) Then &apos; Otherwise ignore !
+ vBar.setValue(pvValue)
+ If Len(pvText) &gt; 0 Then vBar.setText(pvText)
+ End If
+ Case acSysCmdRemoveMeter
+ If Not IsNull(vBar) Then
+ vBar.end()
+ Set _A2B_.StatusBar = Nothing
+ End If
+ Case acSysCmdRuntime
+ SysCmd = False
+ Goto Exit_Function
+ Case Else
+ End Select
+
+ SysCmd = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_Arg:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(3, pvValue))
+ Goto Exit_Function
+End Function &apos; SysCmd V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function TempVars(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return either a Collection or a TempVar object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;TempVars&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iMode As Integer, vTempVars As Variant, bFound As Boolean
+Const cstCount = 0
+Const cstByIndex = 1
+Const cstByName = 2
+
+ If IsMissing(pvIndex) Then
+ iMode = cstCount
+ Else
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ If VarType(pvIndex) = vbString Then iMode = cstByName Else iMode = cstByIndex
+ End If
+
+ Set vTempVars = Nothing
+ Select Case iMode
+ Case cstCount &apos; Build Collection object
+ Set vTempVars = New Collect
+ With vTempVars
+ ._This = vTempVars
+ ._CollType = COLLTEMPVARS
+ ._Count = _A2B_.TempVars.Count
+ End With
+ Case cstByIndex &apos; Build TempVar object
+ If pvIndex &lt; 0 Or pvIndex &gt;= _A2B_.TempVars.Count Then Goto Trace_Error_Index
+ Set vTempVars = _A2B_.TempVars.Item(pvIndex + 1) &apos; Builtin collections start at 1
+ Case cstByName
+ bFound = _A2B_.hasItem(COLLTEMPVARS, pvIndex)
+ If Not bFound Then Goto Trace_NotFound
+ vTempVars = _A2B_.TempVars.Item(UCase(pvIndex))
+ End Select
+
+ Set TempVars = vTempVars
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set vTempVars = Nothing
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;TEMPVAR&quot;), pvIndex))
+ Goto Exit_Function
+End Function &apos; TempVars V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Version() As String
+ Version = Utils._GetProductName()
+End Function &apos; Version V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _CollectNames(ByRef poCollection As Object, ByVal psPrefix As String) As Variant
+&apos; Return a &quot;\;&quot; separated list of hierarchical (prefixed with Prefix) and persistent names contained in Collection
+&apos; If one of those names refers to a folder, function is called recursively
+&apos; Result = 2 items array: (0) list of hierarchical names
+&apos; (1) list of persistent names
+&apos;
+Dim oObject As Object, vNamesList() As Variant, vPersistentList As Variant, i As Integer, sCollect(0 To 1) As String
+Dim sName As String, sType As String, sPrefix As String
+Const cstFormType = &quot;application/vnd.oasis.opendocument.text&quot;
+Const cstSeparator = &quot;\;&quot;
+
+ _CollectNames = sCollect()
+ vPersistentList = Array()
+
+ With poCollection
+ If .getCount = 0 Then Exit Function
+ vNamesList = .getElementNames()
+ ReDim vPersistentList(0 To UBound(vNamesList))
+
+ For i = 0 To UBound(vNamesList)
+ sName = vNamesList(i)
+ Set oObject = .getByName(sName)
+ sType = oObject.getContentType()
+ Select Case sType
+ Case cstFormType
+ vNamesList(i) = psPrefix &amp; vNamesList(i)
+ vPersistentList(i) = oObject.PersistentName
+ Case &quot;&quot; &apos; Folder
+ sCollect = _CollectNames(oObject, psPrefix &amp; sName &amp; &quot;/&quot;)
+ vNamesList(i) = sCollect(0)
+ vPersistentList(i) = sCollect(1)
+ Case Else
+ End Select
+ Next i
+
+ End With
+
+ Set oObject = Nothing
+ sCollect(0) = Join(vNamesList, cstSeparator)
+ sCollect(1) = Join(vPersistentList, cstSeparator)
+ _CollectNames = sCollect()
+
+End Function &apos; _CollectNames V6.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CountOpenForms(ByVal Optional piCountMax As Integer) As Variant
+&apos; Return # of active forms if no argument
+&apos; Return name of piCountMax-th open form if argument present
+
+Dim i As Integer, iCount As Integer, iAllCount As Integer, ofForm As Variant
+ iAllCount = AllForms._Count
+ iCount = 0
+ If iAllCount &gt; 0 Then
+ For i = 0 To iAllCount - 1
+ Set ofForm = Application.AllForms(i)
+ If ofForm._IsLoaded Then iCount = iCount + 1
+ If Not IsMissing(piCountMax) Then
+ If iCount = piCountMax + 1 Then
+ _CountOpenForms = ofForm &apos; OO3.2 aborts when Set verb present ?!?
+ Exit For
+ End If
+ End If
+ Next i
+ End If
+
+ If IsMissing(piCountMax) Then _CountOpenForms = iCount
+
+End Function &apos; CountOpenForms V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CurrentDb(ByVal Optional piDocEntry As Integer, ByVal Optional piDbEntry As Integer) As Variant
+REM Without arguments same as CurrentDb() except that it generates an error if database not connected (internal use)
+REM With 2 arguments return the corresponding entry in Root
+
+Dim oCurrentDb As Object
+ If IsEmpty(_A2B_) Then GoTo Trace_Error
+ If IsMissing(piDocEntry) Then Set oCurrentDb = Application.CurrentDb() _
+ Else Set oCurrentDb = _A2B_._CurrentDb(piDocEntry, piDbEntry)
+ If IsNull(oCurrentDb) Then Goto Trace_Error Else Set _CurrentDb = oCurrentDb
+
+Exit_Function:
+ Exit Function
+Trace_Error:
+ TraceError(TRACEABORT, ERRDBNOTCONNECTED, Utils._CalledSub(), 0, 1)
+ Goto Exit_Function
+End Function &apos; _CurrentDb V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetAllHierarchicalNames() As Variant
+&apos; Return the full hierarchical names list of a database document
+&apos; Get it from the vFormNamesList buffer if the latter is not empty
+
+Dim vNamesList As Variant, iCurrentDoc As Integer, vCurrentDoc As Variant
+Dim oForms As Object
+Const cstSeparator = &quot;\;&quot;
+
+ _GetAllHierarchicalNames = Array()
+
+&apos; Load complete list of names when Base document
+ iCurrentDoc = _A2B_.CurrentDocIndex()
+ If iCurrentDoc &gt;= 0 Then vCurrentDoc = _A2B_.CurrentDocument(iCurrentDoc) Else Exit Function
+ If vCurrentDoc.DbConnect = DBCONNECTBASE Then
+ If IsEmpty(vFormNamesList) Then
+ Set oForms = vCurrentDoc.Document.getFormDocuments()
+ vFormNamesList = _CollectNames(oForms, &quot;&quot;)
+ End If
+ vNamesList = Split(vFormNamesList(0), cstSeparator)
+ Else
+ Exit Function
+ End If
+
+ _GetAllHierarchicalNames = vNamesList
+ Set oForms = Nothing
+
+End Function &apos; _GetAllHierarchicalNames V 6.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetHierarchicalName(ByVal psPersistent As String) As String
+&apos; Return the full hierarchical name from the persistent name of a form/report
+
+Dim vPersistentList As Variant, vNamesList As Variant, i As Integer
+Const cstSeparator = &quot;\;&quot;
+
+ _GetHierarchicalName = &quot;&quot;
+
+&apos; Load complete list of names when Base document
+ vNamesList = _GetAllHierarchicalNames()
+ If UBound(vNamesList) &lt; 0 Then Exit Function
+ vPersistentList = Split(vFormNamesList(1), cstSeparator)
+
+&apos; Search in list
+ For i = 0 To UBound(vPersistentList)
+ If vPersistentList(i) = psPersistent Then
+ _GetHierarchicalName = vNamesList(i)
+ Exit For
+ End If
+ Next i
+
+End Function &apos; _GetHierarchicalName V 6.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _NewBar() As Object
+&apos; Close current status bar, if any, and initialize new one
+
+Dim vBar As Variant, vWindow As Variant, vController As Object
+ On Local Error Resume Next
+ Set _NewBar = Nothing
+
+ Set vBar = _A2B_.StatusBar
+ If Not IsNull(vBar) Then
+ If Utils._hasUNOMethod(vBar, &quot;end&quot;) Then vBar.end()
+ Set _A2B_.StatusBar = Nothing
+ End If
+
+ Set vBar = Nothing
+ Set vWindow = _SelectWindow()
+ If IsNull(vWindow.Frame) Then Exit Function
+ Select Case vWindow.WindowType
+ Case acForm, acReport, acBasicIDE, acDocument &apos; Not found how to make it work for acDatabaseWindow
+ Case Else
+ Exit Function
+ End Select
+ If Utils._hasUNOMethod(vWindow.Frame, &quot;getCurrentController&quot;) Then
+ Set vController = vWindow.Frame.getCurrentController()
+ ElseIf Utils._hasUNOMethod(vWindow.Frame, &quot;getController&quot;) Then
+ Set vController = vWindow.Frame.getController()
+ End If
+
+ If Utils._hasUNOMethod(vController, &quot;getStatusIndicator&quot;) Then vBar = vController.getStatusIndicator()
+ Set _A2B_.StatusBar = vBar
+ Set _NewBar = vBar
+ Exit Function
+
+End Function &apos; _NewBar V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _NewCommandBar(psModule As String _
+ , psToolbarName As String _
+ , psToolbarFullName As String _
+ , piBuiltin As Integer _
+ ) As Object
+
+Dim oObject As Object
+ Set oObject = New CommandBar
+ With oObject
+ ._This = oObject
+ ._Type = OBJCOMMANDBAR
+ ._Name = psToolbarName
+ ._ResourceURL = psToolbarFullName
+ ._Module = psModule
+ ._BarBuiltin = piBuiltin
+ Select Case UCase(Split(psToolbarFullName, &quot;/&quot;)(1))
+ Case &quot;MENUBAR&quot; : ._BarType = msoBarTypeMenuBar
+ Case &quot;STATUSBAR&quot; : ._BarType = msoBarTypeStatusBar
+ Case &quot;TOOLBAR&quot; : ._BarType = msoBarTypeNormal
+ Case &quot;POPUP&quot; : ._BarType = msoBarTypePopup
+ Case &quot;FLOATER&quot; : ._BarType = msoBarTypeFloater
+ Case Else : ._BarType = -1
+ End Select
+ End With
+ Set _NewCommandBar = oObject
+ Exit Function
+
+End Function &apos; NewCommandBar V1.3.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _RootInit(Optional ByVal pbForce As Boolean)
+&apos; Initialize _A2B_ global variable. Reinit forced if pbForce = True
+
+ If IsMissing(pbForce) Then pbForce = False
+ If IsEmpty(_A2B_) Or pbForce Then _A2B_ = New Root_
+
+End Sub &apos; _RootInit V1.1.0
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Collect.xba b/wizards/source/access2base/Collect.xba
new file mode 100644
index 000000000..df964b058
--- /dev/null
+++ b/wizards/source/access2base/Collect.xba
@@ -0,0 +1,399 @@
+<?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="Collect" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM MODULE NAME &lt;&gt; COLLECTION (is a reserved name for ... collections)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be COLLECTION
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _CollType As String
+Private _Parent As Object
+Private _Count As Long
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJCOLLECTION
+ Set _This = Nothing
+ _CollType = &quot;&quot;
+ Set _Parent = Nothing
+ _Count = 0
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get Count() As Long
+ Count = _PropertyGet(&quot;Count&quot;)
+End Property &apos; Count (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Function Item(ByVal Optional pvItem As Variant) As Variant
+&apos;Return property value.
+&apos;pvItem either numeric index or property name
+
+Const cstThisSub = &quot;Collection.getItem&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvItem) Then Goto Exit_Function &apos; To allow object watching in Basic IDE, do not generate error
+ Select Case _CollType
+ Case COLLCOMMANDBARCONTROLS &apos; Have no name
+ If Not Utils._CheckArgument(pvItem, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ Case Else
+ If Not Utils._CheckArgument(pvItem, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End Select
+
+Dim vNames() As Variant, oProperty As Object
+
+ Set Item = Nothing
+ Select Case _CollType
+ Case COLLALLDIALOGS
+ Set Item = Application.AllDialogs(pvItem)
+ Case COLLALLFORMS
+ Set Item = Application.AllForms(pvItem)
+ Case COLLALLMODULES
+ Set Item = Application.AllModules(pvItem)
+ Case COLLCOMMANDBARS
+ Set Item = Application.CommandBars(pvItem)
+ Case COLLCOMMANDBARCONTROLS
+ If IsNull(_Parent) Then GoTo Error_Parent
+ Set Item = _Parent.CommandBarControls(pvItem)
+ Case COLLCONTROLS
+ If IsNull(_Parent) Then GoTo Error_Parent
+ Set Item = _Parent.Controls(pvItem)
+ Case COLLFORMS
+ Set Item = Application.Forms(pvItem)
+ Case COLLFIELDS
+ If IsNull(_Parent) Then GoTo Error_Parent
+ Set Item = _Parent.Fields(pvItem)
+ Case COLLPROPERTIES
+ If IsNull(_Parent) Then GoTo Error_Parent
+ Select Case _Parent._Type
+ Case OBJCONTROL, OBJSUBFORM, OBJDATABASE, OBJDIALOG, OBJFIELD _
+ , OBJFORM, OBJQUERYDEF, OBJRECORDSET, OBJTABLEDEF
+ Set Item = _Parent.Properties(pvItem)
+ Case OBJCOLLECTION, OBJEVENT, OBJOPTIONGROUP, OBJPROPERTY
+ &apos; NOT SUPPORTED
+ End Select
+ Case COLLQUERYDEFS
+ Set Item = _Parent.QueryDefs(pvItem)
+ Case COLLRECORDSETS
+ Set Item = _Parent.Recordsets(pvItem)
+ Case COLLTABLEDEFS
+ Set Item = _Parent.TableDefs(pvItem)
+ Case COLLTEMPVARS
+ Set Item = Application.TempVars(pvItem)
+ Case Else
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ Set Item = Nothing
+ GoTo Exit_Function
+Error_Parent:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, True, Array(_GetLabel(&quot;OBJECT&quot;), _GetLabel(&quot;PARENT&quot;)))
+ Set Item = Nothing
+ GoTo Exit_Function
+End Function &apos; Item V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function Add(Optional pvNew As Variant, Optional pvValue As Variant) As Boolean
+&apos; Append a new TableDef or TempVar object to the TableDefs/TempVars collections
+
+Const cstThisSub = &quot;Collection.Add&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Dim odbDatabase As Object, oConnection As Object, oTables As Object, oTable As Object
+Dim vObject As Variant, oTempVar As Object
+ Add = False
+ If IsMissing(pvNew) Then Call _TraceArguments()
+
+ Select Case _CollType
+ Case COLLTABLEDEFS
+ If Not Utils._CheckArgument(pvNew, 1, vbObject) Then Goto Exit_Function
+ Set vObject = pvNew
+ With vObject
+ Set odbDatabase = ._ParentDatabase
+ If odbDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ Set oConnection = odbDatabase.Connection
+ If IsNull(.TableDescriptor) Or .TableFieldsCount = 0 Then Goto Error_Sequence
+ Set oTables = oConnection.getTables()
+ oTables.appendByDescriptor(.TableDescriptor)
+ Set .Table = oTables.getByName(._Name)
+ .CatalogName = .Table.CatalogName
+ .SchemaName = .Table.SchemaName
+ .TableName = .Table.Name
+ .TableDescriptor.dispose()
+ Set .TableDescriptor = Nothing
+ .TableFieldsCount = 0
+ .TableKeysCount = 0
+ End With
+ Case COLLTEMPVARS
+ If Not Utils._CheckArgument(pvNew, 1, vbString) Then Goto Exit_Function
+ If pvNew = &quot;&quot; Then Goto Error_Name
+ If IsMissing(pvValue) Then Call _TraceArguments()
+ If _A2B_.hasItem(COLLTEMPVARS, pvNew) Then Goto Error_Name
+ Set oTempVar = New TempVar
+ oTempVar._This = oTempVar
+ oTempVar._Name = pvNew
+ oTempVar._Value = pvValue
+ _A2B_.TempVars.Add(oTempVar, UCase(pvNew))
+ Case Else
+ Goto Error_NotApplicable
+ End Select
+
+ _Count = _Count + 1
+ Add = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Sequence:
+ TraceError(TRACEFATAL, ERRTABLECREATION, Utils._CalledSub(), 0, 1, vObject._Name)
+ Goto Exit_Function
+Error_Name:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), False, ,Array(1, pvNew))
+ AddItem = False
+ Goto Exit_Function
+End Function &apos; Add V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Delete(ByVal Optional pvName As Variant) As Boolean
+&apos; Delete a TableDef or QueryDef object in the TableDefs/QueryDefs collections
+
+Const cstThisSub = &quot;Collection.Delete&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Dim odbDatabase As Object, oColl As Object, vName As Variant
+ Delete = False
+ If IsMissing(pvName) Then pvName = &quot;&quot;
+ If Not Utils._CheckArgument(pvName, 1, vbString) Then Goto Exit_Function
+ If pvName = &quot;&quot; Then Call _TraceArguments()
+
+ Select Case _CollType
+ Case COLLTABLEDEFS, COLLQUERYDEFS
+ If _A2B_.CurrentDocIndex() &lt;&gt; 0 Then Goto Error_NotApplicable
+ Set odbDatabase = Application._CurrentDb()
+ If odbDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ If _CollType = COLLTABLEDEFS Then Set oColl = odbDatabase.Connection.getTables() Else Set oColl = odbDatabase.Connection.getQueries()
+ With oColl
+ vName = _InList(pvName, .getElementNames(), True)
+ If vName = False Then Goto trace_NotFound
+ .dropByName(vName)
+ End With
+ odbDatabase.Document.store()
+ Case Else
+ Goto Error_NotApplicable
+ End Select
+
+ _Count = _Count - 1
+ Delete = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(Left(_CollType, 5)), pvName))
+ Goto Exit_Function
+End Function &apos; Delete V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Collection.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;Collection.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Remove(ByVal Optional pvName As Variant) As Boolean
+&apos; Remove a TempVar from the TempVars collection
+
+Const cstThisSub = &quot;Collection.Remove&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Dim oColl As Object, vName As Variant
+ Remove = False
+ If IsMissing(pvName) Then pvName = &quot;&quot;
+ If Not Utils._CheckArgument(pvName, 1, vbString) Then Goto Exit_Function
+ If pvName = &quot;&quot; Then Call _TraceArguments()
+
+ Select Case _CollType
+ Case COLLTEMPVARS
+ If Not _A2B_.hasItem(COLLTEMPVARS, pvName) Then Goto Error_Name
+ _A2B_.TempVars.Remove(UCase(pvName))
+ Case Else
+ Goto Error_NotApplicable
+ End Select
+
+ _Count = _Count - 1
+ Remove = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Name:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), False, ,Array(1, pvName))
+ AddItem = False
+ Goto Exit_Function
+End Function &apos; Remove V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function RemoveAll() As Boolean
+&apos; Remove the whole TempVars collection
+
+Const cstThisSub = &quot;Collection.Remove&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Select Case _CollType
+ Case COLLTEMPVARS
+ Set _A2B_.TempVars = New Collection
+ _Count = 0
+ Case Else
+ Goto Error_NotApplicable
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+End Function &apos; RemoveAll V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+ _PropertiesList = Array(&quot;Count&quot;, &quot;Item&quot;, &quot;ObjectType&quot;)
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Collection.get&quot; &amp; psProperty)
+ _PropertyGet = Nothing
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Count&quot;)
+ _PropertyGet = _Count
+ Case UCase(&quot;Item&quot;)
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Collection.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertyGet = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Collection._PropertyGet&quot;, Erl)
+ _PropertyGet = Nothing
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/CommandBar.xba b/wizards/source/access2base/CommandBar.xba
new file mode 100644
index 000000000..c30f696fb
--- /dev/null
+++ b/wizards/source/access2base/CommandBar.xba
@@ -0,0 +1,396 @@
+<?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="CommandBar" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be COMMANDBAR
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _ResourceURL As String
+Private _Window As Object &apos; com.sun.star.frame.XFrame
+Private _Module As String
+Private _Toolbar As Object
+Private _BarBuiltin As Integer &apos; 1 = builtin, 2 = custom stored in LO/AOO (Base), 3 = custom stored in document (Form)
+Private _BarType As Integer &apos; See msoBarTypeXxx constants
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJCOMMANDBAR
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ _ResourceURL = &quot;&quot;
+ Set _Window = Nothing
+ _Module = &quot;&quot;
+ Set _Toolbar = Nothing
+ _BarBuiltin = 0
+ _BarType = -1
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get BuiltIn() As Boolean
+ BuiltIn = _PropertyGet(&quot;BuiltIn&quot;)
+End Property &apos; BuiltIn (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Parent() As Object
+ Parent = _Parent
+End Function &apos; Parent (get) V6.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Visible() As Variant
+ Visible = _PropertyGet(&quot;Visible&quot;)
+End Property &apos; Visible (get)
+
+Property Let Visible(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Visible&quot;, pvValue)
+End Property &apos; Visible (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CommandBarControls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Return an object of type CommandBarControl indicated by its index
+&apos; Index is different from UNO index: separators do not count
+&apos; If no pvIndex argument, return a Collection type
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;CommandBar.CommandBarControls&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim oLayout As Object, vElements() As Variant, iIndexToolbar As Integer, oToolbar As Object
+Dim i As Integer, iItemsCount As Integer, oSettings As Object, vItem() As Variant, bSeparator As Boolean
+Dim oObject As Object
+
+ Set oObject = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If pvIndex &lt; 0 Then Goto Trace_IndexError
+ End If
+
+ Select Case _BarType
+ Case msoBarTypeNormal, msoBarTypeMenuBar
+ Case Else : Goto Error_NotApplicable &apos; Status bar not supported
+ End Select
+
+ Set oLayout = _Window.LayoutManager
+ vElements = oLayout.getElements()
+ iIndexToolbar = _FindElement(vElements())
+ If iIndexToolbar &lt; 0 Then Goto Error_NotApplicable &apos; Toolbar not visible
+ Set oToolbar = vElements(iIndexToolbar)
+
+ iItemsCount = 0
+ Set oSettings = oToolbar.getSettings(False)
+
+ bSeparator = False
+ For i = 0 To oSettings.getCount() - 1
+ Set vItem() = oSettings.getByIndex(i)
+ If _GetPropertyValue(vItem, &quot;Type&quot;, 1) &lt;&gt; 1 Then &apos; Type = 1 indicates separator
+ iItemsCount = iItemsCount + 1
+ If Not IsMissing(pvIndex) Then
+ If pvIndex = iItemsCount - 1 Then
+ Set oObject = New CommandBarControl
+ With oObject
+ Set ._This = oObject
+ Set ._Parent = _This
+ ._ParentCommandBarName = _Name
+ ._ParentCommandBar = oToolbar
+ ._ParentBuiltin = ( _BarBuiltin = 1 )
+ ._Element = vItem()
+ ._InternalIndex = i
+ ._Index = iItemsCount &apos; Indexes start at 1
+ ._BeginGroup = bSeparator
+ End With
+ End If
+ bSeparator = False
+ End If
+ Else
+ bSeparator = True
+ End If
+ Next i
+
+ If IsNull(oObject) Then
+ Select Case True
+ Case IsMissing(pvIndex)
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLCOMMANDBARCONTROLS
+ Set oObject._Parent = _This
+ oObject._Count = iItemsCount
+ Case Else &apos; pvIndex is numeric
+ Goto Trace_IndexError
+ End Select
+ End If
+
+Exit_Function:
+ Set CommandBarControls = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+End Function &apos; CommandBarControls V1,3,0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Controls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Alias for CommandBarControls (VBA)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;CommandBar.Controls&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim oObject As Object
+
+ If IsMissing(pvIndex) Then Set oObject = CommandBarControls() Else Set oObject = CommandBarControls(pvIndex)
+
+Exit_Function:
+ Set Controls = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; Controls V1,3,0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;CommandBar.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;CommandBar.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Reset() As Boolean
+&apos; Reset a whole command bar to its initial values
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;CommandBar.Reset&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ _Toolbar.reload()
+
+Exit_Function:
+ Reset = True
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Reset = False
+ GoTo Exit_Function
+End Function &apos; Reset V1.3.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _FindElement(pvElements As Variant) As Integer
+&apos; Return -1 if not found, otherwise return index in elements table of LayoutManager
+
+Dim i As Integer
+
+ _FindElement = -1
+ If Not IsArray(pvElements) Then Exit Function
+
+ For i = 0 To UBound(pvElements)
+ If _ResourceURL = pvElements(i).ResourceURL Then
+ _FindElement = i
+ Exit Function
+ End If
+ Next i
+
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+ _PropertiesList = Array(&quot;BuiltIn&quot;, &quot;Name&quot;, &quot;ObjectType&quot;, &quot;Visible&quot;)
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;CommandBar.get&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+ _PropertyGet = Nothing
+
+Dim oLayout As Object, iElementIndex As Integer
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;BuiltIn&quot;)
+ _PropertyGet = ( _BarBuiltin = 1 )
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Visible&quot;)
+ Set oLayout = _Window.LayoutManager
+ iElementIndex = _FindElement(oLayout.getElements())
+ If iElementIndex &lt; 0 Then _PropertyGet = False Else _PropertyGet = oLayout.isElementVisible(_ResourceURL)
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ _PropertyGet = Nothing
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;CommandBar.set&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+ _PropertySet = True
+Dim iArgNr As Integer
+Dim oLayout As Object, iElementIndex As Integer
+
+
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;setProperty&quot;) : iArgNr = 3
+ Case UCase(&quot;CommandBar.setProperty&quot;) : iArgNr = 2
+ Case UCase(cstThisSub) : iArgNr = 1
+ End Select
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Visible&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ Set oLayout = _Window.LayoutManager
+ With oLayout
+ iElementIndex = _FindElement(.getElements())
+ If iElementIndex &lt; 0 Then
+ If pvValue Then
+ .createElement(_ResourceURL)
+ .showElement(_ResourceURL)
+ End If
+ Else
+ If pvValue &lt;&gt; .isElementVisible(_ResourceURL) Then
+ If pvValue Then .showElement(_ResourceURL) Else .hideElement(_ResourceURL)
+ End If
+ End If
+ End With
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/CommandBarControl.xba b/wizards/source/access2base/CommandBarControl.xba
new file mode 100644
index 000000000..9cf183ba9
--- /dev/null
+++ b/wizards/source/access2base/CommandBarControl.xba
@@ -0,0 +1,339 @@
+<?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="CommandBarControl" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be COMMANDBARCONTROL
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _InternalIndex As Integer &apos; Index in toolbar including separators
+Private _Index As Integer &apos; Index in collection, starting at 1 !!
+Private _ControlType As Integer &apos; 1 of the msoControl* constants
+Private _ParentCommandBarName As String
+Private _ParentCommandBar As Object &apos; com.sun.star.ui.XUIElement
+Private _ParentBuiltin As Boolean
+Private _Element As Variant
+Private _BeginGroup As Boolean
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJCOMMANDBARCONTROL
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Index = -1
+ _ParentCommandBarName = &quot;&quot;
+ Set _ParentCommandBar = Nothing
+ _ParentBuiltin = False
+ _Element = Array()
+ _BeginGroup = False
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get BeginGroup() As Boolean
+ BeginGroup = _PropertyGet(&quot;BeginGroup&quot;)
+End Property &apos; BeginGroup (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get BuiltIn() As Boolean
+ BuiltIn = _PropertyGet(&quot;BuiltIn&quot;)
+End Property &apos; BuiltIn (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Caption() As Variant
+ Caption = _PropertyGet(&quot;Caption&quot;)
+End Property &apos; Caption (get)
+
+Property Let Caption(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Caption&quot;, pvValue)
+End Property &apos; Caption (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Index() As Integer
+ Index = _PropertyGet(&quot;Index&quot;)
+End Property &apos; Index (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnAction() As Variant
+ OnAction = _PropertyGet(&quot;OnAction&quot;)
+End Property &apos; OnAction (get)
+
+Property Let OnAction(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnAction&quot;, pvValue)
+End Property &apos; OnAction (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Parent() As Object
+ Parent = _PropertyGet(&quot;Parent&quot;)
+End Property &apos; Parent (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get TooltipText() As Variant
+ TooltipText = _PropertyGet(&quot;TooltipText&quot;)
+End Property &apos; TooltipText (get)
+
+Property Let TooltipText(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;TooltipText&quot;, pvValue)
+End Property &apos; TooltipText (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function pType() As Integer
+ pType = _PropertyGet(&quot;Type&quot;)
+End Function &apos; Type (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Visible() As Variant
+ Visible = _PropertyGet(&quot;Visible&quot;)
+End Property &apos; Visible (get)
+
+Property Let Visible(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Visible&quot;, pvValue)
+End Property &apos; Visible (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Execute()
+&apos; Execute the command stored in a toolbar button
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;CommandBarControl.Execute&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim sExecute As String
+
+ Execute = True
+ sExecute = _GetPropertyValue(_Element, &quot;CommandURL&quot;, &quot;&quot;)
+
+ Select Case True
+ Case sExecute = &quot;&quot; : Execute = False
+ Case _IsLeft(sExecute, &quot;.uno:&quot;)
+ Execute = DoCmd.RunCommand(sExecute)
+ Case _IsLeft(sExecute, &quot;vnd.sun.star.script:&quot;)
+ Execute = Utils._RunScript(sExecute, Array(Nothing))
+ Case Else
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Execute = False
+ GoTo Exit_Function
+End Function &apos; Execute V1.3.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;CommandBarControl.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;CommandBar.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+ _PropertiesList = Array(&quot;BeginGroup&quot;, &quot;BuiltIn&quot;, &quot;Caption&quot;, &quot;Index&quot; _
+ , &quot;ObjectType&quot;, &quot;OnAction&quot;, &quot;Parent&quot; _
+ , &quot;TooltipText&quot;, &quot;Type&quot;, &quot;Visible&quot; _
+ )
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;CommandBarControl.get&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+ _PropertyGet = Null
+
+Dim oLayout As Object, iElementIndex As Integer
+Dim sValue As String
+Const cstUnoPrefix = &quot;.uno:&quot;
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;BeginGroup&quot;)
+ _PropertyGet = _BeginGroup
+ Case UCase(&quot;BuiltIn&quot;)
+ sValue = _GetPropertyValue(_Element, &quot;CommandURL&quot;, &quot;&quot;)
+ _PropertyGet = ( _IsLeft(sValue, cstUnoPrefix) )
+ Case UCase(&quot;Caption&quot;)
+ _PropertyGet = _GetPropertyValue(_Element, &quot;Label&quot;, &quot;&quot;)
+ Case UCase(&quot;Index&quot;)
+ _PropertyGet = _Index
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;OnAction&quot;)
+ _PropertyGet = _GetPropertyValue(_Element, &quot;CommandURL&quot;, &quot;&quot;)
+ Case UCase(&quot;Parent&quot;)
+ Set _PropertyGet = _Parent
+ Case UCase(&quot;TooltipText&quot;)
+ sValue = _GetPropertyValue(_Element, &quot;Tooltip&quot;, &quot;&quot;)
+ If sValue &lt;&gt; &quot;&quot; Then _PropertyGet = sValue Else _PropertyGet = _GetPropertyValue(_Element, &quot;Label&quot;, &quot;&quot;)
+ Case UCase(&quot;Type&quot;)
+ _PropertyGet = msoControlButton
+ Case UCase(&quot;Visible&quot;)
+ _PropertyGet = _GetPropertyValue(_Element, &quot;IsVisible&quot;, &quot;&quot;)
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ _PropertyGet = Nothing
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;CommandBarControl.set&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+ _PropertySet = True
+Dim iArgNr As Integer
+Dim oSettings As Object, sValue As String
+
+
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;setProperty&quot;) : iArgNr = 3
+ Case UCase(&quot;CommandBar.setProperty&quot;) : iArgNr = 2
+ Case UCase(cstThisSub) : iArgNr = 1
+ End Select
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+ If _ParentBuiltin Then Goto Trace_Error &apos; Modifications of individual controls forbidden for builtin toolbars (design choice)
+
+Const cstUnoPrefix = &quot;.uno:&quot;
+Const cstScript = &quot;vnd.sun.star.script:&quot;
+
+ Set oSettings = _ParentCommandBar.getSettings(True)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;OnAction&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, _AddNumeric(vbString), , False) Then Goto Trace_Error_Value
+ Select Case VarType(pvValue)
+ Case vbString
+ If _IsLeft(pvValue, cstUnoPrefix) Then
+ sValue = pvValue
+ ElseIf _IsLeft(pvValue, cstScript) Then
+ sValue = pvValue
+ Else
+ sValue = DoCmd.RunCommand(pvValue, True)
+ End If
+ Case Else &apos; Numeric
+ sValue = DoCmd.RunCommand(pvValue, True)
+ End Select
+ _SetPropertyValue(_Element, &quot;CommandURL&quot;, sValue)
+ Case UCase(&quot;TooltipText&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ _SetPropertyValue(_Element, &quot;Tooltip&quot;, pvValue)
+ Case UCase(&quot;Visible&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ _SetPropertyValue(_Element, &quot;IsVisible&quot;, pvValue)
+ Case Else
+ Goto Trace_Error
+ End Select
+ oSettings.replaceByIndex(_InternalIndex, _Element)
+ _ParentCommandBar.setSettings(oSettings)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Control.xba b/wizards/source/access2base/Control.xba
new file mode 100644
index 000000000..b22bb819b
--- /dev/null
+++ b/wizards/source/access2base/Control.xba
@@ -0,0 +1,2501 @@
+<?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="Control" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be CONTROL
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _ImplementationName As String
+Private _ClassId As Integer
+Private _ParentType As String &apos; One of CTLPARENTISxxxx constants
+Private _Shortcut As String
+Private _Name As String
+Private _FormComponent As Object &apos; com.sun.star.text.TextDocument
+Private _MainForm As String &apos; To be propagated to all subcontrols
+Private _DocEntry As Integer &apos; Doc- and DbContainer entries in Root structure
+Private _DbEntry As Integer
+Private _ControlType As Integer
+Private _ThisProperties As Variant &apos; Buffer for properties list
+Private _SubType As String
+Private ControlModel As Object &apos; com.sun.star.comp.forms.XXXModel
+Private ControlView As Object &apos; com.sun.star.comp.forms.XXXControl (NULL if form open in edit mode)
+Private BoundField As Object &apos; com.sun.star.sdb.ODataColumn
+Private LabelControl As Object &apos; com.sun.star.form.component.FixedText or com.sun.star.form.component.GroupBox
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJCONTROL
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _ClassId = -1
+ _ParentType = &quot;&quot;
+ _Shortcut = &quot;&quot;
+ _Name = &quot;&quot;
+ Set _FormComponent = Nothing
+ _MainForm = &quot;&quot;
+ _DocEntry = -1
+ _DbEntry = -1
+ _ThisProperties = Array()
+ _SubType = &quot;&quot;
+ Set ControlModel = Nothing
+ Set ControlView = Nothing
+ Set BoundField = Nothing
+ Set LabelControl = Nothing
+
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get BackColor() As Variant
+ BackColor = _PropertyGet(&quot;BackColor&quot;)
+End Property &apos; BackColor (get)
+
+Property Let BackColor(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;BackColor&quot;, pvValue)
+End Property &apos; BackColor (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get BorderColor() As Variant
+ BorderColor = _PropertyGet(&quot;BorderColor&quot;)
+End Property &apos; BorderColor (get)
+
+Property Let BorderColor(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;BorderColor&quot;, pvValue)
+End Property &apos; BorderColor (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get BorderStyle() As Variant
+ BorderStyle = _PropertyGet(&quot;BorderStyle&quot;)
+End Property &apos; BorderStyle (get)
+
+Property Let BorderStyle(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;BorderStyle&quot;, pvValue)
+End Property &apos; BorderStyle (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Cancel() As Variant
+ Cancel = _PropertyGet(&quot;Cancel&quot;)
+End Property &apos; Cancel (get)
+
+Property Let Cancel(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Cancel&quot;, pvValue)
+End Property &apos; Cancel (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Caption() As Variant
+ Caption = _PropertyGet(&quot;Caption&quot;)
+End Property &apos; Caption (get)
+
+Property Let Caption(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Caption&quot;, pvValue)
+End Property &apos; Caption (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ControlSource() As Variant
+ ControlSource = _PropertyGet(&quot;ControlSource&quot;)
+End Property &apos; ControlSource (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ControlTipText() As Variant
+ ControlTipText = _PropertyGet(&quot;ControlTipText&quot;)
+End Property &apos; ControlTipText (get)
+
+Property Let ControlTipText(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;ControlTipText&quot;, pvValue)
+End Property &apos; ControlTipText (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ControlType() As Variant
+ ControlType = _PropertyGet(&quot;ControlType&quot;)
+End Property &apos; ControlType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Default() As Variant
+ Default = _PropertyGet(&quot;Default&quot;)
+End Property &apos; Default (get)
+
+Property Let Default(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Default&quot;, pvValue)
+End Property &apos; Default (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get DefaultValue() As Variant
+ DefaultValue = _PropertyGet(&quot;DefaultValue&quot;)
+End Property &apos; DefaultValue (get)
+
+Property Let DefaultValue(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;DefaultValue&quot;, pvValue)
+End Property &apos; DefaultValue (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Enabled() As Variant
+ Enabled = _PropertyGet(&quot;Enabled&quot;)
+End Property &apos; Enabled (get)
+
+Property Let Enabled(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Enabled&quot;, pvValue)
+End Property &apos; Enabled (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FontBold() As Variant
+ FontBold = _PropertyGet(&quot;FontBold&quot;)
+End Property &apos; FontBold (get)
+
+Property Let FontBold(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FontBold&quot;, pvValue)
+End Property &apos; FontBold (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FontItalic() As Variant
+ FontItalic = _PropertyGet(&quot;FontItalic&quot;)
+End Property &apos; FontItalic (get)
+
+Property Let FontItalic(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FontItalic&quot;, pvValue)
+End Property &apos; FontItalic (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FontName() As Variant
+ FontName = _PropertyGet(&quot;FontName&quot;)
+End Property &apos; FontName (get)
+
+Property Let FontName(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FontName&quot;, pvValue)
+End Property &apos; FontName (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FontSize() As Variant
+ FontSize = _PropertyGet(&quot;FontSize&quot;)
+End Property &apos; FontSize (get)
+
+Property Let FontSize(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FontSize&quot;, pvValue)
+End Property &apos; FontSize (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FontUnderline() As Variant
+ FontUnderline = _PropertyGet(&quot;FontUnderline&quot;)
+End Property &apos; FontUnderline (get)
+
+Property Let FontUnderline(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FontUnderline&quot;, pvValue)
+End Property &apos; FontUnderline (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FontWeight() As Variant
+ FontWeight = _PropertyGet(&quot;FontWeight&quot;)
+End Property &apos; FontWeight (get)
+
+Property Let FontWeight(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FontWeight&quot;, pvValue)
+End Property &apos; FontWeight (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ForeColor() As Variant
+ ForeColor = _PropertyGet(&quot;ForeColor&quot;)
+End Property &apos; ForeColor (get)
+
+Property Let ForeColor(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;ForeColor&quot;, pvValue)
+End Property &apos; ForeColor (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Form() As Variant
+ Form = _PropertyGet(&quot;Form&quot;)
+End Property &apos; Form (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Format() As Variant
+ Format = _PropertyGet(&quot;Format&quot;)
+End Property &apos; Format (get)
+
+Property Let Format(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Format&quot;, pvValue)
+End Property &apos; Format (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ItemData(ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvIndex) Then ItemData = _PropertyGet(&quot;ItemData&quot;) Else ItemData = _PropertyGet(&quot;ItemData&quot;, pvIndex)
+End Property &apos; ItemData (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ListCount() As Variant
+ ListCount = _PropertyGet(&quot;ListCount&quot;)
+End Property &apos; ListCount (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ListIndex() As Variant
+ ListIndex = _PropertyGet(&quot;ListIndex&quot;)
+End Property &apos; ListIndex (get)
+
+Property Let ListIndex(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;ListIndex&quot;, pvValue)
+End Property &apos; ListIndex (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Locked() As Variant
+ Locked = _PropertyGet(&quot;Locked&quot;)
+End Property &apos; Locked (get)
+
+Property Let Locked(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Locked&quot;, pvValue)
+End Property &apos; Locked (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get MultiSelect() As Variant
+ MultiSelect = _PropertyGet(&quot;MultiSelect&quot;)
+End Property &apos; MultiSelect (get)
+
+Property Let MultiSelect(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;MultiSelect&quot;, pvValue)
+End Property &apos; MultiSelect (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnActionPerformed() As Variant
+ OnActionPerformed = _PropertyGet(&quot;OnActionPerformed&quot;)
+End Property &apos; OnActionPerformed (get)
+
+Property Let OnActionPerformed(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnActionPerformed&quot;, pvValue)
+End Property &apos; OnActionPerformed (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnAdjustmentValueChanged() As Variant
+ OnAdjustmentValueChanged = _PropertyGet(&quot;OnAdjustmentValueChanged&quot;)
+End Property &apos; OnAdjustmentValueChanged (get)
+
+Property Let OnAdjustmentValueChanged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnAdjustmentValueChanged&quot;, pvValue)
+End Property &apos; OnAdjustmentValueChanged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveAction() As Variant
+ OnApproveAction = _PropertyGet(&quot;OnApproveAction&quot;)
+End Property &apos; OnApproveAction (get)
+
+Property Let OnApproveAction(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveAction&quot;, pvValue)
+End Property &apos; OnApproveAction (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveReset() As Variant
+ OnApproveReset = _PropertyGet(&quot;OnApproveReset&quot;)
+End Property &apos; OnApproveReset (get)
+
+Property Let OnApproveReset(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveReset&quot;, pvValue)
+End Property &apos; OnApproveReset (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveUpdate() As Variant
+ OnApproveUpdate = _PropertyGet(&quot;OnApproveUpdate&quot;)
+End Property &apos; OnApproveUpdate (get)
+
+Property Let OnApproveUpdate(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveUpdate&quot;, pvValue)
+End Property &apos; OnApproveUpdate (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnChanged() As Variant
+ OnChanged = _PropertyGet(&quot;OnChanged&quot;)
+End Property &apos; OnChanged (get)
+
+Property Let OnChanged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnChanged&quot;, pvValue)
+End Property &apos; OnChanged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnErrorOccurred() As Variant
+ OnErrorOccurred = _PropertyGet(&quot;OnErrorOccurred&quot;)
+End Property &apos; OnErrorOccurred (get)
+
+Property Let OnErrorOccurred(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnErrorOccurred&quot;, pvValue)
+End Property &apos; OnErrorOccurred (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnFocusGained() As Variant
+ OnFocusGained = _PropertyGet(&quot;OnFocusGained&quot;)
+End Property &apos; OnFocusGained (get)
+
+Property Let OnFocusGained(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnFocusGained&quot;, pvValue)
+End Property &apos; OnFocusGained (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnFocusLost() As Variant
+ OnFocusLost = _PropertyGet(&quot;OnFocusLost&quot;)
+End Property &apos; OnFocusLost (get)
+
+Property Let OnFocusLost(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnFocusLost&quot;, pvValue)
+End Property &apos; OnFocusLost (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnItemStateChanged() As Variant
+ OnItemStateChanged = _PropertyGet(&quot;OnItemStateChanged&quot;)
+End Property &apos; OnItemStateChanged (get)
+
+Property Let OnItemStateChanged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnItemStateChanged&quot;, pvValue)
+End Property &apos; OnItemStateChanged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnKeyPressed() As Variant
+ OnKeyPressed = _PropertyGet(&quot;OnKeyPressed&quot;)
+End Property &apos; OnKeyPressed (get)
+
+Property Let OnKeyPressed(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnKeyPressed&quot;, pvValue)
+End Property &apos; OnKeyPressed (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnKeyReleased() As Variant
+ OnKeyReleased = _PropertyGet(&quot;OnKeyReleased&quot;)
+End Property &apos; OnKeyReleased (get)
+
+Property Let OnKeyReleased(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnKeyReleased&quot;, pvValue)
+End Property &apos; OnKeyReleased (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseDragged() As Variant
+ OnMouseDragged = _PropertyGet(&quot;OnMouseDragged&quot;)
+End Property &apos; OnMouseDragged (get)
+
+Property Let OnMouseDragged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseDragged&quot;, pvValue)
+End Property &apos; OnMouseDragged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseEntered() As Variant
+ OnMouseEntered = _PropertyGet(&quot;OnMouseEntered&quot;)
+End Property &apos; OnMouseEntered (get)
+
+Property Let OnMouseEntered(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseEntered&quot;, pvValue)
+End Property &apos; OnMouseEntered (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseExited() As Variant
+ OnMouseExited = _PropertyGet(&quot;OnMouseExited&quot;)
+End Property &apos; OnMouseExited (get)
+
+Property Let OnMouseExited(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseExited&quot;, pvValue)
+End Property &apos; OnMouseExited (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseMoved() As Variant
+ OnMouseMoved = _PropertyGet(&quot;OnMouseMoved&quot;)
+End Property &apos; OnMouseMoved (get)
+
+Property Let OnMouseMoved(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseMoved&quot;, pvValue)
+End Property &apos; OnMouseMoved (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMousePressed() As Variant
+ OnMousePressed = _PropertyGet(&quot;OnMousePressed&quot;)
+End Property &apos; OnMousePressed (get)
+
+Property Let OnMousePressed(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMousePressed&quot;, pvValue)
+End Property &apos; OnMousePressed (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseReleased() As Variant
+ OnMouseReleased = _PropertyGet(&quot;OnMouseReleased&quot;)
+End Property &apos; OnMouseReleased (get)
+
+Property Let OnMouseReleased(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseReleased&quot;, pvValue)
+End Property &apos; OnMouseReleased (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnResetted() As Variant
+ OnResetted = _PropertyGet(&quot;OnResetted&quot;)
+End Property &apos; OnResetted (get)
+
+Property Let OnResetted(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnResetted&quot;, pvValue)
+End Property &apos; OnResetted (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnTextChanged() As Variant
+ OnTextChanged = _PropertyGet(&quot;OnTextChanged&quot;)
+End Property &apos; OnTextChanged (get)
+
+Property Let OnTextChanged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnTextChanged&quot;, pvValue)
+End Property &apos; OnTextChanged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUpdated() As Variant
+ OnUpdated = _PropertyGet(&quot;OnUpdated&quot;)
+End Property &apos; OnUpdated (get)
+
+Property Let OnUpdated(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnUpdated&quot;, pvValue)
+End Property &apos; OnUpdated (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OptionValue() As Variant
+ OptionValue = _PropertyGet(&quot;OptionValue&quot;)
+End Property &apos; OptionValue (get)
+
+Property Let OptionValue(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OptionValue&quot;, pvValue)
+End Property &apos; OptionValue (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Page() As Variant
+ Page = _PropertyGet(&quot;Page&quot;)
+End Property &apos; Page (get)
+
+Property Let Page(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Page&quot;, pvValue)
+End Property &apos; Page (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Parent() As Object
+ Parent = _PropertyGet(&quot;Parent&quot;)
+End Function &apos; Parent (get) V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Picture() As Variant
+ Picture = _PropertyGet(&quot;Picture&quot;)
+End Property &apos; Picture (get)
+
+Property Let Picture(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Picture&quot;, pvValue)
+End Property &apos; Picture (set) V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+ Utils._SetCalledSub(&quot;Control.Properties&quot;)
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(&quot;Control.Properties&quot;)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Required() As Variant
+ Required = _PropertyGet(&quot;Required&quot;)
+End Property &apos; Required (get)
+
+Property Let Required(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Required&quot;, pvValue)
+End Property &apos; Required (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get RowSource() As Variant
+ RowSource = _PropertyGet(&quot;RowSource&quot;)
+End Property &apos; RowSource (get)
+
+Property Let RowSource(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;RowSource&quot;, pvValue)
+End Property &apos; RowSource (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get RowSourceType() As Variant
+ RowSourceType = _PropertyGet(&quot;RowSourceType&quot;)
+End Property &apos; RowSourceType (get)
+
+Property Let RowSourceType(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;RowSourceType&quot;, pvValue)
+End Property &apos; RowSourceType (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Selected(ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvIndex) Then Selected = _PropertyGet(&quot;Selected&quot;) Else Selected = _PropertyGet(&quot;Selected&quot;, pvIndex)
+End Property &apos; Selected (get)
+
+Property Let Selected(ByVal pvValue As Variant) &apos; , ByVal Optional pvIndex As Variant)
+&apos; If IsMissing(pvIndex) Then Call _PropertySet(&quot;Selected&quot;, pvValue) Else Call _PropertySet(&quot;Selected&quot;, pvValue, pvIndex)
+ Call _PropertySet(&quot;Selected&quot;, pvValue)
+End Property &apos; Selected (set)
+
+Public Function SelectedI(ByVal pvValue As variant, ByVal pvIndex As Variant)
+ Call _PropertySet(&quot;Selected&quot;, pvValue, pvIndex)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SelLength() As Variant
+ SelLength = _PropertyGet(&quot;SelLength&quot;)
+End Property &apos; SelLength (get)
+
+Property Let SelLength(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;SelLength&quot;, pvValue)
+End Property &apos; SelLength (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SelStart() As Variant
+ SelStart = _PropertyGet(&quot;SelStart&quot;)
+End Property &apos; SelStart (get)
+
+Property Let SelStart(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;SelStart&quot;, pvValue)
+End Property &apos; SelStart (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SelText() As Variant
+ SelText = _PropertyGet(&quot;SelText&quot;)
+End Property &apos; SelText (get)
+
+Property Let SelText(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;SelText&quot;, pvValue)
+End Property &apos; SelText (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SpecialEffect() As Variant
+ SpecialEffect = _PropertyGet(&quot;SpecialEffect&quot;)
+End Property &apos; SpecialEffect (get)
+
+Property Let SpecialEffect(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;SpecialEffect&quot;, pvValue)
+End Property &apos; SpecialEffect (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SubType() As Variant
+ SubType = _PropertyGet(&quot;SubType&quot;)
+End Property &apos; SubType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get TabIndex() As Variant
+ TabIndex = _PropertyGet(&quot;TabIndex&quot;)
+End Property &apos; TabIndex (get)
+
+Property Let TabIndex(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;TabIndex&quot;, pvValue)
+End Property &apos; TabIndex (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get TabStop() As Variant
+ TabStop = _PropertyGet(&quot;TabStop&quot;)
+End Property &apos; TabStop (get)
+
+Property Let TabStop(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;TabStop&quot;, pvValue)
+End Property &apos; TabStop (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Tag() As Variant
+ Tag = _PropertyGet(&quot;Tag&quot;)
+End Property &apos; Tag (get)
+
+Property Let Tag(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Tag&quot;, pvValue)
+End Property &apos; Tag (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Text() As Variant
+ Text = _PropertyGet(&quot;Text&quot;)
+End Property &apos; Text (get)
+
+Public Function pText() As Variant
+ pText = _PropertyGet(&quot;Text&quot;)
+End Function &apos; pText (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get TextAlign() As Variant
+ TextAlign = _PropertyGet(&quot;TextAlign&quot;)
+End Property &apos; TextAlign (get)
+
+Property Let TextAlign(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;TextAlign&quot;, pvValue)
+End Property &apos; TextAlign (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get TripleState() As Variant
+ TripleState = _PropertyGet(&quot;TripleState&quot;)
+End Property &apos; TripleState (get)
+
+Property Let TripleState(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;TripleState&quot;, pvValue)
+End Property &apos; TripleState (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Value() As Variant
+ Value = _PropertyGet(&quot;Value&quot;)
+End Property &apos; Value (get)
+
+Property Let Value(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Value&quot;, pvValue)
+End Property &apos; Value (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Visible() As Variant
+ Visible = _PropertyGet(&quot;Visible&quot;)
+End Property &apos; Visible (get)
+
+Property Let Visible(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Visible&quot;, pvValue)
+End Property &apos; Visible (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function AddItem(ByVal Optional pvItem As Variant, ByVal Optional pvIndex) As Boolean
+&apos; Add an item in a Listbox
+
+ Utils._SetCalledSub(&quot;Control.AddItem&quot;)
+ AddItem = False
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If IsMissing(pvItem) Then Call _TraceArguments()
+ If IsMissing(pvIndex) Then pvIndex = -1
+
+Dim iArgNr As Integer
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;AddItem&quot;) : iArgNr = 1
+ Case UCase(&quot;Control.AddItem&quot;) : iArgNr = 0
+ End Select
+
+ If Not Utils._CheckArgument(pvItem, iArgNr + 1, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvIndex, iArgNr + 2, Utils._AddNumeric()) Then Goto Exit_Function
+ If _SubType &lt;&gt; CTLLISTBOX Then Goto Error_Control
+ If _ParentType &lt;&gt; CTLPARENTISDIALOG Then
+ If ControlModel.ListSourceType &lt;&gt; com.sun.star.form.ListSourceType.VALUELIST Then Goto Error_Control
+ End If
+
+Dim vRowSource() As Variant, iCount As Integer, i As Integer
+ If IsArray(ControlModel.StringItemList) Then vRowSource = ControlModel.StringItemList Else vRowSource = Array(ControlModel.StringItemList)
+ iCount = UBound(vRowSource)
+ If pvIndex &lt; -1 Or pvIndex &gt; iCount + 1 Then Goto Error_Index
+ ReDim Preserve vRowSource(0 To iCount + 1)
+ If pvIndex = -1 Then pvIndex = iCount + 1
+ For i = iCount + 1 To pvIndex + 1 Step -1
+ vRowSource(i) = vRowSource(i - 1)
+ Next i
+ vRowSource(pvIndex) = pvItem
+
+ If _ParentType &lt;&gt; CTLPARENTISDIALOG Then
+ ControlModel.ListSource = vRowSource()
+ End If
+ ControlModel.StringItemList = vRowSource()
+ AddItem = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Control.AddItem&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Control.AddItem&quot;, Erl)
+ AddItem = False
+ GoTo Exit_Function
+Error_Control:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, , &quot;Control.AddItem&quot;)
+ AddItem = False
+ Goto Exit_Function
+Error_Index:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), False, ,Array(iArgNr + 2,pvIndex))
+ AddItem = False
+ Goto Exit_Function
+End Function &apos; AddItem V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Controls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Return a Control object with name or index = pvIndex
+
+Const cstThisSub = &quot;Control.Controls&quot;
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+
+Dim ocControl As Variant, sParentShortcut As String, iControlCount As Integer
+Dim oCounter As Variant, sControls() As Variant, i As Integer, bFound As Boolean, sIndex As String
+Dim j As Integer, oView As Object
+
+ If _SubType &lt;&gt; CTLGRIDCONTROL Then Goto Trace_Error_Context
+ Set ocControl = Nothing
+ iControlCount = ControlModel.getCount()
+
+ If IsMissing(pvIndex) Then &apos; No argument, return Collection pseudo-object
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLCONTROLS
+ Set oCounter._Parent = _This
+ oCounter._Count = iControlCount
+ Set Controls = oCounter
+ Goto Exit_Function
+ End If
+
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+
+ &apos; Start building the ocControl object
+ &apos; Determine exact name
+ Set ocControl = New Control
+ Set ocControl._This = ocControl
+ Set ocControl._Parent = _This
+ ocControl._ParentType = CTLPARENTISGRID
+ sParentShortcut = _Shortcut
+ sControls() = ControlModel.getElementNames()
+
+ Select Case VarType(pvIndex)
+ Case vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal
+ If pvIndex &lt; 0 Or pvIndex &gt; iControlCount - 1 Then Goto Trace_Error_Index
+ ocControl._Name = sControls(pvIndex)
+ Case vbString &apos; Check control name validity (non case sensitive)
+ bFound = False
+ sIndex = UCase(Utils._Trim(pvIndex))
+ For i = 0 To iControlCount - 1
+ If UCase(sControls(i)) = sIndex Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If bFound Then ocControl._Name = sControls(i) Else Goto Trace_NotFound
+ End Select
+
+ With ocControl
+ ._Shortcut = sParentShortcut &amp; &quot;!&quot; &amp; Utils._Surround(._Name)
+ Set .ControlModel = ControlModel.getByName(._Name)
+ ._ImplementationName = .ControlModel.ColumnServiceName &apos; getImplementationName aborts for subcontrols !?
+ ._FormComponent = ParentComponent
+ ._MainForm = _MainForm
+ If Utils._hasUNOProperty(.ControlModel, &quot;ClassId&quot;) Then ._ClassId = .ControlModel.ClassId
+ &apos; Complex bypass to find View of grid subcontrols !
+ If Not IsNull(ControlView) Then &apos; Anticipate absence of ControlView in grid controls when edit mode
+ For i = 0 to ControlView.getCount() - 1
+ Set oView = ControlView.GetByIndex(i)
+ If Not IsNull(oView) Then
+ If oView.getModel.Name = ._Name Then
+ Set .ControlView = oView
+ Exit For
+ End If
+ End If
+ Next i
+ End If
+
+ ._Initialize()
+ ._DocEntry = _DocEntry
+ ._DbEntry = _DbEntry
+ End With
+ Set Controls = ocControl
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERRCONTROLNOTFOUND, Utils._CalledSub(), 0, , Array(pvIndex, _Name))
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_Error_Context:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, , &quot;Grid.Controls&quot;)
+ Set Controls = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Set Controls = Nothing
+ GoTo Exit_Function
+End Function &apos; Controls
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Control.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ If IsMissing(pvIndex) Then
+ getProperty = _PropertyGet(pvProperty)
+ Else
+ getProperty = _PropertyGet(pvProperty, pvIndex)
+ End If
+ Utils._ResetCalledSub(&quot;Control.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function RemoveItem(ByVal Optional pvIndex) As Boolean
+&apos; Remove an item from a Listbox
+&apos; Index may be a string value or an index-position
+
+ Utils._SetCalledSub(&quot;Control.RemoveItem&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If IsMissing(pvIndex) Then Call _TraceArguments()
+Dim iArgNr As Integer
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;RemoveItem&quot;) : iArgNr = 1
+ Case UCase(&quot;Control.RemoveItem&quot;) : iArgNr = 0
+ End Select
+ If Not Utils._CheckArgument(pvIndex, iArgNr + 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ If _SubType &lt;&gt; CTLLISTBOX Then Goto Error_Control
+ If _ParentType &lt;&gt; CTLPARENTISDIALOG Then
+ If ControlModel.ListSourceType &lt;&gt; com.sun.star.form.ListSourceType.VALUELIST Then Goto Error_Control
+ End If
+
+Dim vRowSource() As Variant, iCount As Integer, i As Integer, j As integer, bFound As Boolean
+ If IsArray(ControlModel.StringItemList) Then vRowSource = ControlModel.StringItemList Else vRowSource = Array(ControlModel.StringItemList)
+ iCount = UBound(vRowSource)
+
+ Select Case VarType(pvIndex)
+ Case vbString
+ bFound = False
+ For i = 0 To iCount
+ If vRowSource(i) = pvIndex Then
+ For j = i To iCount - 1
+ vRowSource(j) = vRowSource(j + 1)
+ Next j
+ bFound = True
+ Exit For &apos; Remove only 1st occurrence of string
+ End If
+ Next i
+ Case Else
+ If pvIndex &lt; 0 Or pvIndex &gt; iCount Then Goto Error_Index
+ For i = pvIndex To iCount - 1
+ vRowSource(i) = vRowSource(i + 1)
+ Next i
+ bFound = True
+ End Select
+
+ If bFound Then
+ If iCount &gt; 0 Then &apos; https://forum.openoffice.org/en/forum/viewtopic.php?f=47&amp;t=75008
+ ReDim Preserve vRowSource(0 To iCount - 1)
+ Else
+ vRowSource = Array()
+ End If
+ If _ParentType &lt;&gt; CTLPARENTISDIALOG Then
+ ControlModel.ListSource = vRowSource()
+ End If
+ ControlModel.StringItemList = vRowSource()
+ RemoveItem = True
+ Else
+ RemoveItem = False
+ End If
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Control.RemoveItem&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Control.RemoveItem&quot;, Erl)
+ RemoveItem = False
+ GoTo Exit_Function
+Error_Control:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, &quot;Control.RemoveItem&quot;)
+ RemoveItem = False
+ Goto Exit_Function
+Error_Index:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), False, ,Array(2, pvIndex))
+ RemoveItem = False
+ Goto Exit_Function
+End Function &apos; RemoveItem V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Requery() As Boolean
+&apos; Refresh data displayed in a form, subform, combobox or listbox
+ Utils._SetCalledSub(&quot;Control.Requery&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Requery = False
+
+ Select Case _SubType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If Utils._InList(ControlModel.ListSourceType, Array( _
+ com.sun.star.form.ListSourceType.QUERY _
+ , com.sun.star.form.ListSourceType.TABLE _
+ , com.sun.star.form.ListSourceType.TABLEFIELDS _
+ , com.sun.star.form.ListSourceType.SQL _
+ , com.sun.star.form.ListSourceType.SQLPASSTHROUGH _
+ )) Then
+ ControlModel.refresh()
+ End If
+ Case Else
+ Goto Error_Control
+ End Select
+ Requery = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Control.Requery&quot;)
+ Exit Function
+Error_Control:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, &quot;Control.Requery&quot;)
+ Requery = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Control.Requery&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Requery
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SetFocus() As Boolean
+&apos; Execute setFocus method
+ Utils._SetCalledSub(&quot;Control.SetFocus&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ SetFocus = False
+
+Dim i As Integer, j As Integer, iColPosition As Integer
+Dim ocControl As Object, ocGrid As Variant, oGridModel As Object
+
+ If IsNull(ControlView) Then GoTo Exit_Function
+ If _ParentType = CTLPARENTISGRID Then &apos;setFocus method does not work on controlviews in grid ?!?
+ &apos; Find column position of control
+ iColPosition = -1
+ ocGrid = getObject(_getUpperShortcut(_Shortcut, _Name)) &apos; return containing grid
+ Set oGridModel = ocGrid.ControlModel
+ j = -1
+ For i = 0 To oGridModel.Count - 1
+ Set ocControl = oGridModel.GetByIndex(i)
+ If Not ocControl.Hidden Then j = j + 1 &apos; Skip if hidden
+ If oGridModel.GetByIndex(i).Name = _Name Then
+ iColPosition = j
+ Exit For
+ End If
+ Next i
+ If iColPosition &gt;= 0 Then
+ ocGrid.ControlView.setFocus() &apos;Set first focus on grid itself
+ ocGrid.ControlView.setCurrentColumnPosition(iColPosition) &apos;Deprecated but no alternative found
+ Else
+ Goto Error_Grid
+ End If
+ Else
+ ControlView.setFocus()
+ End If
+ SetFocus = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Control.SetFocus&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Control.SetFocus&quot;, Erl)
+ Goto Exit_Function
+Error_Grid:
+ TraceError(TRACEFATAL, ERRFOCUSINGRID, Utils._CalledSub(), 0, 1, Array(_Name, ocGrid._Name))
+ Goto Exit_Function
+End Function &apos; SetFocus V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant, ByVal Optional pvIndex As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;Control.setProperty&quot;)
+ If IsMissing(pvIndex) Then
+ setProperty = _PropertySet(psProperty, pvValue)
+ Else
+ setProperty = _PropertySet(psProperty, pvValue, pvIndex)
+ End If
+ Utils._ResetCalledSub(&quot;Control.setProperty&quot;)
+End Function &apos; setProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SetSelected(ByVal Optional pvValue As Variant, ByVal Optional pvIndex As Variant) As Boolean
+&apos; Workaround for limitation of Basic: Property Let does not accept optional arguments
+
+ If IsMissing(pvValue) Then Call _TraceArguments()
+ If IsMissing(pvIndex) Then
+ SetSelected = _PropertySet(&quot;Selected&quot;, pvValue)
+ Else
+ SetSelected = _PropertySet(&quot;Selected&quot;, pvValue, pvIndex)
+ End If
+
+End Function &apos; SetSelected
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _Formats(ByVal psControlType As String) As Variant
+&apos; Return allowed format entries for Date and Time control types
+
+Dim vFormats() As Variant
+ Select Case psControlType
+ Case CTLDATEFIELD
+ vFormats = Array( _
+ &quot;Standard (short)&quot; _
+ , &quot;Standard (short YY)&quot; _
+ , &quot;Standard (short YYYY)&quot; _
+ , &quot;Standard (long)&quot; _
+ , &quot;DD/MM/YY&quot; _
+ , &quot;MM/DD/YY&quot; _
+ , &quot;YY/MM/DD&quot; _
+ , &quot;DD/MM/YYYY&quot; _
+ , &quot;MM/DD/YYYY&quot; _
+ , &quot;YYYY/MM/DD&quot; _
+ , &quot;YY-MM-DD&quot; _
+ , &quot;YYYY-MM-DD&quot; _
+ )
+ Case CTLTIMEFIELD
+ vFormats = Array( _
+ &quot;24h short&quot; _
+ , &quot;24h long&quot; _
+ , &quot;12h short&quot; _
+ , &quot;12h long&quot; _
+ )
+ Case Else
+ vFormats = Array()
+ End Select
+
+ _Formats = vFormats
+
+End Function &apos; _Formats V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetListener(ByVal psProperty As String) As String
+&apos; Return the X...Listener corresponding with the property in argument
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;OnActionPerformed&quot;)
+ _GetListener = &quot;XActionListener&quot;
+ Case UCase(&quot;OnAdjustmentValueChanged&quot;)
+ _GetListener = &quot;XAdjustmentListener&quot;
+ Case UCase(&quot;OnApproveAction&quot;)
+ _GetListener = &quot;XApproveActionListener&quot;
+ Case UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnResetted&quot;)
+ _GetListener = &quot;XResetListener&quot;
+ Case UCase(&quot;OnApproveUpdate&quot;), UCase(&quot;OnUpdated&quot;)
+ _GetListener = &quot;XUpdateListener&quot;
+ Case UCase(&quot;OnChanged&quot;)
+ _GetListener = &quot;XChangeListener&quot;
+ Case UCase(&quot;OnErrorOccurred&quot;)
+ _GetListener = &quot;XErrorListener&quot;
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;)
+ _GetListener = &quot;XFocusListener&quot;
+ Case UCase(&quot;OnItemStateChanged&quot;)
+ _GetListener = &quot;XItemListener&quot;
+ Case UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;)
+ _GetListener = &quot;XKeyListener&quot;
+ Case UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseMoved&quot;)
+ _GetListener = &quot;XMouseMotionListener&quot;
+ Case UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ _GetListener = &quot;XMouseListener&quot;
+ Case UCase(&quot;OnTextChanged&quot;)
+ _GetListener = &quot;XTextListener&quot;
+ End Select
+
+End Function &apos; _GetListener V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos; Initialize new Control
+&apos; ControlModel, ParentType, Name, Shortcut, ControlView, ImplementationName, ClassId (if parent &lt;&gt; dialog)
+&apos; are presumed preexisting
+
+ &apos; Identify SubType and ControlView
+Dim sControlTypes() As Variant, i As Integer, vSplit() As Variant, sTrailer As String
+ sControlTypes = array( CTLCONTROL _
+ , CTLCOMMANDBUTTON _
+ , CTLRADIOBUTTON _
+ , CTLIMAGEBUTTON _
+ , CTLCHECKBOX _
+ , CTLLISTBOX _
+ , CTLCOMBOBOX _
+ , CTLGROUPBOX _
+ , CTLTEXTFIELD _
+ , CTLFIXEDTEXT _
+ , CTLGRIDCONTROL _
+ , CTLFILECONTROL _
+ , CTLHIDDENCONTROL _
+ , CTLIMAGECONTROL _
+ , CTLDATEFIELD _
+ , CTLTIMEFIELD _
+ , CTLNUMERICFIELD _
+ , CTLCURRENCYFIELD _
+ , CTLPATTERNFIELD _
+ , CTLSCROLLBAR _
+ , CTLSPINBUTTON _
+ , CTLNAVIGATIONBAR _
+ , CTLPROGRESSBAR _
+ , CTLFIXEDLINE _
+ )
+
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ vSplit = Split(ControlModel.getServiceName(), &quot;.&quot;)
+ sTrailer = UCase(vSplit(UBound(vSplit)))
+ &apos; Manage homonyms
+ Select Case sTrailer
+ Case &quot;BUTTON&quot; : sTrailer = CTLCOMMANDBUTTON
+ Case &quot;EDIT&quot; : sTrailer = CTLTEXTFIELD
+ Case Else
+ End Select
+ If sTrailer &lt;&gt; CTLFORMATTEDFIELD Then
+ For i = 0 To UBound(sControlTypes)
+ If sControlTypes(i) = sTrailer Then
+ _ClassId = i + 1
+ _SubType = sTrailer
+ _ControlType = _ClassId
+ Exit For
+ End If
+ Next i
+ Else
+ _ClassId = acFormattedField
+ _SubType = CTLFORMATTEDFIELD
+ _ControlType = _ClassId
+ End If
+ Case Else
+ &apos;Is ClassId one of the properties ?
+ If _ClassId &gt; 0 Then &apos; All control types have a ClassId except subforms
+ _SubType = sControlTypes(_ClassId - 1)
+ _ControlType = _ClassId
+ If _SubType = CTLTEXTFIELD Then &apos; Formatted fields belong to the TextField family
+ If _ImplementationName = &quot;com.sun.star.comp.forms.OFormattedFieldWrapper&quot; _
+ Or _ImplementationName = &quot;com.sun.star.comp.forms.OFormattedFieldWrapper_ForcedFormatted&quot; _
+ Or _ImplementationName = &quot;com.sun.star.form.component.FormattedField&quot; Then &apos; When in datagrid
+ _SubType = CTLFORMATTEDFIELD
+ _ControlType = acFormattedField
+ End If
+ End If
+ Else &apos; Initialize subform Control
+ If ControlModel.ImplementationName = &quot;com.sun.star.comp.forms.ODatabaseForm&quot; Then
+ _SubType = CTLSUBFORM
+ _ControlType = acSubform
+ End If
+ End If
+ End Select
+
+End Sub &apos; _Initialize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _ListboxBound() As Boolean
+&apos; Return True if listbox has a bound column
+
+Dim bListboxBound As Boolean, j As Integer
+Dim vValue() As variant, vString As Variant
+
+ bListboxBound = False
+
+ If Not IsNull(ControlModel.ValueItemList) _
+ And ControlModel.DataField &lt;&gt; &quot;&quot; _
+ And Not IsNull(ControlModel.BoundField) _
+ And Utils._InList(ControlModel.ListSourceType, Array( _
+ com.sun.star.form.ListSourceType.TABLE _
+ , com.sun.star.form.ListSourceType.QUERY _
+ , com.sun.star.form.ListSourceType.SQL _
+ , com.sun.star.form.ListSourceType.SQLPASSTHROUGH _
+ )) Then &apos; MultiSelect behaviour changed in OpenOffice &gt;= 3.3
+ If IsArray(ControlModel.ValueItemList) Then
+ vValue = ControlModel.ValueItemList
+ vString = ControlModel.StringItemList
+ For j = 0 To UBound(vValue)
+ If VarType(vValue(j)) &lt;&gt; VarType(vString(j)) Then
+ bListboxBound = True
+ ElseIf vValue(j) &lt;&gt; vString(j) Then
+ bListboxBound = True
+ End If
+ If bListboxBound Then Exit For
+ Next j
+ End If
+ End If
+
+ _ListboxBound = bListboxBound
+
+End Function &apos; _ListboxBound V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+&apos; Based on ControlProperties.ods analysis
+
+Dim vFullPropertiesList() As Variant
+
+ &apos;List established only once
+ If UBound(_ThisProperties) &gt; -1 Then
+ _PropertiesList = _ThisProperties
+ Exit Function
+ End If
+
+ vFullPropertiesList = Array( _
+ &quot;BackColor&quot; _
+ , &quot;BorderColor&quot; _
+ , &quot;BorderStyle&quot; _
+ , &quot;Cancel&quot; _
+ , &quot;Caption&quot; _
+ , &quot;ControlSource&quot; _
+ , &quot;ControlTipText&quot; _
+ , &quot;ControlType&quot; _
+ , &quot;Default&quot; _
+ , &quot;DefaultValue&quot; _
+ , &quot;Enabled&quot; _
+ , &quot;FontBold&quot; _
+ , &quot;FontItalic&quot; _
+ , &quot;FontName&quot; _
+ , &quot;FontSize&quot; _
+ , &quot;FontUnderline&quot; _
+ , &quot;FontWeight&quot; _
+ , &quot;ForeColor&quot; _
+ , &quot;Form&quot; _
+ , &quot;Format&quot; _
+ , &quot;ItemData&quot; _
+ , &quot;LinkChildFields&quot; _
+ , &quot;LinkMasterFields&quot; _
+ , &quot;ListCount&quot; _
+ , &quot;ListIndex&quot; _
+ , &quot;Locked&quot; _
+ , &quot;MultiSelect&quot; _
+ , &quot;Name&quot; _
+ , &quot;ObjectType&quot; _
+ , &quot;OnActionPerformed&quot; _
+ , &quot;OnAdjustmentValueChanged&quot; _
+ , &quot;OnApproveAction&quot; _
+ , &quot;OnApproveReset&quot; _
+ , &quot;OnApproveUpdate&quot; _
+ , &quot;OnChanged&quot; _
+ , &quot;OnErrorOccurred&quot; _
+ , &quot;OnFocusGained&quot; _
+ , &quot;OnFocusLost&quot; _
+ , &quot;OnItemStateChanged&quot; _
+ , &quot;OnKeyPressed&quot; _
+ , &quot;OnKeyReleased&quot; _
+ , &quot;OnMouseDragged&quot; _
+ , &quot;OnMouseEntered&quot; _
+ , &quot;OnMouseExited&quot; _
+ , &quot;OnMouseMoved&quot; _
+ , &quot;OnMousePressed&quot; _
+ , &quot;OnMouseReleased&quot; _
+ , &quot;OnResetted&quot; _
+ , &quot;OnTextChanged&quot; _
+ , &quot;OnUpdated&quot; _
+ , &quot;OptionValue&quot; _
+ , &quot;Page&quot; _
+ , &quot;Parent&quot; _
+ , &quot;Picture&quot; _
+ , &quot;Required&quot; _
+ , &quot;RowSource&quot; _
+ , &quot;RowSourceType&quot; _
+ , &quot;Selected&quot; _
+ , &quot;SelLength&quot; _
+ , &quot;SelStart&quot; _
+ , &quot;Seltext&quot; _
+ , &quot;SpecialEffect&quot; _
+ , &quot;SubType&quot; _
+ , &quot;TabIndex&quot; _
+ , &quot;TabStop&quot; _
+ , &quot;Tag&quot; _
+ , &quot;Text&quot; _
+ , &quot;TextAlign&quot; _
+ , &quot;TripleState&quot; _
+ , &quot;Value&quot; _
+ , &quot;Visible&quot; _
+ )
+Dim vPropertiesMatrix(25) As Variant
+ Select Case _ParentType
+ Case CTLPARENTISFORM, CTLPARENTISSUBFORM
+ vPropertiesMatrix(acCheckBox) = Array(0,4,5,6,7,9,10,11,12,13,14,15,16,17,27,28,29,32,36,37,38,39,40,41,42,43,44,45,46,47,52,54,61,62,63,64,65,67,68,69,70)
+ vPropertiesMatrix(acComboBox) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,20,23,24,25,27,28,29,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,52,54,55,56,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acCommandButton) = Array(0,3,4,6,7,8,10,11,12,13,14,15,16,17,27,28,29,31,32,36,37,38,39,40,41,42,43,44,45,46,47,52,53,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acCurrencyField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acDateField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,19,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acFileControl) = Array(0,1,2,6,7,9,10,11,12,13,14,15,16,17,25,27,28,32,36,37,39,40,41,42,43,44,45,46,47,48,52,62,63,64,65,66,69,70)
+ vPropertiesMatrix(acFixedText) = Array(0,1,2,4,6,7,10,11,12,13,14,15,16,17,27,28,36,37,39,40,41,42,43,44,45,46,52,62,65,67,70)
+ vPropertiesMatrix(acFormattedField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,19,25,27,28,32,33,35,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acGridControl) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,27,28,32,33,35,36,37,39,40,41,42,43,44,45,46,47,49,52,62,63,64,65,70)
+ vPropertiesMatrix(acGroupBox) = Array(4,6,7,10,11,12,13,14,15,16,17,27,28,32,36,37,39,40,41,42,43,44,45,46,47,52,62,65,70)
+ vPropertiesMatrix(acHiddenControl) = Array(7,27,28,52,62,65,69,70)
+ vPropertiesMatrix(acImageButton) = Array(0,1,2,6,7,10,27,28,31,36,37,39,40,41,42,43,44,45,46,52,53,62,63,64,65,70)
+ vPropertiesMatrix(acImageControl) = Array(0,1,2,5,6,7,10,25,27,28,32,36,37,39,40,41,42,43,44,45,46,47,52,53,54,62,63,64,65,70)
+ vPropertiesMatrix(acListBox) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,20,23,24,25,26,27,28,29,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,52,54,55,56,57,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acNavigationBar) = Array(0,2,6,7,10,11,12,13,14,15,16,17,27,28,36,37,39,40,41,42,43,44,45,46,52,62,63,64,65,70)
+ vPropertiesMatrix(acNumericField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acPatternField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,58,59,60,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acRadioButton) = Array(0,4,5,6,7,9,10,11,12,13,14,15,16,17,27,28,29,32,36,37,38,39,40,41,42,43,44,45,46,47,50,52,54,61,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acScrollBar) = Array(0,1,2,6,7,10,27,28,30,32,33,36,37,39,40,41,42,43,44,45,46,47,49,52,62,63,64,65,69,70)
+ vPropertiesMatrix(acSpinButton) = Array(0,1,2,6,7,9,10,27,28,30,32,33,36,37,39,40,41,42,43,44,45,46,47,49,52,62,63,64,65,69,70)
+ vPropertiesMatrix(0) = Array(7,18,21,22,27,28,52,62)
+ vPropertiesMatrix(acTextField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,25,27,28,32,33,34,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,58,59,60,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acTimeField) = Array(0,1,2,5,6,7,9,10,11,12,13,14,15,16,17,19,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,63,64,65,66,67,69,70)
+ Case CTLPARENTISGROUP
+ &apos; To be duplicated from above !!!
+ vPropertiesMatrix(acRadioButton) = Array(0,4,5,6,7,9,10,11,12,13,14,15,16,17,27,28,29,32,36,37,38,39,40,41,42,43,44,45,46,47,50,52,54,61,62,63,64,65,67,69,70)
+ Case CTLPARENTISGRID
+ vPropertiesMatrix(acCheckBox) = Array(4,5,6,7,9,10,27,28,29,32,36,37,38,39,40,41,42,43,44,45,46,47,52,54,61,62,65,67,68,69)
+ vPropertiesMatrix(acComboBox) = Array(4,5,6,7,9,10,20,23,24,25,27,28,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,52,54,55,56,62,65,66,67,69)
+ vPropertiesMatrix(acCurrencyField) = Array(4,5,6,7,9,10,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,65,67,69)
+ vPropertiesMatrix(acDateField) = Array(4,5,6,7,9,10,19,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,65,66,67,69)
+ vPropertiesMatrix(acFormattedField) = Array(4,5,6,7,9,10,19,25,27,28,32,33,35,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,65,66,67,69)
+ vPropertiesMatrix(acListBox) = Array(4,5,6,7,9,10,20,23,24,25,26,27,28,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,49,52,54,55,56,57,62,65,67,69)
+ vPropertiesMatrix(acNumericField) = Array(4,5,6,7,9,10,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,65,67,69)
+ vPropertiesMatrix(acPatternField) = Array(4,5,6,7,9,10,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,58,59,60,62,65,66,67,69)
+ vPropertiesMatrix(acTextField) = Array(4,5,6,7,9,10,25,27,28,32,33,34,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,58,59,60,62,65,66,67,69)
+ vPropertiesMatrix(acTimeField) = Array(4,5,6,7,9,10,19,25,27,28,32,33,36,37,39,40,41,42,43,44,45,46,47,48,49,52,54,62,65,66,67,69)
+ Case CTLPARENTISDIALOG
+ vPropertiesMatrix(acCheckBox) = Array(0,4,6,7,10,11,12,13,14,15,16,17,27,28,29,36,37,38,39,40,41,42,43,44,45,46,51,52,61,62,63,64,65,67,68,69,70)
+ vPropertiesMatrix(acComboBox) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,20,23,24,25,27,28,29,36,37,38,39,40,41,42,43,44,45,46,48,51,52,55,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acCommandButton) = Array(0,3,4,6,7,8,10,11,12,13,14,15,16,17,27,28,29,36,37,38,39,40,41,42,43,44,45,46,51,52,53,62,63,64,65,67,70)
+ vPropertiesMatrix(acCurrencyField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acDateField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,19,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acFileControl) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acFixedLine) = Array(0,4,6,7,10,11,12,13,14,15,16,17,27,28,36,37,39,40,41,42,43,44,45,46,51,52,62,63,65,70)
+ vPropertiesMatrix(acFixedText) = Array(0,1,2,4,6,7,10,11,12,13,14,15,16,17,27,28,36,37,39,40,41,42,43,44,45,46,51,52,62,63,64,65,67,70)
+ vPropertiesMatrix(acFormattedField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,19,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acGroupBox) = Array(4,6,7,10,11,12,13,14,15,16,17,27,28,36,37,39,40,41,42,43,44,45,46,51,52,62,63,65,70)
+ vPropertiesMatrix(acImageControl) = Array(0,1,2,6,7,10,27,28,36,37,39,40,41,42,43,44,45,46,51,52,53,62,63,64,65,70)
+ vPropertiesMatrix(acListBox) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,20,23,24,25,26,27,28,29,36,37,38,39,40,41,42,43,44,45,46,51,52,55,57,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acNavigationBar) = Array(36,37,39,40,41,42,43,44,45,46)
+ vPropertiesMatrix(acNumericField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acPatternField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,58,59,60,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acProgressBar) = Array(0,1,2,6,7,10,27,28,36,37,39,40,41,42,43,44,45,46,51,52,62,63,65,69,70)
+ vPropertiesMatrix(acRadioButton) = Array(0,4,6,7,10,11,12,13,14,15,16,17,27,28,29,36,37,38,39,40,41,42,43,44,45,46,50,51,52,61,62,63,64,65,67,69,70)
+ vPropertiesMatrix(acScrollBar) = Array(0,1,2,6,7,10,27,28,30,36,37,39,40,41,42,43,44,45,46,51,52,62,63,64,65,69,70)
+ vPropertiesMatrix(acTextField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,58,59,60,62,63,64,65,66,67,69,70)
+ vPropertiesMatrix(acTimeField) = Array(0,1,2,6,7,10,11,12,13,14,15,16,17,19,25,27,28,36,37,39,40,41,42,43,44,45,46,48,51,52,62,63,64,65,66,67,69,70)
+ End Select
+
+Dim i As Integer, iIndex As Integer
+ If _ControlType = acSubForm Then iIndex = 0 Else iIndex = _ControlType
+ If IsEmpty(vPropertiesMatrix(iIndex)) Then
+ _ThisProperties = Array()
+ Else
+ ReDim _ThisProperties(0 To UBound(vPropertiesMatrix(iIndex)))
+ For i = 0 To UBound(_ThisProperties)
+ _ThisProperties(i) = vFullPropertiesList(vPropertiesMatrix(iIndex)(i))
+ Next i
+ End If
+
+ _PropertiesList = _ThisProperties()
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return property value of the psProperty property name
+
+Dim iArg As Integer
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Control.get&quot; &amp; psProperty)
+ _PropertyGet = EMPTY
+
+&apos;Check Index argument
+Dim iArgNr As Integer
+ If Not IsMissing(pvIndex) Then
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;getProperty&quot;) : iArgNr = 3
+ Case UCase(&quot;Control.getProperty&quot;) : iArgNr = 2
+ Case UCase(&quot;Control.get&quot; &amp; psProperty) : iArgNr = 1
+ End Select
+ If Not Utils._CheckArgument(pvIndex, iArgNr, Utils._AddNumeric()) Then Goto Exit_Function
+ End If
+
+Dim vDefaultValue As Variant, oDefaultValue As Object, vValue As Variant, oValue As Object, iIndex As Integer
+Dim lListIndex As Long, i As Integer, j As Integer, vCurrentValue As Variant, lListCount As Long
+Dim vListboxValue As Variant, vListSource, bSelected() As Boolean, bListboxBound As Boolean
+Dim vGet As Variant, vDate As Variant
+Dim ofSubForm As Object
+Dim vFormats() As Variant
+Dim vSelection As Variant, sSelectedText As String
+Dim oControlEvents As Object, sEventName As String
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;BackColor&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;BackgroundColor&quot;) Then _PropertyGet = ControlModel.BackgroundColor
+ Case UCase(&quot;BorderColor&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;BorderColor&quot;) Then _PropertyGet = ControlModel.BorderColor
+ Case UCase(&quot;BorderStyle&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Border&quot;) Then _PropertyGet = ControlModel.Border
+ Case UCase(&quot;Cancel&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;PushButtonType&quot;) Then _PropertyGet = ( ControlModel.PushButtonType = com.sun.star.awt.PushButtonType.CANCEL )
+ Case UCase(&quot;Caption&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Label&quot;) Then _PropertyGet = ControlModel.Label
+ Case UCase(&quot;ControlSource&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;DataField&quot;) Then _PropertyGet = ControlModel.DataField
+ Case UCase(&quot;ControlTipText&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;HelpText&quot;) Then _PropertyGet = ControlModel.HelpText
+ Case UCase(&quot;ControlType&quot;)
+ _PropertyGet = _ControlType
+ Case UCase(&quot;Default&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultButton&quot;) Then _PropertyGet = ControlModel.DefaultButton
+ Case UCase(&quot;DefaultValue&quot;)
+ Select Case _SubType
+ Case CTLCHECKBOX, CTLRADIOBUTTON
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultState&quot;) Then _PropertyGet = ControlModel.DefaultState
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultText&quot;) Then _PropertyGet = ControlModel.DefaultText
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultValue&quot;) Then _PropertyGet = ControlModel.DefaultValue
+ Case CTLDATEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultDate&quot;) Then
+ Select Case VarType(ControlModel.DefaultDate)
+ Case vbLong &apos; AOO and LO &lt;= 4.1
+ vDefaultValue = ControlModel.DefaultDate
+ _PropertyGet = DateSerial(Left(vDefaultValue, 4), Mid(vDefaultValue, 5, 2), Right(vDefaultValue, 2))
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Date
+ Set oDefaultValue = ControlModel.DefaultDate
+ _PropertyGet = DateSerial(oDefaultValue.Year,oDefaultValue.Month, oDefaultValue.Day)
+ Case vbEmpty
+ End Select
+ End If
+ Case CTLFORMATTEDFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;EffectiveDefault&quot;) Then _PropertyGet = ControlModel.EffectiveDefault
+ Case CTLLISTBOX
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultSelection&quot;) And Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then
+ vDefaultValue = ControlModel.DefaultSelection
+ If IsArray(vDefaultValue) Then
+ If UBound(vDefaultValue) &gt;= LBound(vDefaultValue) Then &apos; Is array initialized ?
+ iIndex = UBound(ControlModel.StringItemList)
+ If vDefaultValue(0) &gt;= 0 And vDefaultValue(0) &lt;= iIndex Then _PropertyGet = ControlModel.StringItemList(vDefaultValue(0))
+ &apos; Only first default value is considered
+ End If
+ End If
+ End If
+ Case CTLSPINBUTTON
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultSpinValue&quot;) Then _PropertyGet = ControlModel.DefaultSpinValue
+ Case CTLTIMEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;DefaultTime&quot;) Then
+ Select Case VarType(ControlModel.DefaultTime)
+ Case vbLong &apos; AOO and LO &lt;= 4.1
+ _PropertyGet = ControlModel.DefaultTime
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Time
+ Set oDefaultValue = ControlModel.DefaultTime
+ _PropertyGet = TimeSerial(oDefaultValue.Hours, oDefaultValue.Minutes, oDefaultValue.Seconds)
+ Case vbEmpty
+ End Select
+ End If
+ Case Else
+ Goto Trace_Error
+ End Select
+ Case UCase(&quot;Enabled&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Enabled&quot;) Then _PropertyGet = ControlModel.Enabled
+ Case UCase(&quot;FontBold&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;FontWeight&quot;) Then _PropertyGet = ( ControlModel.FontWeight &gt;= com.sun.star.awt.FontWeight.BOLD )
+ Case UCase(&quot;FontItalic&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;FontSlant&quot;) Then _PropertyGet = ( ControlModel.FontSlant = com.sun.star.awt.FontSlant.ITALIC )
+ Case UCase(&quot;FontName&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;FontName&quot;) Then _PropertyGet = ControlModel.FontName
+ Case UCase(&quot;FontSize&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;FontHeight&quot;) Then _PropertyGet = ControlModel.FontHeight
+ Case UCase(&quot;FontUnderline&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;FontUnderline&quot;) Then _PropertyGet = _
+ Not ( ControlModel.FontUnderline = com.sun.star.awt.FontUnderline.NONE _
+ Or ControlModel.FontUnderline = com.sun.star.awt.FontUnderline.DONTKNOW )
+ Case UCase(&quot;FontWeight&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;FontWeight&quot;) Then _PropertyGet = ControlModel.FontWeight
+ Case UCase(&quot;ForeColor&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;TextColor&quot;) Then _PropertyGet = ControlModel.TextColor
+ Case UCase(&quot;Form&quot;)
+ Set ofSubForm = New SubForm &apos; Start building the SUBFORM object
+ With ofSubForm
+ Set ._This = ofSubForm
+ Set .DatabaseForm = ControlModel
+ ._Name = _Name
+ ._Shortcut = _Shortcut &amp; &quot;.Form&quot;
+ ._MainForm = _MainForm
+ .ParentComponent = _FormComponent
+ ._DocEntry = _DocEntry
+ ._DbEntry = _DbEntry
+ ._OrderBy = ControlModel.Order
+ End With
+ set _PropertyGet = ofSubForm
+ Case UCase(&quot;Format&quot;)
+ vFormats = _Formats(_Subtype)
+ Select Case _SubType
+ Case CTLDATEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;DateFormat&quot;) Then
+ If ControlModel.DateFormat &lt;= UBound(vFormats) Then _PropertyGet = vFormats(ControlModel.DateFormat)
+ End If
+ Case CTLTIMEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;TimeFormat&quot;) Then
+ If ControlModel.TimeFormat &lt;= UBound(vFormats) Then _PropertyGet = vFormats(ControlModel.TimeFormat)
+ End If
+ Case Else
+ If Utils._hasUNOProperty(ControlModel, &quot;FormatKey&quot;) Then
+ If Utils._hasUNOProperty(ControlModel, &quot;FormatsSupplier&quot;) Then
+ _PropertyGet = ControlModel.FormatsSupplier.getNumberFormats.getByKey(ControlModel.FormatKey).FormatString
+ End If
+ End If
+ End Select
+ Case UCase(&quot;ItemData&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then
+ If IsMissing(pvIndex) Then
+ _PropertyGet = ControlModel.StringItemList
+ Else
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(ControlModel.StringItemList) Then Goto Trace_Error_Index
+ _PropertyGet = ControlModel.StringItemList(pvIndex)
+ End If
+ End If
+ Case UCase(&quot;ListCount&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then _PropertyGet = UBound(ControlModel.StringItemList) + 1
+ Case UCase(&quot;ListIndex&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then
+ lListIndex = -1 &apos; Either Multiple selections or no selection at all
+ Select Case _SubType
+ Case CTLCOMBOBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Then Goto Trace_Error
+ iIndex = 0
+ If ControlModel.Text &lt;&gt; &quot;&quot; Then
+ For j = 0 To UBound(ControlModel.StringItemList)
+ If ControlModel.StringItemList(j) = ControlModel.Text Then
+ lListIndex = j
+ iIndex = iIndex + 1
+ End If
+ Next j
+ If iIndex &lt;&gt; 1 Then lListIndex = -1 &apos; Multiselection or synonyms rejected
+ End If
+ Case CTLLISTBOX &apos; No mean found to access bound column !! See mail Lionel 10/5/2013 for improvement
+ If Not Utils._hasUNOProperty(ControlModel, &quot;SelectedItems&quot;) Then Goto Trace_Error
+ If UBound(ControlModel.SelectedItems) &gt; 0 Then &apos; Several items selected
+ Else &apos; Mono selection
+ If _ParentType &lt;&gt; CTLPARENTISDIALOG Then &apos; getCurrentValue not found in dialog listboxes ??
+ vCurrentValue = ControlModel.getCurrentValue() &apos; Space or uninitialized array if no selection at all
+ If IsArray(vCurrentValue) Then &apos; Is an array if MultiSelect
+ vListboxValue = &quot;&quot;
+ If UBound(vCurrentValue) = 0 Then vListboxValue = vCurrentValue(0)
+ Else
+ vListboxValue = vCurrentValue
+ End If
+ If vListboxValue &lt;&gt; &quot;&quot; Then &apos; Speed up search PM Pastim 12/02/2013
+ If Ubound(ControlModel.SelectedItems) &gt;= 0 Then lListIndex = Controlmodel.Selecteditems(0)
+ End If
+ Else
+ If Ubound(ControlModel.SelectedItems) &gt;= 0 Then lListIndex = Controlmodel.Selecteditems(0)
+ End If
+ End If
+ End Select
+ _PropertyGet = lListIndex
+ End If
+ Case UCase(&quot;Locked&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;ReadOnly&quot;) Then _PropertyGet = ControlModel.ReadOnly
+ Case UCase(&quot;MultiSelect&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;MultiSelection&quot;) Then
+ _PropertyGet = ControlModel.MultiSelection &apos; Boolean in OO, Integer (0, 1 or 2) in VBA
+ ElseIf Utils._hasUNOProperty(ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then &apos; Not documented: only for GridControls !? Changed in OO &gt;= 3,3 !?
+ _PropertyGet = ControlModel.MultiSelectionSimpleMode
+ Else
+ _PropertyGet = False
+ End If
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;OnActionPerformed&quot;), UCase(&quot;OnAdjustmentValueChanged&quot;), UCase(&quot;OnApproveAction&quot;), UCase(&quot;OnApproveReset&quot;) _
+ , UCase(&quot;OnApproveUpdate&quot;), UCase(&quot;OnChanged&quot;), UCase(&quot;OnErrorOccurred&quot;), UCase(&quot;OnFocusGained&quot;) _
+ , UCase(&quot;OnFocusLost&quot;), UCase(&quot;OnItemStateChanged&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnTextChanged&quot;) _
+ , UCase(&quot;OnUpdated&quot;)
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ Set oControlEvents = ControlModel.getEvents()
+ sEventName = &quot;com.sun.star.awt.&quot; &amp; _GetListener(psProperty) &amp; &quot;::&quot; &amp; Utils._GetEventName(psProperty)
+ If oControlEvents.hasByName(sEventName) Then
+ _PropertyGet = oControlEvents.getByName(sEventName).ScriptCode
+ Else
+ _PropertyGet = &quot;&quot;
+ End If
+ Case Else
+ _PropertyGet = Utils._GetEventScriptCode(ControlModel, psProperty, _Name)
+ End Select
+ Case UCase(&quot;OptionValue&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;RefValue&quot;) Then
+ If ControlModel.RefValue &lt;&gt; &quot;&quot; Then
+ _PropertyGet = ControlModel.RefValue
+ ElseIf Utils._hasUNOProperty(ControlModel, &quot;Label&quot;) Then
+ _PropertyGet = ControlModel.Label
+ End If
+ End If
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Page&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Step&quot;) Then _PropertyGet = ControlModel.Step
+ Case UCase(&quot;Parent&quot;)
+ Set _PropertyGet = _Parent
+ Case UCase(&quot;Picture&quot;)
+ _PropertyGet = ConvertToUrl(ControlModel.ImageURL)
+ Case UCase(&quot;Required&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;InputRequired&quot;) Then _PropertyGet = ControlModel.InputRequired
+ Case UCase(&quot;RowSource&quot;)
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ If Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then
+ If IsArray(ControlModel.StringItemList) Then vListSource = ControlModel.StringItemList Else vListSource = Array(ControlModel.StringItemList)
+ _PropertyGet = Join(vListSource, &quot;;&quot;)
+ End If
+ Case Else
+ If Utils._hasUNOProperty(ControlModel, &quot;ListSource&quot;) Then
+ Select Case ControlModel.ListSourceType
+ Case com.sun.star.form.ListSourceType.VALUELIST _
+ , com.sun.star.form.ListSourceType.TABLEFIELDS
+ If IsArray(ControlModel.StringItemList) Then vListSource = ControlModel.StringItemList Else vListSource = Array(ControlModel.StringItemList)
+ Case com.sun.star.form.ListSourceType.TABLE _
+ , com.sun.star.form.ListSourceType.QUERY _
+ , com.sun.star.form.ListSourceType.SQL _
+ , com.sun.star.form.ListSourceType.SQLPASSTHROUGH
+ If IsArray(ControlModel.ListSource) Then vListSource = ControlModel.ListSource Else vListSource = Array(ControlModel.ListSource)
+ End Select
+ _PropertyGet = Join(vListSource, &quot;;&quot;)
+ End If
+ End Select
+ Case UCase(&quot;RowSourceType&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;ListSourceType&quot;) Then _PropertyGet = ControlModel.ListSourceType
+ Case UCase(&quot;Selected&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then
+ lListIndex = UBound(ControlModel.StringItemList)
+ If Not IsMissing(pvIndex) Then
+ If pvIndex &lt; 0 Or pvIndex &gt; lListIndex Then Goto Trace_Error_Index
+ End If
+ If lListIndex &lt; 0 Then &apos; Do nothing if listbox empty
+ _PropertyGet = Array()
+ Else
+ Redim bSelected(0 To lListIndex)
+ For j = 0 To lListIndex
+ bSelected(j) = False
+ Next j
+ For j = 0 To UBound(ControlModel.SelectedItems)
+ iIndex = ControlModel.SelectedItems(j)
+ If iIndex &gt;= 0 And iIndex &lt;= lListIndex Then bSelected(iIndex) = True
+ Next j
+ If IsMissing(pvIndex) Then _PropertyGet = bSelected Else _PropertyGet = bSelected(pvIndex)
+ End If
+ End If
+ Case UCase(&quot;SelLength&quot;)
+ If Utils._hasUNOProperty(ControlView, &quot;Selection&quot;) Then
+ vSelection = ControlView.getSelection()
+ If vSelection.Max &gt;= vSelection.Min Then
+ _PropertyGet = vSelection.Max - vSelection.Min
+ Else
+ _PropertyGet = 0 &apos; probably control does not have focus
+ End If
+ Else
+ _PropertyGet = 0
+ End If
+ Case UCase(&quot;SelStart&quot;)
+ If Utils._hasUNOProperty(ControlView, &quot;Selection&quot;) Then
+ vSelection = ControlView.getSelection()
+ If vSelection.Max &gt;= vSelection.Min Then
+ _PropertyGet = vSelection.Min + 1
+ Else
+ _PropertyGet = 1 &apos; probably control does not have focus
+ End If
+ Else
+ _PropertyGet = 1
+ End If
+ Case UCase(&quot;SelText&quot;)
+ If Utils._hasUNOProperty(ControlView, &quot;SelectedText&quot;) Then
+ _PropertyGet = ControlView.getSelectedText()
+ Else
+ _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;SpecialEffect&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;VisualEffect&quot;) Then _PropertyGet = ControlModel.VisualEffect
+ Case UCase(&quot;SubType&quot;)
+ _PropertyGet = _SubType
+ Case UCase(&quot;TabIndex&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;TabIndex&quot;) Then _PropertyGet = ControlModel.TabIndex
+ Case UCase(&quot;TabStop&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Tabstop&quot;) Then _PropertyGet = ControlModel.Tabstop
+ Case UCase(&quot;Tag&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Tag&quot;) Then _PropertyGet = ControlModel.Tag
+ Case UCase(&quot;Text&quot;)
+ Select Case _SubType
+ Case CTLDATEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Date&quot;) Then
+ If Utils._hasUNOProperty(ControlModel, &quot;FormatKey&quot;) Then
+ If Utils._hasUNOProperty(ControlModel, &quot;FormatsSupplier&quot;) Then
+ Select Case VarType(ControlModel.Date)
+ Case vbLong &apos; AOO and LO &lt;= 4.1
+ vDate = DateSerial(Left(ControlModel.Date, 4), Mid(ControlModel.Date, 5, 2), Right(ControlModel.Date, 2))
+ Case vbObject &apos; LO &gt;= 4.2
+ vDate = DateSerial(ControlModel.Date.Year, ControlModel.Date.Month, ControlModel.Date.Day)
+ Case vbEmpty
+ End Select
+ _PropertyGet = Format(vDate, ControlModel.FormatsSupplier.getNumberFormats.getByKey(ControlModel.FormatKey).FormatString)
+ End If
+ End If
+ End If
+ Case CTLTIMEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Then
+ Select Case VarType(ControlModel.Time)
+ Case vbLong &apos; AOO and LO &lt;= 4.1
+ _PropertyGet = Format(ControlModel.Time, &quot;HH:MM:SS&quot;)
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Time
+ Set oValue = ControlModel.Time
+ _PropertyGet = Format(TimeSerial(oValue.Hours, oValue.Minutes, oValue.Seconds), &quot;HH:MM:SS&quot;)
+ Case vbEmpty
+ End Select
+ End If
+ Case Else
+ If Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Then _PropertyGet = ControlModel.Text
+ End Select
+ Case UCase(&quot;TextAlign&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;Tag&quot;) Then _PropertyGet = ControlModel.Tag
+ Case UCase(&quot;TripleState&quot;)
+ If Utils._hasUNOProperty(ControlModel, &quot;TriState&quot;) Then _PropertyGet = ControlModel.TriState
+ Case UCase(&quot;Value&quot;)
+ Select Case _SubType
+ Case CTLCHECKBOX
+ If Utils._hasUNOProperty(ControlModel, &quot;State&quot;) Then vGet = ControlModel.State
+ Case CTLCOMMANDBUTTON
+ vGet = False
+ If Utils._hasUNOProperty(ControlModel, &quot;Toggle&quot;) Then
+ If Utils._hasUNOProperty(ControlModel, &quot;State&quot;) Then vGet = ( ControlModel.State = 1 )
+ End If
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Then vGet = ControlModel.Text
+ Case CTLCURRENCYFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Value&quot;) Then vGet = ControlModel.Value
+ Case CTLDATEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Date&quot;) Then
+ Select Case VarType(ControlModel.Date)
+ Case vbLong &apos; AOO and LO &lt;= 4.1
+ vValue = ControlModel.Date
+ vGet = DateSerial(Left(vValue, 4), Mid(vValue, 5, 2), Right(vValue, 2))
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Date
+ Set oValue = ControlModel.Date
+ vGet = DateSerial(oValue.Year, oValue.Month, oValue.Day)
+ Case vbEmpty
+ End Select
+ End If
+ Case CTLFORMATTEDFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;EffectiveValue&quot;) Then vGet = ControlModel.EffectiveValue
+ Case CTLHIDDENCONTROL
+ If Utils._hasUNOProperty(ControlModel, &quot;HiddenValue&quot;) Then vGet = ControlModel.HiddenValue
+ Case CTLLISTBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then Goto Trace_Error
+ If Not Utils._hasUNOProperty(ControlModel, &quot;SelectedItems&quot;) Then Goto Trace_Error
+ If UBound(ControlModel.SelectedItems) &gt; 0 Then &apos; Several items selected
+ vGet = EMPTY &apos; Listbox has no value, only an array of Selected flags to identify values
+ Else &apos; Mono selection
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ If Ubound(ControlModel.SelectedItems) &gt;= 0 Then
+ lListIndex = Controlmodel.Selecteditems(0)
+ If lListIndex &gt; -1 And lListIndex &lt;= UBound(ControlModel.StringItemList) Then
+ vGet = ControlModel.StringItemList(lListIndex)
+ Else
+ vGet = EMPTY
+ End If
+ End If
+ Case Else
+ &apos;getCurrentValue does not return any significant value anymore
+ &apos; Speed up getting value PM PASTIM 12/02/2013
+ If Ubound(ControlModel.SelectedItems) &gt;= 0 Then lListIndex = Controlmodel.Selecteditems(0) Else lListIndex = -1
+ &apos; If listbox has hidden column = real bound field, then explore ValueItemList
+ If _ListboxBound() Then
+ If lListIndex &gt; -1 Then vGet = ControlModel.ValueItemList(lListIndex) &apos; PASTIM
+ Else
+ If lListIndex &gt; -1 Then vGet = ControlModel.getItemText(lListIndex)
+ End If
+ End Select
+ End If
+ Case CTLNUMERICFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Value&quot;) Then vGet = ControlModel.Value
+ Case CTLPROGRESSBAR
+ If Utils._hasUNOProperty(ControlModel, &quot;ProgressValue&quot;) Then vGet = ControlModel.ProgressValue
+ Case CTLSCROLLBAR
+ If Utils._hasUNOProperty(ControlModel, &quot;ScrollValue&quot;) Then vGet = ControlModel.ScrollValue
+ Case CTLSPINBUTTON
+ If Utils._hasUNOProperty(ControlModel, &quot;SpinValue&quot;) Then vGet = ControlModel.SpinValue
+ Case CTLTIMEFIELD
+ If Utils._hasUNOProperty(ControlModel, &quot;Time&quot;) Then
+ Select Case VarType(ControlModel.Time)
+ Case vbLong &apos; AOO and LO &lt;= 4.1
+ vGet = ControlModel.Time
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Time
+ Set oValue = ControlModel.Time
+ vGet = TimeSerial(oValue.Hours, oValue.Minutes, oValue.Seconds)
+ Case vbEmpty
+ End Select
+ End If
+ Case Else
+ End Select
+ If _SubType &lt;&gt; CTLLISTBOX Then &apos; Give getCurrentValue an additional try
+ If IsEmpty(vGet) And Utils._hasUNOMethod(ControlModel, &quot;getCurrentValue&quot;) Then vGet = ControlModel.getCurrentValue()
+ End If
+ _PropertyGet = vGet
+ Case UCase(&quot;Visible&quot;)
+ Select Case _SubType
+ Case CTLHIDDENCONTROL
+ _PropertyGet = False
+ Case Else
+ If Utils._hasUNOMethod(ControlView, &quot;isVisible&quot;) Then _PropertyGet = CBool(ControlView.isVisible())
+ End Select
+ Case Else
+ Goto Trace_Error
+ End Select
+
+ If IsEmpty(_PropertyGet) Then TraceError(TRACEINFO, ERRPROPERTYINIT, Utils._CalledSub(), 0, , psProperty)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Control.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRINDEXVALUE, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Control._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant, ByVal Optional pvIndex As Variant) As Boolean
+&apos; Return True if property setting OK
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Control.set&quot; &amp; psProperty)
+ _PropertySet = True
+
+&apos;Check Index argument
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ End If
+&apos;Execute
+Dim iArgNr As Integer, vButton As Variant, i As Integer
+Dim odbDatabase As Object, vNames() As Variant, bFound As Boolean, sName As String
+Dim bMultiSelect As Boolean, iCount As Integer, iSelectedItems() As Integer, lListCount As Long, bSelected() As Boolean
+Dim vItemList() As Variant, vFormats() As Variant
+Dim oStruct As Object, sValue As String
+Dim vSelection As Variant, sText As String, lStart As long
+Dim oControlEvents As Object, sListener As String, sEvent As String, sEventName As String, oEvent As Object
+
+ _PropertySet = True
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;setProperty&quot;) : iArgNr = 3
+ Case UCase(&quot;Control.setProperty&quot;) : iArgNr = 2
+ Case UCase(&quot;Control.set&quot; &amp; psProperty) : iArgNr = 1
+ End Select
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;BackColor&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;BackgroundColor&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.BackgroundColor = CLng(pvValue)
+ Case UCase(&quot;BorderColor&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;BorderColor&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.BorderColor = CLng(pvValue)
+ Case UCase(&quot;BorderStyle&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;BorderColor&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; 2 Then Goto Trace_Error_Value &apos; 0 = No border, 1 = 3D border, 2 = Normal border
+ ControlModel.Border = CLng(pvValue)
+ Case UCase(&quot;Cancel&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;PushButtonType&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then vButton = com.sun.star.awt.PushButtonType.CANCEL Else vButton = com.sun.star.awt.PushButtonType.STANDARD
+ ControlModel.PushButtonType = vButton
+ Case UCase(&quot;Caption&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Label&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.Label = pvValue
+ Case UCase(&quot;ControlTipText&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;HelpText&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.HelpText = pvValue
+ Case UCase(&quot;Default&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultButton&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ControlModel.DefaultButton = pvValue
+ Case UCase(&quot;DefaultValue&quot;)
+ Select Case _SubType
+ Case CTLDATEFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultDate&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbDate, , False) Then Goto Trace_Error_Value
+ Select Case VarType(ControlModel.DefaultDate)
+ Case vbEmpty, vbLong &apos; AOO and LO &lt;= 4.1
+ ControlModel.DefaultDate = Year(pvValue) * 10000 + Month(pvValue) * 100 + Day(pvValue)
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Date
+ ControlModel.DefaultDate.Year = Year(pvValue)
+ ControlModel.DefaultDate.Month = Month(pvValue)
+ ControlModel.DefaultDate.Day = Day(pvValue)
+ End Select
+ Case CTLLISTBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultSelection&quot;) Or Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ For i = 0 To UBound(ControlModel.StringItemList)
+ If UCase(pvValue) = UCase(ControlModel.StringItemList(i)) Then
+ ControlModel.DefaultSelection = Array(i)
+ Exit For
+ End If
+ Next i
+ Case CTLSPINBUTTON
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultSpinValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.DefaultSpinValue = pvValue
+ Case CTLCHECKBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultState&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; 2 Then Goto Trace_Error_Value &apos; 0 = Not checked 1 = Checked 2 = don&apos;t know
+ ControlModel.DefaultState = pvValue
+ Case CTLRADIOBUTTON
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultState&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; 1 Then Goto Trace_Error_Value &apos; 0 = Not checked 1 = Checked
+ ControlModel.DefaultState = pvValue
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultText&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.DefaultText = pvValue
+ Case CTLTIMEFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultTime&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &gt;= 0 And pvValue &lt;= 23595999 Then
+ Select Case VarType(ControlModel.DefaultTime)
+ Case vbEmpty, vbLong &apos; AOO and LO &lt;= 4.1
+ ControlModel.DefaultTime = pvValue
+ Case vbObject &apos; LO &gt;= 4.2 com.sun.star.Util.Time
+ ControlModel.DefaultDate.Hours = Hour(pvValue)
+ ControlModel.DefaultDate.Minutes = Minute(pvValue)
+ ControlModel.DefaultDate.Seconds = Second(pvValue)
+ End Select
+ Else Goto Trace_Error_Value
+ End If
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;DefaultValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.DefaultValue = pvValue
+ Case CTLFORMATTEDFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;EffectiveDefault&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.EffectiveDefault = pvValue &apos; Thanks, PASTIM
+ Case Else
+ Goto Trace_Error
+ End Select
+ Case UCase(&quot;Enabled&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Enabled&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ControlModel.Enabled = pvValue
+ Case UCase(&quot;FontBold&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;FontWeight&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then &apos; Iif construction does not work !
+ ControlModel.FontWeight = com.sun.star.awt.FontWeight.BOLD
+ Else
+ ControlModel.FontWeight = com.sun.star.awt.FontWeight.NORMAL
+ End If
+ Case UCase(&quot;FontItalic&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;FontSlant&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then &apos; Iif construction does not work !
+ ControlModel.FontSlant = com.sun.star.awt.FontSlant.ITALIC
+ Else
+ ControlModel.FontSlant = com.sun.star.awt.FontSlant.NONE
+ End If
+ Case UCase(&quot;FontName&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;FontName&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.FontName = pvValue
+ Case UCase(&quot;FontSize&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;FontHeight&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 1 Or pvValue &gt; 127 Then Goto Trace_Error_Value
+ ControlModel.FontHeight = pvValue
+ Case UCase(&quot;FontUnderline&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;FontUnderline&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then &apos; Iif construction does not work !
+ ControlModel.FontUnderline = com.sun.star.awt.FontUnderline.SINGLE
+ Else
+ ControlModel.FontUnderline = com.sun.star.awt.FontUnderline.NONE
+ End If
+ Case UCase(&quot;FontWeight&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;FontWeight&quot;) Then Goto Trace_Error
+ If Not Utils._IsScalar(CSng(pvValue), vbSingle, Array( _
+ com.sun.star.awt.FontWeight.THIN _
+ , com.sun.star.awt.FontWeight.ULTRALIGHT _
+ , com.sun.star.awt.FontWeight.LIGHT _
+ , com.sun.star.awt.FontWeight.SEMILIGHT _
+ , com.sun.star.awt.FontWeight.NORMAL _
+ , com.sun.star.awt.FontWeight.SEMIBOLD _
+ , com.sun.star.awt.FontWeight.BOLD _
+ , com.sun.star.awt.FontWeight.ULTRABOLD _
+ , com.sun.star.awt.FontWeight.BLACK _
+ )) Then Goto Trace_Error_Value
+ ControlModel.FontWeight = pvValue
+ Case UCase(&quot;Format&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ vFormats = _Formats(_SubType)
+ Select Case _SubType
+ Case CTLDATEFIELD, CTLTIMEFIELD
+ bFound = False
+ For i = 0 To UBound(vFormats)
+ If UCase(pvValue) = UCase(vFormats(i)) Then
+ If _SubType = CTLDATEFIELD Then
+ If Utils._hasUNOProperty(ControlModel, &quot;DateFormat&quot;) Then ControlModel.DateFormat = i Else Goto Trace_Error
+ Else
+ If Utils._hasUNOProperty(ControlModel, &quot;TimeFormat&quot;) Then ControlModel.TimeFormat = i Else Goto Trace_Error
+ End If
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_Error_Value
+ Case Else
+ Goto Trace_Error
+ End Select
+ Case UCase(&quot;ForeColor&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;TextColor&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.TextColor = CLng(pvValue)
+ Case UCase(&quot;ListIndex&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; UBound(ControlModel.StringItemList) Then Goto Trace_Error_Value
+ Select Case _SubType
+ Case CTLCOMBOBOX
+ ControlModel.Text = ControlModel.StringItemList(pvValue)
+ Case CTLLISTBOX
+ ControlModel.SelectedItems = Array(pvValue)
+ End Select
+ Case UCase(&quot;Locked&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ReadOnly&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ControlModel.ReadOnly = pvValue
+ Case UCase(&quot;MultiSelect&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;MultiSelection&quot;) And Not Utils._hasUNOProperty(ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(ControlModel, &quot;MultiSelection&quot;) Then
+ ControlModel.MultiSelection = pvValue
+ ElseIf Utils._hasUNOProperty(ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then
+ ControlModel.MultiSelectionSimpleMode = pvValue
+ End If
+ If Not pvValue Then ControlModel.SelectedItems = Array() &apos; Cancel selections when MultiSelect becomes False
+ Case UCase(&quot;OnActionPerformed&quot;), UCase(&quot;OnAdjustmentValueChanged&quot;), UCase(&quot;OnApproveAction&quot;), UCase(&quot;OnApproveReset&quot;) _
+ , UCase(&quot;OnApproveUpdate&quot;), UCase(&quot;OnChanged&quot;), UCase(&quot;OnErrorOccurred&quot;), UCase(&quot;OnFocusGained&quot;) _
+ , UCase(&quot;OnFocusLost&quot;), UCase(&quot;OnItemStateChanged&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnTextChanged&quot;) _
+ , UCase(&quot;OnUpdated&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ If Not Utils._RegisterDialogEventScript(ControlModel _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue _
+ ) Then GoTo Trace_Error
+ Case Else
+ If Not Utils._RegisterEventScript(ControlModel _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue _
+ , _Name _
+ ) Then GoTo Trace_Error
+ End Select
+ Case UCase(&quot;OptionValue&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;RefValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Label&quot;) Then
+ If pvValue = &quot;&quot; Then Goto Trace_Error_Value
+ If ControlModel.RefValue &lt;&gt; &quot;&quot; Then ControlModel.RefValue = pvValue
+ Else
+ ControlModel.Label = pvValue
+ End If
+ Case UCase(&quot;Page&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Step&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Then Goto Trace_Error_Value
+ ControlModel.Step = pvValue
+ Case UCase(&quot;Picture&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ImageURL&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.ImageURL = ConvertToUrl(pvValue)
+ Case UCase(&quot;Required&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;InputRequired&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ControlModel.InputRequired = pvValue
+ Case UCase(&quot;RowSource&quot;)
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ If Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then Goto Trace_Error
+ ControlModel.StringItemList = Split(pvValue, &quot;;&quot;)
+ Case Else
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ListSource&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ Select Case ControlModel.ListSourceType
+ Case com.sun.star.form.ListSourceType.QUERY _
+ , com.sun.star.form.ListSourceType.TABLE _
+ , com.sun.star.form.ListSourceType.TABLEFIELDS
+ Set odbDatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ If ControlModel.ListSourceType = com.sun.star.form.ListSourceType.QUERY Then vNames = odbDatabase.Connection.getQueries.GetElementNames _
+ Else vNames = odbDatabase.Connection.getTables.GetElementNames
+ bFound = False &apos; Check existence of table or query and find its correct (case-sensitive) name
+ For i = 0 To UBound(vNames)
+ If UCase(vNames(i)) = UCase(pvValue) Then
+ bFound = True
+ sName = vNames(i)
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_Error_Value
+ If _SubType = CTLCOMBOBOX Then ControlModel.ListSource = sName Else ControlModel.ListSource = Array(sName)
+ ControlModel.refresh()
+ Case com.sun.star.form.ListSourceType.SQL
+ Set odbDatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ If _SubType = CTLCOMBOBOX Then ControlModel.ListSource = odbDatabase._ReplaceSquareBrackets(pvValue) Else ControlModel.ListSource = Array(odbDatabase._ReplaceSquareBrackets(pvValue))
+ ControlModel.refresh()
+ Case com.sun.star.form.ListSourceType.VALUELIST &apos; Forbidden for COMBOBOX !
+ If _SubType = CTLCOMBOBOX Then Goto Trace_Error
+ ControlModel.ListSource = Split(pvValue, &quot;;&quot;)
+ ControlModel.StringItemList = ControlModel.ListSource
+ Case com.sun.star.form.ListSourceType.SQLPASSTHROUGH
+ If _SubType = CTLCOMBOBOX Then ControlModel.ListSource = pvValue Else ControlModel.ListSource = Array(pvValue)
+ ControlModel.refresh()
+ End Select
+ End Select
+ If _SubType = CTLLISTBOX Then ControlModel.SelectedItems = Array()
+ Case UCase(&quot;RowSourceType&quot;) &apos; Refresh done when RowSource changes, not RowSourceType
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ListSourceType&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Not Utils._IsScalar(pvValue, Utils._AddNumeric(), Array( _
+ com.sun.star.form.ListSourceType.VALUELIST _
+ , com.sun.star.form.ListSourceType.TABLE _
+ , com.sun.star.form.ListSourceType.QUERY _
+ , com.sun.star.form.ListSourceType.SQL _
+ , com.sun.star.form.ListSourceType.SQLPASSTHROUGH _
+ , com.sun.star.form.ListSourceType.TABLEFIELDS _
+ )) Then Goto Trace_Error_Value
+ ControlModel.ListSourceType = pvValue
+ Case UCase(&quot;Selected&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;SelectedItems&quot;) Then Goto Trace_Error
+ If Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) Then Goto Trace_Error
+ If Utils._hasUNOProperty(ControlModel, &quot;MultiSelection&quot;) Then
+ bMultiSelect = ControlModel.MultiSelection
+ ElseIf Utils._hasUNOProperty(ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then
+ bMultiSelect = ControlModel.MultiSelectionSimpleMode
+ Else: Goto Trace_Error
+ End If
+ lListCount = UBound(ControlModel.StringItemList) + 1
+ If IsMissing(pvIndex) Then &apos; Full boolean array passed
+ If Not IsArray(pvValue) Then Goto Trace_Error_Array
+ If LBound(pvValue) &lt;&gt; 0 Or UBound(pvValue) &lt; 0 Then Goto Trace_Error_Array
+ If Not Utils._CheckArgument(pvValue(0), iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If UBound(pvValue) &lt;&gt; lListCount - 1 Then Goto Trace_Error_Index
+ iCount = 0
+ For i = 0 To UBound(pvValue) &apos; Count True values
+ If pvValue(i) Then iCount = iCount + 1
+ Next i
+ If iCount &gt; 0 Then
+ Redim iSelectedItems(0 To iCount - 1)
+ iCount = 0
+ For i = 0 To UBound(pvValue)
+ If pvValue(i) Then
+ iSelectedItems(iCount) = i
+ iCount = iCount + 1
+ End If
+ Next i
+ ControlModel.SelectedItems = iSelectedItems &apos; iSelectedItems maps OO internals (size = # of selected items)
+ Else
+ ControlModel.SelectedItems = Array()
+ End If
+ Else &apos; Single boolean value passed
+ If Not Utils._CheckArgument(pvIndex, iArgNr + 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If pvIndex &lt; 0 Or pvIndex &gt;= lListCount Then Goto Trace_Error_Index
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ReDim bSelected(0 To lListCount - 1) &apos; bSelected maps VBA internals (size = # of displayed items)
+ If Not bMultiSelect Then &apos; Set all other values to False
+ For i = 0 To lListCount - 1
+ If i = pvIndex Then
+ bSelected(i) = pvValue &apos; All entries = False except one
+ Else
+ bSelected(i) = False
+ End If
+ Next i
+ Else
+ For i = 0 To lListCount - 1
+ bSelected(i) = False
+ Next i
+ iSelectedItems = ControlModel.SelectedItems
+ iCount = UBound(iSelectedItems)
+ For i = 0 To iCount
+ bSelected(iSelectedItems(i)) = True
+ Next i
+ bSelected(pvIndex) = pvValue
+ End If
+ iCount = 0 &apos; Rebuild SelectedItems
+ For i = 0 To lListCount - 1
+ If bSelected(i) Then iCount = iCount + 1
+ Next i
+ If iCount &gt; 0 Then
+ Redim iSelectedItems(0 To iCount - 1)
+ iCount = 0
+ For i = 0 To lListCount - 1
+ If bSelected(i) Then
+ iSelectedItems(iCount) = i
+ iCount = iCount + 1
+ End If
+ Next i
+ ControlModel.SelectedItems = iSelectedItems
+ Else
+ ControlModel.SelectedItems = Array()
+ End If
+ End If
+ Case UCase(&quot;SelLength&quot;)
+ If Not Utils._hasUNOProperty(ControlView, &quot;Selection&quot;) Then Goto trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Then Goto Trace_Error_Value
+ vSelection = ControlView.getSelection()
+ vSelection.Max = vSelection.Min + pvValue
+ ControlView.setSelection(vSelection)
+ Case UCase(&quot;SelStart&quot;)
+ If Not Utils._hasUNOProperty(ControlView, &quot;Selection&quot;) Then Goto trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 1 Or pvValue &gt; Len(ControlModel.Text) + 1 Then Goto Trace_Error_Value
+ vSelection = ControlView.getSelection()
+ vSelection.Min = pvValue - 1
+ vSelection.Max = pvValue - 1 &apos; Also reset length to 0
+ ControlView.setSelection(vSelection)
+ Case UCase(&quot;SelText&quot;)
+ If Not Utils._hasUNOProperty(ControlView, &quot;Selection&quot;) Then Goto trace_Error
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Then Goto trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If Len(pvValue) &gt; 0 Then
+ vSelection = ControlView.getSelection()
+ sText = ControlModel.Text
+ lStart = InStr(1, sText, pvValue, 0) &apos; Case sensitive !
+ If lStart &gt; 0 Then
+ vSelection.Min = lStart - 1
+ vSelection.Max = lStart + Len(pvValue) - 1
+ ControlView.setSelection(vSelection)
+ End If
+ End If
+ Case UCase(&quot;SpecialEffect&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;VisualEffect&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; 2 Then Goto Trace_Error_Value &apos; 0 = None, 1 = Look3D, 2 = Flat
+ ControlModel.VisualEffect = pvValue
+ Case UCase(&quot;TabIndex&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;TabIndex&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; -1 Then Goto Trace_Error_Value
+ ControlModel.TabIndex = pvValue
+ Case UCase(&quot;TabStop&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Tabstop&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ControlModel.Tabstop = pvValue
+ Case UCase(&quot;Tag&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Tag&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.Tag = pvValue
+ Case UCase(&quot;TextAlign&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Align&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; 2 Then Goto Trace_Error_Value &apos; 0 = Left, 1 = Center, 2 = Right
+ ControlModel.Align = pvValue
+ Case UCase(&quot;TripleState&quot;)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;TriState&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ControlModel.TriState = pvValue
+ Case UCase(&quot;Value&quot;)
+ Select Case _SubType
+ Case CTLCHECKBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;State&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(vbBoolean), , False) Then Goto Trace_Error_Value
+ If VarType(pvValue) = vbBoolean Then pvValue = Iif(pvValue, 1, 0)
+ If pvValue &lt; 0 Or pvValue &gt; 2 Then Goto Trace_Error_Value &apos; 0 = Not checked 1 = Checked 2 = don&apos;t know
+ ControlModel.State = pvValue
+ Case CTLCOMMANDBUTTON
+ If Not Utils._hasUNOProperty(ControlModel, &quot;State&quot;) Then Goto Trace_Error
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Toggle&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then ControlModel.State = 1 Else ControlModel.State = 0
+ Case CTLCOMBOBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Or Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) _
+ Then Goto Trace_Error
+ If pvValue &lt;&gt; &quot;&quot; Then
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, ControlModel.StringItemList, False) Then Goto Trace_Error_Value
+ End If
+ ControlModel.Text = pvValue
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Value&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ ControlModel.Value = pvValue
+ Case CTLDATEFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Date&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbDate, , False) Then Goto Trace_Error_Value
+ Select Case _InspectPropertyType(ControlModel, &quot;Date&quot;)
+ Case &quot;long&quot; &apos; AOO and LO &lt;= 4.1
+ &apos;ControlModel.Date = Year(pvValue) * 10000 + Month(pvValue) * 100 + Day(pvValue) &apos; Gives error in dialogs ?!?
+ ControlModel.setPropertyValue(&quot;Date&quot;, Year(pvValue) * 10000 + Month(pvValue) * 100 + Day(pvValue))
+ Case &quot;com.sun.star.util.Date&quot; &apos; LO &gt;= 4.2
+ &apos;Direct assignment of ControlModel.Date.Xxx has no effect ?!?
+ Set oStruct = CreateUnoStruct(&quot;com.sun.star.util.Date&quot;)
+ oStruct.Year = Year(pvValue)
+ oStruct.Month = Month(pvValue)
+ oStruct.Day = Day(pvValue)
+ Set ControlModel.Date = oStruct
+ End Select
+ Case CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Text&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ ControlModel.Text = pvValue
+ Case CTLFORMATTEDFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;EffectiveValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(vbString), , False) Then Goto Trace_Error_Value
+ ControlModel.EffectiveValue = pvValue
+ Case CTLHIDDENCONTROL
+ If Not Utils._hasUNOProperty(ControlModel, &quot;HiddenValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(Array(vbString, vbBoolean, vbDate)), , False) Then Goto Trace_Error_Value
+ ControlModel.HiddenValue = pvValue
+ Case CTLLISTBOX
+ If Not Utils._hasUNOProperty(ControlModel, &quot;SelectedItems&quot;) Or Not Utils._hasUNOProperty(ControlModel, &quot;StringItemList&quot;) _
+ Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(Array(vbString, vbDate)), , False) Then Goto Trace_Error_Value &apos; PASTIM
+ If IsArray(pvValue) Then Goto Trace_Error_Value &apos; Setting the value on a listbox is allowed only if single value and value in the list
+ &apos; Check ValueItemList
+ bFound = False
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG
+ vItemList = ControlModel.StringItemList
+ Case Else
+ If _ListboxBound() Then &apos; Performance improvement (PASTIM PM 9 Feb 2013)
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ValueItemList&quot;) Then Goto Trace_Error
+ vItemList = ControlModel.ValueItemList
+ Else
+ vItemList = ControlModel.StringItemList
+ End If
+ End Select
+ For i = 0 To UBound(vItemList)
+ If pvValue = vItemList(i) Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If bFound Then ControlModel.SelectedItems = Array(i) Else Goto Trace_Error_Value
+ Case CTLPROGRESSBAR
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ProgressValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(ControlModel, &quot;ProgressValueMin&quot;) Then
+ If pvValue &lt; ControlModel.ProgressValueMin Then Goto Trace_Error_Value
+ End If
+ If Utils._hasUNOProperty(ControlModel, &quot;ProgressValueMax&quot;) Then
+ If pvValue &gt; ControlModel.ProgressValueMax Then Goto Trace_Error_Value
+ End If
+ ControlModel.ProgressValue = pvValue
+ Case CTLSCROLLBAR
+ If Not Utils._hasUNOProperty(ControlModel, &quot;ScrollValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(ControlModel, &quot;ScrollValueMin&quot;) Then
+ If pvValue &lt; ControlModel.ScrollValueMin Then Goto Trace_Error_Value
+ End If
+ If Utils._hasUNOProperty(ControlModel, &quot;ScrollValueMax&quot;) Then
+ If pvValue &gt; ControlModel.ScrollValueMax Then Goto Trace_Error_Value
+ End If
+ ControlModel.ScrollValue = pvValue
+ Case CTLSPINBUTTON
+ If Not Utils._hasUNOProperty(ControlModel, &quot;SpinValue&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(ControlModel, &quot;SpinValueMin&quot;) Then
+ If pvValue &lt; ControlModel.SpinValueMin Then Goto Trace_Error_Value
+ End If
+ If Utils._hasUNOProperty(ControlModel, &quot;SpinValueMax&quot;) Then
+ If pvValue &gt; ControlModel.SpinValueMax Then Goto Trace_Error_Value
+ End If
+ ControlModel.SpinValue = pvValue
+ Case CTLTIMEFIELD
+ If Not Utils._hasUNOProperty(ControlModel, &quot;Time&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ Select Case _InspectPropertyType(ControlModel, &quot;Time&quot;)
+ Case &quot;long&quot; &apos; AOO and LO &lt;= 4.0
+ ControlModel.Time = CLng(pvValue)
+ Case &quot;com.sun.star.util.Time&quot; &apos; LO &gt;= 4.1
+ &apos;Direct assignment of ControlModel.Time.Xxx gives error ?!?
+ Set oStruct = CreateUnoStruct(&quot;com.sun.star.util.Time&quot;)
+ sValue = Right(&quot;00000000&quot; &amp; Str(CLng(pvValue)), 8)
+ oStruct.Hours = Val(Left(sValue, 2))
+ oStruct.Minutes = Val(Mid(sValue, 3, 2))
+ oStruct.Seconds = Val(Mid(sValue, 5, 2))
+ Set ControlModel.Time = oStruct
+ End Select
+ Case Else
+ Goto Trace_Error
+ End Select
+ &apos; FINAL COMMITMENT
+ If Utils._hasUNOMethod(ControlModel, &quot;commit&quot;) Then ControlModel.commit() &apos; f.i. checkboxes have no commit method ?? [PASTIM]
+ Case UCase(&quot;Visible&quot;)
+ If _SubType = CTLHIDDENCONTROL Then Goto Trace_Error &apos; Hidden remains hidden !!
+ If Not Utils._hasUNOMethod(ControlView, &quot;setVisible&quot;) Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then ControlModel.EnableVisible = True
+ ControlView.setVisible(pvValue)
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Control.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRINDEXVALUE, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Array:
+ TraceError(TRACEFATAL, ERRPROPERTYNOTARRAY, Utils._CalledSub(), 0, 1, iArgNr)
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Control._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet V1.1.0
+
+</script:module>
diff --git a/wizards/source/access2base/DataDef.xba b/wizards/source/access2base/DataDef.xba
new file mode 100644
index 000000000..8cc6b9bb1
--- /dev/null
+++ b/wizards/source/access2base/DataDef.xba
@@ -0,0 +1,598 @@
+<?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="DataDef" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be TABLEDEF or QUERYDEF
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String &apos; For tables: [[Catalog.]Schema.]Table
+Private _ParentDatabase As Object
+Private _ReadOnly As Boolean
+Private Table As Object &apos; com.sun.star.sdb.dbaccess.ODBTable
+Private CatalogName As String
+Private SchemaName As String
+Private TableName As String
+Private Query As Object &apos; com.sun.star.sdb.dbaccess.OQuery
+Private TableDescriptor As Object &apos; com.sun.star.sdb.dbaccess.ODBTable
+Private TableFieldsCount As Integer
+Private TableKeysCount As Integer
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = &quot;&quot;
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ Set _ParentDatabase = Nothing
+ _ReadOnly = False
+ Set Table = Nothing
+ CatalogName = &quot;&quot;
+ SchemaName = &quot;&quot;
+ TableName = &quot;&quot;
+ Set Query = Nothing
+ Set TableDescriptor = Nothing
+ TableFieldsCount = 0
+ TableKeysCount = 0
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SQL() As Variant
+ SQL = _PropertyGet(&quot;SQL&quot;)
+End Property &apos; SQL (get)
+
+Property Let SQL(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;SQL&quot;, pvValue)
+End Property &apos; SQL (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function pType() As Integer
+ pType = _PropertyGet(&quot;Type&quot;)
+End Function &apos; Type (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function CreateField(ByVal Optional pvFieldName As Variant _
+ , ByVal optional pvType As Variant _
+ , ByVal optional pvSize As Variant _
+ , ByVal optional pvAttributes As Variant _
+ ) As Object
+&apos;Return a Field object
+Const cstThisSub = &quot;TableDef.CreateField&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Dim oTable As Object, oNewField As Object, oKeys As Object, oPrimaryKey As Object, oColumn As Object
+Const cstMaxKeyLength = 30
+
+ CreateField = Nothing
+ If _ParentDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ If IsMissing(pvFieldName) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvFieldName, 1, vbString) Then Goto Exit_Function
+ If pvFieldName = &quot;&quot; Then Call _TraceArguments()
+ If IsMissing(pvType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvType, 1, Utils._AddNumeric( _
+ dbInteger, dbLong, dbBigInt, dbFloat, vbSingle, dbDouble _
+ , dbNumeric, dbDecimal, dbText, dbChar, dbMemo _
+ , dbDate, dbTime, dbTimeStamp _
+ , dbBinary, dbVarBinary, dbLongBinary, dbBoolean _
+ )) Then Goto Exit_Function
+ If IsMissing(pvSize) Then pvSize = 0
+ If pvSize &lt; 0 Then pvSize = 0
+ If Not Utils._CheckArgument(pvSize, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If IsMissing(pvAttributes) Then pvAttributes = 0
+ If Not Utils._CheckArgument(pvAttributes, 1, Utils._AddNumeric(), Array(0, dbAutoIncrField)) Then Goto Exit_Function
+
+ If _Type &lt;&gt; OBJTABLEDEF Then Goto Error_NotApplicable
+ If IsNull(Table) And IsNull(TableDescriptor) Then Goto Error_NotApplicable
+
+ If _ReadOnly Then Goto Error_NoUpdate
+
+ Set oNewField = New Field
+ With oNewField
+ ._This = oNewField
+ ._Name = pvFieldName
+ ._ParentName = _Name
+ ._ParentType = OBJTABLEDEF
+ If IsNull(Table) Then Set oTable = TableDescriptor Else Set oTable = Table
+ Set .Column = oTable.Columns.createDataDescriptor()
+ End With
+ With oNewField.Column
+ .Name = pvFieldName
+ Select Case pvType
+ Case dbInteger : .Type = com.sun.star.sdbc.DataType.TINYINT
+ Case dbLong : .Type = com.sun.star.sdbc.DataType.INTEGER
+ Case dbBigInt : .Type = com.sun.star.sdbc.DataType.BIGINT
+ Case dbFloat : .Type = com.sun.star.sdbc.DataType.FLOAT
+ Case dbSingle : .Type = com.sun.star.sdbc.DataType.REAL
+ Case dbDouble : .Type = com.sun.star.sdbc.DataType.DOUBLE
+ Case dbNumeric, dbCurrency : .Type = com.sun.star.sdbc.DataType.NUMERIC
+ Case dbDecimal : .Type = com.sun.star.sdbc.DataType.DECIMAL
+ Case dbText : .Type = com.sun.star.sdbc.DataType.CHAR
+ Case dbChar : .Type = com.sun.star.sdbc.DataType.VARCHAR
+ Case dbMemo : .Type = com.sun.star.sdbc.DataType.LONGVARCHAR
+ Case dbDate : .Type = com.sun.star.sdbc.DataType.DATE
+ Case dbTime : .Type = com.sun.star.sdbc.DataType.TIME
+ Case dbTimeStamp : .Type = com.sun.star.sdbc.DataType.TIMESTAMP
+ Case dbBinary : .Type = com.sun.star.sdbc.DataType.BINARY
+ Case dbVarBinary : .Type = com.sun.star.sdbc.DataType.VARBINARY
+ Case dbLongBinary : .Type = com.sun.star.sdbc.DataType.LONGVARBINARY
+ Case dbBoolean : .Type = com.sun.star.sdbc.DataType.BOOLEAN
+ End Select
+ .Precision = Int(pvSize)
+ If pvType = dbNumeric Or pvType = dbDecimal Or pvType = dbCurrency Then .Scale = Int(pvSize * 10) - Int(pvSize) * 10
+ .IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE
+ If Utils._hasUNOProperty(oNewField.Column, &quot;CatalogName&quot;) Then .CatalogName = CatalogName
+ If Utils._hasUNOProperty(oNewField.Column, &quot;SchemaName&quot;) Then .SchemaName = SchemaName
+ If Utils._hasUNOProperty(oNewField.Column, &quot;TableName&quot;) Then .TableName = TableName
+ If Not IsNull(TableDescriptor) Then TableFieldsCount = TableFieldsCount + 1
+ If pvAttributes = dbAutoIncrField Then
+ If Not IsNull(Table) Then Goto Error_Sequence &apos; Do not accept adding an AutoValue field when table exists
+ Set oKeys = oTable.Keys
+ Set oPrimaryKey = oKeys.createDataDescriptor()
+ Set oColumn = oPrimaryKey.Columns.createDataDescriptor()
+ oColumn.Name = pvFieldName
+ oColumn.CatalogName = CatalogName
+ oColumn.SchemaName = SchemaName
+ oColumn.TableName = TableName
+ oColumn.IsAutoIncrement = True
+ oColumn.IsNullable = com.sun.star.sdbc.ColumnValue.NO_NULLS
+ oPrimaryKey.Columns.appendByDescriptor(oColumn)
+ oPrimaryKey.Name = Left(&quot;PK_&quot; &amp; Join(Split(TableName, &quot; &quot;), &quot;_&quot;) &amp; &quot;_&quot; &amp; Join(Split(pvFieldName, &quot; &quot;), &quot;_&quot;), cstMaxKeyLength)
+ oPrimaryKey.Type = com.sun.star.sdbcx.KeyType.PRIMARY
+ oKeys.appendByDescriptor(oPrimaryKey)
+ .IsAutoIncrement = True
+ .IsNullable = com.sun.star.sdbc.ColumnValue.NO_NULLS
+ oColumn.dispose()
+ Else
+ .IsAutoIncrement = False
+ End If
+ End With
+ oTable.Columns.appendByDescriptor(oNewfield.Column)
+
+ Set CreateField = oNewField
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Sequence:
+ TraceError(TRACEFATAL, ERRFIELDCREATION, Utils._CalledSub(), 0, 1, pvFieldName)
+ Goto Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; CreateField V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Execute(ByVal Optional pvOptions As Variant) As Boolean
+&apos;Execute a stored query. The query must be an ACTION query.
+
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.Execute&quot;
+ Utils._SetCalledSub(cstThisSub)
+ On Local Error Goto Error_Function
+Const cstNull = -1
+ Execute = False
+ If _Type &lt;&gt; OBJQUERYDEF Then Goto Trace_Method
+ If IsMissing(pvOptions) Then
+ pvOptions = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOptions, 1, Utils._AddNumeric(), dbSQLPassThrough) Then Goto Exit_Function
+ End If
+
+ &apos;Check action query
+Dim oStatement As Object, vResult As Variant
+Dim iType As Integer, sSql As String
+ iType = pType
+ If ( (iType And DBQAction) = 0 ) And ( (iType And DBQDDL) = 0 ) Then Goto Trace_Action
+
+ &apos;Execute action query
+ Set oStatement = _ParentDatabase.Connection.createStatement()
+ sSql = Query.Command
+ If pvOptions = dbSQLPassThrough Then oStatement.EscapeProcessing = False _
+ Else oStatement.EscapeProcessing = Query.EscapeProcessing
+ On Local Error Goto SQL_Error
+ vResult = oStatement.executeUpdate(_ParentDatabase._ReplaceSquareBrackets(sSql))
+ On Local Error Goto Error_Function
+
+ Execute = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Method:
+ TraceError(TRACEFATAL, ERRMETHOD, cstThisSub, 0, , cstThisSub)
+ Goto Exit_Function
+Trace_Action:
+ TraceError(TRACEFATAL, ERRNOTACTIONQUERY, cstThisSub, 0, , _Name)
+ Goto Exit_Function
+SQL_Error:
+ TraceError(TRACEFATAL, ERRSQLSTATEMENT, Utils._CalledSub(), 0, , sSql)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; Execute V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Fields(ByVal Optional pvIndex As Variant) As Object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.Fields&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ Set Fields = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+Dim sObjects() As String, sObjectName As String, oObject As Object
+Dim i As Integer, bFound As Boolean, oFields As Object
+
+ If _Type = OBJTABLEDEF Then Set oFields = Table.getColumns() Else Set oFields = Query.getColumns()
+ sObjects = oFields.ElementNames()
+ Select Case True
+ Case IsMissing(pvIndex)
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLFIELDS
+ Set oObject._Parent = _This
+ oObject._Count = UBound(sObjects) + 1
+ Goto Exit_Function
+ Case VarType(pvIndex) = vbString
+ bFound = False
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ For i = 0 To UBound(sObjects)
+ If UCase(pvIndex) = UCase(sObjects(i)) Then
+ sObjectName = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+ Case Else &apos; pvIndex is numeric
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(sObjects) Then Goto Trace_IndexError
+ sObjectName = sObjects(pvIndex)
+ End Select
+
+ Set oObject = New Field
+ Set oObject._This = oObject
+ oObject._Name = sObjectName
+ Set oObject.Column = oFields.getByName(sObjectName)
+ oObject._ParentName = _Name
+ oObject._ParentType = _Type
+ Set oObject._ParentDatabase = _ParentDatabase
+
+Exit_Function:
+ Set Fields = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;FIELD&quot;), pvIndex))
+ Goto Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; Fields
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.getProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.hasProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenRecordset(ByVal Optional pvType As Variant, ByVal Optional pvOptions As Variant, ByVal Optional pvLockEdit As Variant) As Object
+&apos;Return a Recordset object based on current table- or querydef object
+
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.OpenRecordset&quot;
+ Utils._SetCalledSub(cstThisSub)
+Const cstNull = -1
+Dim lCommandType As Long, sCommand As String, oObject As Object,bPassThrough As Boolean
+Dim iType As Integer, iOptions As Integer, iLockEdit As Integer
+
+
+ Set oObject = Nothing
+ If VarType(pvType) = vbError Then
+ iType = cstNull
+ ElseIf IsMissing(pvType) Then
+ iType = cstNull
+ Else
+ If Not Utils._CheckArgument(pvType, 1, Utils._AddNumeric(), Array(cstNull, dbOpenForwardOnly)) Then Goto Exit_Function
+ iType = pvType
+ End If
+ If VarType(pvOptions) = vbError Then
+ iOptions = cstNull
+ ElseIf IsMissing(pvOptions) Then
+ iOptions = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOptions, 2, Utils._AddNumeric(), Array(cstNull, dbSQLPassThrough)) Then Goto Exit_Function
+ iOptions = pvOptions
+ End If
+ If VarType(pvLockEdit) = vbError Then
+ iLockEdit = cstNull
+ ElseIf IsMissing(pvLockEdit) Then
+ iLockEdit = cstNull
+ Else
+ If Not Utils._CheckArgument(pvLockEdit, 3, Utils._AddNumeric(), Array(cstNull, dbReadOnly)) Then Goto Exit_Function
+ iLockEdit = pvLockEdit
+ End If
+
+ Select Case _Type
+ Case OBJTABLEDEF
+ lCommandType = com.sun.star.sdb.CommandType.TABLE
+ sCommand = _Name
+ Case OBJQUERYDEF
+ lCommandType = com.sun.star.sdb.CommandType.QUERY
+ sCommand = _Name
+ If iOptions = dbSQLPassThrough Then bPassThrough = True Else bPassThrough = Not Query.EscapeProcessing
+ End Select
+
+ Set oObject = New Recordset
+ With oObject
+ ._CommandType = lCommandType
+ ._Command = sCommand
+ ._ParentName = _Name
+ ._ParentType = _Type
+ ._ForwardOnly = ( iType = dbOpenForwardOnly )
+ ._PassThrough = bPassThrough
+ ._ReadOnly = ( (iLockEdit = dbReadOnly) Or _ReadOnly )
+ Set ._ParentDatabase = _ParentDatabase
+ Set ._This = oObject
+ Call ._Initialize()
+ End With
+ With _ParentDatabase
+ .RecordsetMax = .RecordsetMax + 1
+ oObject._Name = Format(.RecordsetMax, &quot;0000000&quot;)
+ .RecordsetsColl.Add(oObject, UCase(oObject._Name))
+ End With
+
+ If Not ( oObject._BOF And oObject._EOF ) Then oObject.MoveFirst() &apos; Do nothing if resultset empty
+
+Exit_Function:
+ Set OpenRecordset = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Set oObject = Nothing
+ GoTo Exit_Function
+End Function &apos; OpenRecordset V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.Properties&quot;
+ Utils._SetCalledSub(cstThisSub)
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+ Set vProperty._ParentDatabase = _ParentDatabase
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.setProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(cstThisSub)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ Select Case _Type
+ Case OBJTABLEDEF
+ _PropertiesList = Array(&quot;Name&quot;, &quot;ObjectType&quot;)
+ Case OBJQUERYDEF
+ _PropertiesList = Array(&quot;Name&quot;, &quot;ObjectType&quot;, &quot;SQL&quot;, &quot;Type&quot;)
+ Case Else
+ End Select
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type)
+ Utils._SetCalledSub(cstThisSub &amp; &quot;.get&quot; &amp; psProperty)
+Dim sSql As String, sVerb As String, iType As Integer
+ _PropertyGet = EMPTY
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;SQL&quot;)
+ _PropertyGet = Query.Command
+ Case UCase(&quot;Type&quot;)
+ iType = 0
+ sSql = Utils._Trim(UCase(Query.Command))
+ sVerb = Split(sSql, &quot; &quot;)(0)
+ If sVerb = &quot;SELECT&quot; Then iType = iType + dbQSelect
+ If sVerb = &quot;SELECT&quot; And InStr(sSql, &quot; INTO &quot;) &gt; 0 _
+ Or sVerb = &quot;CREATE&quot; And InStr(sSql, &quot; TABLE &quot;) &gt; 0 _
+ Then iType = iType + dbQMakeTable
+ If sVerb = &quot;SELECT&quot; And InStr(sSql, &quot; UNION &quot;) &gt; 0 Then iType = iType + dbQSetOperation
+ If Not Query.EscapeProcessing Then iType = iType + dbQSQLPassThrough
+ If sVerb = &quot;INSERT&quot; Then iType = iType + dbQAppend
+ If sVerb = &quot;DELETE&quot; Then iType = iType + dbQDelete
+ If sVerb = &quot;UPDATE&quot; Then iType = iType + dbQUpdate
+ If sVerb = &quot;CREATE&quot; _
+ Or sVerb = &quot;ALTER&quot; _
+ Or sVerb = &quot;DROP&quot; _
+ Or sVerb = &quot;RENAME&quot; _
+ Or sVerb = &quot;TRUNCATE&quot; _
+ Then iType = iType + dbQDDL
+ &apos; dbQAction implied by dbQMakeTable, dbQAppend, dbQDelete and dbQUpdate
+ &apos; To check Type use: If (iType And dbQxxx) &lt;&gt; 0 Then ...
+ _PropertyGet = iType
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub &amp; &quot;.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub &amp; &quot;._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type)
+ Utils._SetCalledSub(cstThisSub &amp; &quot;.set&quot; &amp; psProperty)
+
+&apos;Execute
+Dim iArgNr As Integer
+
+ _PropertySet = True
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;setProperty&quot;) : iArgNr = 3
+ Case UCase(cstThisSub &amp; &quot;.setProperty&quot;) : iArgNr = 2
+ Case UCase(cstThisSub &amp; &quot;.set&quot; &amp; psProperty) : iArgNr = 1
+ End Select
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+ If _ReadOnly Then Goto Error_NoUpdate
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;SQL&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ Query.Command = pvValue
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub &amp; &quot;.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub &amp; &quot;._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module>
diff --git a/wizards/source/access2base/Database.xba b/wizards/source/access2base/Database.xba
new file mode 100644
index 000000000..347eafeb4
--- /dev/null
+++ b/wizards/source/access2base/Database.xba
@@ -0,0 +1,1889 @@
+<?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="Database" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be DATABASE
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _DbConnect As Integer &apos; DBCONNECTxxx constants
+Private Title As String
+Private Document As Object &apos; com.sun.star.comp.dba.ODatabaseDocument or SwXTextDocument or ScModelObj
+Private Connection As Object &apos; com.sun.star.sdbc.drivers.OConnectionWrapper or com.sun.star.sdbc.XConnection
+Private URL As String
+Private Location As String &apos; Different from URL for registered databases
+Private _ReadOnly As Boolean
+Private MetaData As Object &apos; interface XDatabaseMetaData
+Private _RDBMS As Integer &apos; DBMS constants
+Private _ColumnTypes() As Variant &apos; Part of Metadata.GetTypeInfo()
+Private _ColumnTypeNames() As Variant
+Private _ColumnPrecisions() As Variant
+Private _ColumnTypesReference() As Variant
+Private _ColumnTypesAlias() As Variant &apos; To what should a field whose origin is another DBMS be converted ? See DataTypes By RDBMS.ods
+Private _BinaryStream As Boolean &apos; False = binary fields must NOT be streamed f.i. via ReadAllBytes or WriteAllBytes
+Private Form As Object &apos; com.sun.star.form.XForm
+Private FormName As String
+Private RecordsetMax As Long &apos; To make unique names in Collection below (See bug # 121342)
+Private RecordsetsColl As Object &apos; Collection of active recordsets
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJDATABASE
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _DbConnect = 0
+ Title = &quot;&quot;
+ Set Document = Nothing
+ Set Connection = Nothing
+ URL = &quot;&quot;
+ _ReadOnly = False
+ Set MetaData = Nothing
+ _RDBMS = DBMS_UNKNOWN
+ _ColumnTypes = Array()
+ _ColumnTypeNames = Array()
+ _ColumnPrecisions = Array()
+ _ColumnTypesReference = Array()
+ _ColumnTypesAlias() = Array()
+ _BinaryStream = False
+ Set Form = Nothing
+ FormName = &quot;&quot;
+ RecordsetMax = 0
+ Set RecordsetsColl = New Collection
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call CloseAllRecordsets()
+ If _DbConnect &lt;&gt; DBCONNECTANY Then
+ If Not IsNull(Connection) Then
+ Connection.close()
+ Connection.dispose()
+ Set Connection = Nothing
+ End If
+ Else
+ mClose()
+ End If
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get Connect() As String
+ Connect = _PropertyGet(&quot;Connect&quot;)
+End Property &apos; Connect (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnCreate() As String
+ OnCreate = _PropertyGet(&quot;OnCreate&quot;)
+End Property &apos; OnCreate (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnFocus() As String
+ OnFocus = _PropertyGet(&quot;OnFocus&quot;)
+End Property &apos; OnFocus (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnLoad() As String
+ OnLoad = _PropertyGet(&quot;OnLoad&quot;)
+End Property &apos; OnLoad (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnLoadFinished() As String
+ OnLoadFinished = _PropertyGet(&quot;OnLoadFinished&quot;)
+End Property &apos; OnLoadFinished (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnModifyChanged() As String
+ OnModifyChanged = _PropertyGet(&quot;OnModifyChanged&quot;)
+End Property &apos; OnModifyChanged (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnNew() As String
+ OnNew = _PropertyGet(&quot;OnNew&quot;)
+End Property &apos; OnNew (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnPrepareUnload() As String
+ OnPrepareUnload = _PropertyGet(&quot;OnPrepareUnload&quot;)
+End Property &apos; OnPrepareUnload (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnPrepareViewClosing() As String
+ OnPrepareViewClosing = _PropertyGet(&quot;OnPrepareViewClosing&quot;)
+End Property &apos; OnPrepareViewClosing (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSave() As String
+ OnSave = _PropertyGet(&quot;OnSave&quot;)
+End Property &apos; OnSave (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSaveAs() As String
+ OnSaveAs = _PropertyGet(&quot;OnSaveAs&quot;)
+End Property &apos; OnSaveAs (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSaveAsDone() As String
+ OnSaveAsDone = _PropertyGet(&quot;OnSaveAsDone&quot;)
+End Property &apos; OnSaveAsDone (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSaveAsFailed() As String
+ OnSaveAsFailed = _PropertyGet(&quot;OnSaveAsFailed&quot;)
+End Property &apos; OnSaveAsFailed (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSaveDone() As String
+ OnSaveDone = _PropertyGet(&quot;OnSaveDone&quot;)
+End Property &apos; OnSaveDone (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSaveFailed() As String
+ OnSaveFailed = _PropertyGet(&quot;OnSaveFailed&quot;)
+End Property &apos; OnSaveFailed (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSubComponentClosed() As String
+ OnSubComponentClosed = _PropertyGet(&quot;OnSubComponentClosed&quot;)
+End Property &apos; OnSubComponentClosed (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnSubComponentOpened() As String
+ OnSubComponentOpened = _PropertyGet(&quot;OnSubComponentOpened&quot;)
+End Property &apos; OnSubComponentOpened (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnTitleChanged() As String
+ OnTitleChanged = _PropertyGet(&quot;OnTitleChanged&quot;)
+End Property &apos; OnTitleChanged (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUnfocus() As String
+ OnUnfocus = _PropertyGet(&quot;OnUnfocus&quot;)
+End Property &apos; OnUnfocus (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUnload() As String
+ OnUnload = _PropertyGet(&quot;OnUnload&quot;)
+End Property &apos; OnUnload (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnViewClosed() As String
+ OnViewClosed = _PropertyGet(&quot;OnViewClosed&quot;)
+End Property &apos; OnViewClosed (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnViewCreated() As String
+ OnViewCreated = _PropertyGet(&quot;OnViewCreated&quot;)
+End Property &apos; OnViewCreated (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Version() As String
+ Version = _PropertyGet(&quot;Version&quot;)
+End Property &apos; Version (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function mClose() As Variant
+&apos; Close the database
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Database.Close&quot;
+ Utils._SetCalledSub(cstThisSub)
+ mClose = False
+ If _DbConnect &lt;&gt; DBCONNECTANY Then Goto Error_NotApplicable
+
+ With Connection
+ If Utils._hasUNOMethod(Connection, &quot;flush&quot;) Then .flush
+ .close()
+ .dispose()
+ End With
+ Set Connection = Nothing
+ mClose = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ GoTo Exit_Function
+End Function &apos; (m)Close
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub CloseAllRecordsets()
+&apos; Clean all recordsets for housekeeping
+
+Dim sRecordsets() As String, i As Integer, oRecordset As Object
+ On Local Error Goto Exit_Sub
+
+ If IsNull(RecordsetsColl) Then Exit Sub
+ If RecordsetsColl.Count &lt; 1 Then Exit Sub
+ For i = 1 To RecordsetsColl.Count
+ Set oRecordset = RecordsetsColl.Item(i)
+ oRecordset.mClose(False) &apos; Do not remove entry in collection
+ Next i
+ Set RecordsetsColl = New Collection
+ RecordsetMax = 0
+
+Exit_Sub:
+ Exit Sub
+End Sub &apos; CloseAllRecordsets V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CreateQueryDef(ByVal Optional pvQueryName As Variant _
+ , ByVal Optional pvSql As Variant _
+ , ByVal Optional pvOption As Variant _
+ ) As Object
+&apos;Return a (new) QueryDef object based on SQL statement
+Const cstThisSub = &quot;Database.CreateQueryDef&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Const cstNull = -1
+Dim oQuery As Object, oQueries As Object, i As Integer, sQueryName As String
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Set CreateQueryDef = Nothing
+ If _DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ If IsMissing(pvQueryName) Then Call _TraceArguments()
+ If IsMissing(pvSql) Then Call _TraceArguments()
+ If IsMissing(pvOption) Then pvOption = cstNull
+
+ If Not Utils._CheckArgument(pvQueryName, 1, vbString) Then Goto Exit_Function
+ If pvQueryName = &quot;&quot; Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSql, 2, vbString) Then Goto Exit_Function
+ If pvSql = &quot;&quot; Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvOption, 3, Utils._AddNumeric(), Array(cstNull, dbSQLPassThrough)) Then Goto Exit_Function
+
+ If _ReadOnly Then Goto Error_NoUpdate
+
+ Set oQuery = CreateUnoService(&quot;com.sun.star.sdb.QueryDefinition&quot;)
+ oQuery.rename(pvQueryName)
+ oQuery.Command = _ReplaceSquareBrackets(pvSql)
+ oQuery.EscapeProcessing = Not ( pvOption = dbSQLPassThrough )
+
+ Set oQueries = Document.DataSource.getQueryDefinitions()
+ With oQueries
+ For i = 0 To .getCount() - 1
+ sQueryName = .getByIndex(i).Name
+ If UCase(sQueryName) = UCase(pvQueryName) Then
+ TraceError(TRACEWARNING, ERRQUERYDEFDELETED, Utils._CalledSub(), 0, False, sQueryName)
+ .removeByName(sQueryName)
+ Exit For
+ End If
+ Next i
+ .insertByName(pvQueryName, oQuery)
+ End With
+ Set CreateQueryDef = QueryDefs(pvQueryName)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; CreateQueryDef V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CreateTableDef(ByVal Optional pvTableName As Variant) As Object
+&apos;Return a (new/empty) TableDef object
+Const cstThisSub = &quot;Database.CreateTableDef&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim oTable As Object, oTables As Object, sTables() As String
+Dim i As Integer, sTableName As String, oNewTable As Object
+Dim vNameComponents() As Variant, iNames As Integer
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Set CreateTableDef = Nothing
+ If _DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ If IsMissing(pvTableName) Then Call _TraceArguments()
+
+ If Not Utils._CheckArgument(pvTableName, 1, vbString) Then Goto Exit_Function
+ If pvTableName = &quot;&quot; Then Call _TraceArguments()
+
+ If _ReadOnly Then Goto Error_NoUpdate
+
+ Set oTables = Connection.getTables
+ With oTables
+ sTables = .ElementNames()
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ For i = 0 To UBound(sTables)
+ If UCase(pvTableName) = UCase(sTables(i)) Then
+ sTableName = sTables(i)
+ TraceError(TRACEWARNING, ERRTABLEDEFDELETED, Utils._CalledSub(), 0, False, sTableName)
+ .dropByName(sTableName)
+ Exit For
+ End If
+ Next i
+ Set oNewTable = New DataDef
+ Set oNewTable._This = oNewTable
+ oNewTable._Type = OBJTABLEDEF
+ oNewTable._Name = pvTableName
+ vNameComponents = Split(pvTableName, &quot;.&quot;)
+ iNames = UBound(vNameComponents)
+ If iNames &gt;= 2 Then oNewtable.CatalogName = vNameComponents(iNames - 2) Else oNewTable.CatalogName = &quot;&quot;
+ If iNames &gt;= 1 Then oNewtable.SchemaName = vNameComponents(iNames - 1) Else oNewTable.SchemaName = &quot;&quot;
+ oNewtable.TableName = vNameComponents(iNames)
+ Set oNewTable._ParentDatabase = _This
+ Set oNewTable.TableDescriptor = .createDataDescriptor()
+ oNewTable.TableDescriptor.CatalogName = oNewTable.CatalogName
+ oNewTable.TableDescriptor.SchemaName = oNewTable.SchemaName
+ oNewTable.TableDescriptor.Name = oNewTable.TableName
+ oNewTable.TableDescriptor.Type = &quot;TABLE&quot;
+ End With
+
+ Set CreateTabledef = oNewTable
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; CreateTableDef V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DAvg( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return average of scope
+Const cstThisSub = &quot;Database.DAvg&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DAvg = _DFunction(&quot;AVG&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DAvg
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DCount( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return # of occurrences of scope
+Const cstThisSub = &quot;Database.DCount&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DCount = _DFunction(&quot;COUNT&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DCount
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DLookup( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ , ByVal Optional pvOrderClause As Variant _
+ ) As Variant
+
+&apos; Return a value within a table
+ &apos;Arguments: psExpr: an SQL expression
+ &apos; psDomain: a table- or queryname
+ &apos; pvCriteria: an optional WHERE clause
+ &apos; pcOrderClause: an optional order clause incl. &quot;DESC&quot; if relevant
+ &apos;Return: Value of the psExpr if found, else Null.
+ &apos;Author: inspired from Allen Browne. http://allenbrowne.com/ser-42.html
+ &apos;Examples:
+ &apos; 1. To find the last value, include DESC in the OrderClause, e.g.:
+ &apos; DLookup(&quot;[Surname] &amp; [FirstName]&quot;, &quot;tblClient&quot;, , &quot;ClientID DESC&quot;)
+ &apos; 2. To find the lowest non-null value of a field, use the Criteria, e.g.:
+ &apos; DLookup(&quot;ClientID&quot;, &quot;tblClient&quot;, &quot;Surname Is Not Null&quot; , &quot;Surname&quot;)
+
+Const cstThisSub = &quot;Database.DLookup&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DLookup = _DFunction(&quot;&quot;, psExpr, psDomain _
+ , Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria) _
+ , Iif(IsMissing(pvOrderClause), &quot;&quot;, pvOrderClause) _
+ )
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DLookup
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DMax( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return maximum of scope
+Const cstThisSub = &quot;Database.DMax&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DMax = _DFunction(&quot;MAX&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DMax
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DMin( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return minimum of scope
+Const cstThisSub = &quot;Database.DMin&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DMin = _DFunction(&quot;MIN&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DMin
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DStDev( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return standard deviation of scope
+Const cstThisSub = &quot;Database.DStDev&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DStDev = _DFunction(&quot;STDDEV_SAMP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;) &apos; STDDEV not STDEV !
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DStDev
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DStDevP( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return standard deviation of scope
+Const cstThisSub = &quot;Database.DStDevP&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DStDevP = _DFunction(&quot;STDDEV_POP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;) &apos; STDDEV not STDEV !
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DStDevP
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DSum( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return sum of scope
+Const cstThisSub = &quot;Database.DSum&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DSum = _DFunction(&quot;SUM&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DSum
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DVar( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return variance of scope
+Const cstThisSub = &quot;Database.DVar&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DVar = _DFunction(&quot;VAR_SAMP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DVar
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function DVarP( _
+ ByVal Optional psExpr As String _
+ , ByVal Optional psDomain As String _
+ , ByVal Optional pvCriteria As Variant _
+ ) As Variant
+&apos; Return variance of scope
+Const cstThisSub = &quot;Database.DVarP&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(psExpr) Or IsMissing(psDomain) Then Call _TraceArguments()
+ DVarP = _DFunction(&quot;VAR_POP&quot;, psExpr, psDomain, Iif(IsMissing(pvCriteria), &quot;&quot;, pvCriteria), &quot;&quot;)
+ Utils._ResetCalledSub(cstThisSub)
+End Function &apos; DVarP
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Database.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;Database.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenRecordset(ByVal Optional pvSource As Variant _
+ , ByVal Optional pvType As Variant _
+ , ByVal Optional pvOptions As Variant _
+ , ByVal Optional pvLockEdit As Variant _
+ ) As Object
+&apos;Return a Recordset object based on Source (= SQL, table or query name)
+
+Const cstThisSub = &quot;Database.OpenRecordset&quot;
+ Utils._SetCalledSub(cstThisSub)
+Const cstNull = -1
+
+Dim lCommandType As Long, sCommand As String, oObject As Object
+Dim sSource As String, i As Integer, iCount As Integer
+Dim sObjects() As String, bFound As Boolean, oTables As Object, oQueries As Object
+Dim iType As Integer, iOptions As Integer, iLockEdit As Integer
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Set oObject = Nothing
+ If IsMissing(pvSource) Then Call _TraceArguments()
+ If pvSource = &quot;&quot; Then Call _TraceArguments()
+ If VarType(pvType) = vbError Then
+ iType = cstNull
+ ElseIf IsMissing(pvType) Then
+ iType = cstNull
+ Else
+ If Not Utils._CheckArgument(pvType, 2, Utils._AddNumeric(), Array(cstNull, dbOpenForwardOnly)) Then Goto Exit_Function
+ iType = pvType
+ End If
+ If VarType(pvOptions) = vbError Then
+ iOptions = cstNull
+ ElseIf IsMissing(pvOptions) Then
+ iOptions = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOptions, 3, Utils._AddNumeric(), Array(cstNull, dbSQLPassThrough)) Then Goto Exit_Function
+ iOptions = pvOptions
+ End If
+ If VarType(pvLockEdit) = vbError Then
+ iLockEdit = cstNull
+ ElseIf IsMissing(pvLockEdit) Then
+ iLockEdit = cstNull
+ Else
+ If Not Utils._CheckArgument(pvLockEdit, 4, Utils._AddNumeric(), Array(cstNull, dbReadOnly)) Then Goto Exit_Function
+ iLockEdit = pvLockEdit
+ End If
+
+ sSource = Split(UCase(Trim(pvSource)), &quot; &quot;)(0)
+ Select Case True
+ Case sSource = &quot;SELECT&quot;
+ lCommandType = com.sun.star.sdb.CommandType.COMMAND
+ sCommand = _ReplaceSquareBrackets(pvSource)
+ Case Else
+ sSource = UCase(Trim(pvSource))
+ REM Explore tables
+ Set oTables = Connection.getTables
+ sObjects = oTables.ElementNames()
+ bFound = False
+ For i = 0 To UBound(sObjects)
+ If sSource = UCase(sObjects(i)) Then
+ sCommand = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If bFound Then
+ lCommandType = com.sun.star.sdb.CommandType.TABLE
+ Else
+ REM Explore queries
+ Set oQueries = Connection.getQueries
+ sObjects = oQueries.ElementNames()
+ For i = 0 To UBound(sObjects)
+ If sSource = UCase(sObjects(i)) Then
+ sCommand = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+ lCommandType = com.sun.star.sdb.CommandType.QUERY
+ End If
+ End Select
+
+ Set oObject = New Recordset
+ With oObject
+ ._CommandType = lCommandType
+ ._Command = sCommand
+ ._ParentName = Title
+ ._ParentType = _Type
+ ._ForwardOnly = ( iType = dbOpenForwardOnly )
+ ._PassThrough = ( iOptions = dbSQLPassThrough )
+ ._ReadOnly = ( (iLockEdit = dbReadOnly) Or _ReadOnly )
+ Set ._This = oObject
+ Set ._ParentDatabase = _This
+ Call ._Initialize()
+ RecordsetMax = RecordsetMax + 1
+ ._Name = Format(RecordsetMax, &quot;0000000&quot;)
+ RecordsetsColl.Add(oObject, UCase(._Name))
+ End With
+
+ If Not ( oObject._BOF And oObject._EOF ) Then oObject.MoveFirst() &apos; Do nothing if resultset empty
+
+Exit_Function:
+ Set OpenRecordset = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;TABLE&quot;) &amp; &quot;/&quot; &amp; _GetLabel(&quot;QUERY&quot;), pvSource))
+ Goto Exit_Function
+End Function &apos; OpenRecordset V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenSQL(Optional ByVal pvSQL As Variant _
+ , Optional ByVal pvOption As Variant _
+ ) As Boolean
+&apos; Return True if the execution of the SQL statement was successful
+&apos; SQL must contain a SELECT query
+&apos; pvOption can force pass through mode
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Const cstThisSub = &quot;Database.OpenSQL&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ OpenSQL = False
+ If IsMissing(pvSQL) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSQL, 1, vbString) Then Goto Exit_Function
+Const cstNull = -1
+ If IsMissing(pvOption) Then
+ pvOption = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOption, 2, Utils._AddNumeric(), Array(dbSQLPassThrough, cstNull)) Then Goto Exit_Function
+ End If
+ If _DbConnect &lt;&gt; DBCONNECTBASE And _DbConnect &lt;&gt; DBCONNECTFORM Then Goto Error_NotApplicable
+
+Dim oURL As New com.sun.star.util.URL, oDispatch As Object
+Dim vArgs(8) as New com.sun.star.beans.PropertyValue
+
+ oURL.Complete = &quot;.component:DB/DataSourceBrowser&quot;
+ oDispatch = StarDesktop.queryDispatch(oURL, &quot;_Blank&quot;, 8)
+
+ vArgs(0).Name = &quot;ActiveConnection&quot; : vArgs(0).Value = Connection
+ vArgs(1).Name = &quot;CommandType&quot; : vArgs(1).Value = com.sun.star.sdb.CommandType.COMMAND
+ vArgs(2).Name = &quot;Command&quot; : vArgs(2).Value = _ReplaceSquareBrackets(pvSQL)
+ vArgs(3).Name = &quot;ShowMenu&quot; : vArgs(3).Value = True
+ vArgs(4).Name = &quot;ShowTreeView&quot; : vArgs(4).Value = False
+ vArgs(5).Name = &quot;ShowTreeViewButton&quot; : vArgs(5).Value = False
+ vArgs(6).Name = &quot;Filter&quot; : vArgs(6).Value = &quot;&quot;
+ vArgs(7).Name = &quot;ApplyFilter&quot; : vArgs(7).Value = False
+ vArgs(8).Name = &quot;EscapeProcessing&quot; : vArgs(8).Value = CBool(Not ( pvOption = dbSQLPassThrough ))
+
+ oDispatch.dispatch(oURL, vArgs)
+ OpenSQL = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenSQL&quot;, Erl)
+ GoTo Exit_Function
+SQL_Error:
+ TraceError(TRACEFATAL, ERRSQLSTATEMENT, Utils._CalledSub(), 0, , pvSQL)
+ Goto Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+End Function &apos; OpenSQL V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OutputTo(ByVal pvObjectType As Variant _
+ , ByVal Optional pvObjectName As Variant _
+ , ByVal Optional pvOutputFormat As Variant _
+ , ByVal Optional pvOutputFile As Variant _
+ , ByVal Optional pvAutoStart As Variant _
+ , ByVal Optional pvTemplateFile As Variant _
+ , ByVal Optional pvEncoding As Variant _
+ , ByVal Optional pvQuality As Variant _
+ , ByRef Optional pvHeaders As Variant _
+ , ByRef Optional pvData As Variant _
+ ) As Boolean
+&apos;Supported: acFormatHTML, acFormatODS, acFormatXLS, acFormatXLSX, acFormatTXT for tables and queries
+&apos;pvHeaders and pvData (unpublished) when pvObjectType = acOutputArray
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Database.OutputTo&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ OutputTo = False
+
+ If Not Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), Array(acOutputTable, acOutputQuery, acOutputArray)) Then Goto Exit_Function
+ If IsMissing(pvObjectName) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvObjectName, 2, vbString) Then Goto Exit_Function
+ If IsMissing(pvOutputFormat) Then pvOutputFormat = &quot;&quot;
+ If Not Utils._CheckArgument(pvOutputFormat, 3, vbString) Then Goto Exit_Function
+ If pvOutputFormat &lt;&gt; &quot;&quot; Then
+ If Not Utils._CheckArgument(UCase(pvOutputFormat), 3, vbString, Array( _
+ UCase(acFormatHTML), &quot;HTML&quot; _
+ , UCase(acFormatODS), &quot;ODS&quot; _
+ , UCase(acFormatXLS), &quot;XLS&quot; _
+ , UCase(acFormatXLSX), &quot;XLSX&quot; _
+ , UCase(acFormatTXT), &quot;TXT&quot;, &quot;CSV&quot; _
+ , &quot;&quot;)) _
+ Then Goto Exit_Function &apos; A 2nd time to allow case unsensitivity
+ End If
+ If IsMissing(pvOutputFile) Then pvOutputFile = &quot;&quot;
+ If Not Utils._CheckArgument(pvOutputFile, 4, vbString) Then Goto Exit_Function
+ If IsMissing(pvAutoStart) Then pvAutoStart = False
+ If Not Utils._CheckArgument(pvAutoStart, 5, vbBoolean) Then Goto Exit_Function
+ If IsMissing(pvTemplateFile) Then pvTemplateFile = &quot;&quot;
+ If Not Utils._CheckArgument(pvTemplateFile, 6, vbString) Then Goto Exit_Function
+ If IsMissing(pvEncoding) Then pvEncoding = 0
+ If Not Utils._CheckArgument(pvEncoding, 7, _AddNumeric()) Then Goto Exit_Function
+ If IsMissing(pvQuality) Then pvQuality = acExportQualityPrint
+ If Not Utils._CheckArgument(pvQuality, 7, _AddNumeric(), Array(acExportQualityPrint, acExportQualityScreen)) Then Goto Exit_Function
+ If pvObjectType = acOutputArray Then
+ If IsMissing(pvHeaders) Or IsMissing(pvData) Then Call _TraceArguments()
+ pvOutputFormat = &quot;HTML&quot;
+ End If
+
+Dim sOutputFile As String, oTable As Object
+Dim sOutputFormat As String, iTemplate As Integer, iOutputFile As Integer, bOutput As Boolean, sSuffix As String
+
+ If pvObjectType = acOutputArray Then
+ Set oTable = Nothing
+ Else
+ &apos;Find applicable table or query
+ If pvObjectType = acOutputTable Then Set oTable = TableDefs(pvObjectName, True) Else Set oTable = Querydefs(pvObjectName, True)
+ If IsNull(oTable) Then Goto Error_NotFound
+ End If
+
+ &apos;Determine format and parameters
+ If pvOutputFormat = &quot;&quot; Then
+ sOutputFormat = _PromptFormat(Array(&quot;HTML&quot;, &quot;ODS&quot;, &quot;XLS&quot;, &quot;XLSX&quot;, &quot;TXT&quot;)) &apos; Prompt user for format
+ If sOutputFormat = &quot;&quot; Then Goto Exit_Function
+ Else
+ sOutputFormat = UCase(pvOutputFormat)
+ End If
+
+ &apos;Determine output file
+ If pvOutputFile = &quot;&quot; Then &apos; Prompt file picker to user
+ Select Case sOutputFormat
+ Case UCase(acFormatHTML), &quot;HTML&quot; : sSuffix = &quot;html&quot;
+ Case UCase(acFormatODS), &quot;ODS&quot; : sSuffix = &quot;ods&quot;
+ Case UCase(acFormatXLS), &quot;XLS&quot; : sSuffix = &quot;xls&quot;
+ Case UCase(acFormatXLSX), &quot;XLSX&quot; : sSuffix = &quot;xlsx&quot;
+ Case UCase(acFormatTXT), &quot;TXT&quot;, &quot;CSV&quot; : sSuffix = &quot;txt&quot;
+ End Select
+ sOutputFile = _PromptFilePicker(sSuffix)
+ If sOutputFile = &quot;&quot; Then Goto Exit_Function
+ Else
+ sOutputFile = pvOutputFile
+ End If
+ sOutputFile = ConvertToURL(sOutputFile)
+
+ &apos;Create file
+ Select Case sOutputFormat
+ Case UCase(acFormatHTML), &quot;HTML&quot;
+ If pvObjectType = acOutputArray Then
+ bOutput = _OutputToHTML(Nothing, pvObjectName, sOutputFile, pvTemplateFile, pvHeaders, pvData)
+ Else
+ bOutput = _OutputToHTML(oTable, pvObjectName, sOutputFile, pvTemplateFile)
+ End If
+ Case UCase(acFormatODS), &quot;ODS&quot;
+ bOutput = _OutputToCalc(oTable, sOutputFile, acFormatODS)
+ Case UCase(acFormatXLS), &quot;XLS&quot;
+ bOutput = _OutputToCalc(oTable, sOutputFile, acFormatXLS)
+ Case UCase(acFormatXLS), &quot;XLSX&quot;
+ bOutput = _OutputToCalc(oTable, sOutputFile, acFormatXLSX)
+ Case UCase(acFormatTXT), &quot;TXT&quot;, &quot;CSV&quot;
+ bOutput = _OutputToCalc(oTable, sOutputFile, acFormatTXT, pvEncoding)
+ End Select
+
+ &apos;Launch application, if requested
+ If bOutput Then
+ If pvAutoStart Then Call _ShellExecute(sOutputFile)
+ Else
+ GoTo Error_File
+ End If
+
+ OutputTo = True
+
+Exit_Function:
+ If Not IsNull(oTable) Then
+ oTable.Dispose()
+ Set oTable = Nothing
+ End If
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;OBJECT&quot;), pvObjectName))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_File:
+ TraceError(TRACEFATAL, ERRFILENOTCREATED, Utils._CalledSub(), 0, , sOutputFile)
+ GoTo Exit_Function
+End Function &apos; OutputTo V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+ Utils._SetCalledSub(&quot;Database.Properties&quot;)
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+ Set vProperty._ParentDatabase = _This
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(&quot;Database.Properties&quot;)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function QueryDefs(ByVal Optional pvIndex As Variant, ByVal Optional pbCheck As Boolean) As Object
+&apos; Collect all Queries in the database
+&apos; pbCheck unpublished
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Database.QueryDefs&quot;)
+ If IsMissing(pbCheck) Then pbCheck = False
+
+Dim sObjects() As String, sObjectName As String, oObject As Object
+Dim i As Integer, bFound As Boolean, oQueries As Object
+ Set oObject = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+ Set oQueries = Connection.getQueries
+ sObjects = oQueries.ElementNames()
+ Select Case True
+ Case IsMissing(pvIndex)
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLQUERYDEFS
+ Set oObject._Parent = _This
+ oObject._Count = UBound(sObjects) + 1
+ Goto Exit_Function
+ Case VarType(pvIndex) = vbString
+ bFound = False
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ For i = 0 To UBound(sObjects)
+ If UCase(pvIndex) = UCase(sObjects(i)) Then
+ sObjectName = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+ Case Else &apos; pvIndex is numeric
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(sObjects) Then Goto Trace_IndexError
+ sObjectName = sObjects(pvIndex)
+ End Select
+
+ Set oObject = New DataDef
+ Set oObject._This = oObject
+ oObject._Type = OBJQUERYDEF
+ oObject._Name = sObjectName
+ Set oObject._ParentDatabase = _This
+ oObject._readOnly = _ReadOnly
+ Set oObject.Query = oQueries.getByName(sObjectName)
+
+Exit_Function:
+ Set QueryDefs = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(&quot;Database.QueryDefs&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Database.QueryDefs&quot;, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ If Not pbCheck Then TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;QUERY&quot;), pvIndex))
+ Goto Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; QueryDefs V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Recordsets(ByVal Optional pvIndex As Variant) As Object
+&apos; Collect all active recordsets
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Database.Recordsets&quot;)
+
+ Set Recordsets = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+Dim sObjects() As String, sObjectName As String, oObject As Object
+Dim i As Integer, bFound As Boolean, oTables As Object
+
+ Select Case True
+ Case IsMissing(pvIndex)
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLRECORDSETS
+ Set oObject._Parent = _This
+ oObject._Count = RecordsetsColl.Count
+ Case VarType(pvIndex) = vbString
+ bFound = _hasRecordset(pvIndex)
+ If Not bFound Then Goto Trace_NotFound
+ Set oObject = RecordsetsColl.Item(pvIndex)
+ Case Else &apos; pvIndex is numeric
+ If pvIndex &lt; 0 Or pvIndex &gt;= RecordsetsColl.Count Then Goto Trace_IndexError
+ Set oObject = RecordsetsColl.Item(pvIndex + 1) &apos; Collection members are numbered 1 ... Count
+ End Select
+
+Exit_Function:
+ Set Recordsets = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(&quot;Database.Recordsets&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Database.Recordsets&quot;, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;RECORDSET&quot;), pvIndex))
+ Goto Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; Recordsets V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function RunSQL(Optional ByVal pvSQL As Variant _
+ , Optional ByVal pvOption As Variant _
+ ) As Boolean
+&apos; Return True if the execution of the SQL statement was successful
+&apos; SQL must contain an ACTION query
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Const cstThisSub = &quot;Database.RunSQL&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ RunSQL = False
+ If IsMissing(pvSQL) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSQL, 1, vbString) Then Goto Exit_Function
+Const cstNull = -1
+ If IsMissing(pvOption) Then
+ pvOption = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOption, 2, Utils._AddNumeric(), Array(cstNull, dbSQLPassThrough)) Then Goto Exit_Function
+ End If
+
+Dim oStatement As Object, vResult As Variant
+ Set oStatement = Connection.createStatement()
+ oStatement.EscapeProcessing = Not ( pvOption = dbSQLPassThrough )
+ On Local Error Goto SQL_Error
+ vResult = oStatement.execute(_ReplaceSquareBrackets(pvSQL))
+ On Local Error Goto Error_Function
+ RunSQL = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+SQL_Error:
+ TraceError(TRACEFATAL, ERRSQLSTATEMENT, Utils._CalledSub(), 0, , pvSQL)
+ Goto Exit_Function
+End Function &apos; RunSQL V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function TableDefs(ByVal Optional pvIndex As Variant, ByVal Optional pbCheck As Boolean) As Object
+&apos; Collect all tables in the database
+&apos; pbCheck unpublished
+
+Const cstThisSub = &quot;Database.TableDefs&quot;
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pbCheck) Then pbCheck = False
+
+Dim sObjects() As String, sObjectName As String, oObject As Object
+Dim i As Integer, bFound As Boolean, oTables As Object
+ Set oObject = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+ Set oTables = Connection.getTables
+ sObjects = oTables.ElementNames()
+ Select Case True
+ Case IsMissing(pvIndex)
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLTABLEDEFS
+ Set oObject._Parent = _This
+ oObject._Count = UBound(sObjects) + 1
+ Goto Exit_Function
+ Case VarType(pvIndex) = vbString
+ bFound = False
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ For i = 0 To UBound(sObjects)
+ If UCase(pvIndex) = UCase(sObjects(i)) Then
+ sObjectName = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+ Case Else &apos; pvIndex is numeric
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(sObjects) Then Goto Trace_IndexError
+ sObjectName = sObjects(pvIndex)
+ End Select
+
+ Set oObject = New DataDef
+ With oObject
+ ._This = oObject
+ ._Type = OBJTABLEDEF
+ ._Name = sObjectName
+ Set ._ParentDatabase = _This
+ ._ReadOnly = _ReadOnly
+ Set .Table = oTables.getByName(sObjectName)
+ .CatalogName = .Table.CatalogName
+ .SchemaName = .Table.SchemaName
+ .TableName = .Table.Name
+ End With
+
+Exit_Function:
+ Set TableDefs = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ If Not pbCheck Then TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;TABLE&quot;), pvIndex))
+ Goto Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; TableDefs V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _DFunction(ByVal psFunction As String _
+ , ByVal psExpr As String _
+ , ByVal psDomain As String _
+ , ByVal pvCriteria As Variant _
+ , ByVal Optional pvOrderClause As Variant _
+ ) As Variant
+ &apos;Arguments: psFunction an optional aggregate function
+ &apos; psExpr: an SQL expression [might contain an aggregate function]
+ &apos; psDomain: a table- or queryname
+ &apos; pvCriteria: an optional WHERE clause
+ &apos; pcOrderClause: an optional order clause incl. &quot;DESC&quot; if relevant
+
+If _ErrorHandler() Then On Local Error GoTo Error_Function
+
+Dim oResult As Object &apos;To retrieve the value to find.
+Dim vResult As Variant &apos;Return value for function.
+Dim sSql As String &apos;SQL statement.
+Dim oStatement As Object &apos;For CreateStatement method
+Dim sExpr As String &apos;For inclusion of aggregate function
+Dim sTempField As String &apos;Random temporary field in SQL expression
+
+Dim sTarget as String, sWhere As String, sOrderBy As String, sLimit As String
+Dim sProductName As String
+
+ vResult = Null
+
+ Randomize 2^14-1
+ sTempField = &quot;[TEMP&quot; &amp; Right(&quot;00000&quot; &amp; Int(100000 * Rnd), 5) &amp; &quot;]&quot;
+ If pvCriteria &lt;&gt; &quot;&quot; Then sWhere = &quot; WHERE &quot; &amp; pvCriteria Else sWhere = &quot;&quot;
+ If pvOrderClause &lt;&gt; &quot;&quot; Then sOrderBy = &quot; ORDER BY &quot; &amp; pvOrderClause Else sOrderBy = &quot;&quot;
+ sLimit = &quot;&quot;
+
+ sProductName = UCase(MetaData.getDatabaseProductName())
+
+ Select Case sProductName
+ Case &quot;MYSQL&quot;, &quot;SQLITE&quot;
+ If psFunction = &quot;&quot; Then
+ sTarget = psExpr
+ sLimit = &quot; LIMIT 1&quot;
+ Else
+ sTarget = UCase(psFunction) &amp; &quot;(&quot; &amp; psExpr &amp; &quot;)&quot;
+ End If
+ sSql = &quot;SELECT &quot; &amp; sTarget &amp; &quot; AS &quot; &amp; sTempField &amp; &quot; FROM &quot; &amp; psDomain &amp; sWhere &amp; sOrderBy &amp; sLimit
+ Case &quot;FIREBIRD (ENGINE12)&quot;
+ If psFunction = &quot;&quot; Then sTarget = &quot;FIRST 1 &quot; &amp; psExpr Else sTarget = UCase(psFunction) &amp; &quot;(&quot; &amp; psExpr &amp; &quot;)&quot;
+ sSql = &quot;SELECT &quot; &amp; sTarget &amp; &quot; AS &quot; &amp; sTempField &amp; &quot; FROM &quot; &amp; psDomain &amp; sWhere &amp; sOrderBy
+ Case Else &apos; Standard syntax - Includes HSQLDB
+ If psFunction = &quot;&quot; Then sTarget = &quot;TOP 1 &quot; &amp; psExpr Else sTarget = UCase(psFunction) &amp; &quot;(&quot; &amp; psExpr &amp; &quot;)&quot;
+ sSql = &quot;SELECT &quot; &amp; sTarget &amp; &quot; AS &quot; &amp; sTempField &amp; &quot; FROM &quot; &amp; psDomain &amp; sWhere &amp; sOrderBy
+ End Select
+
+ &apos;Lookup the value.
+ Set oStatement = Connection.createStatement()
+ With oStatement
+ .ResultSetType = com.sun.star.sdbc.ResultSetType.FORWARD_ONLY
+ .ResultSetConcurrency = com.sun.star.sdbc.ResultSetConcurrency.READ_ONLY
+ .EscapeProcessing = False
+ sSql = _ReplaceSquareBrackets(sSql) &apos;Substitute [] by quote string
+ Set oResult = .executeQuery(sSql)
+ If Not IsNull(oResult) And Not IsEmpty(oResult) Then
+ If Not oResult.next() Then Goto Exit_Function
+ vResult = Utils._getResultSetColumnValue(oResult, 1, True) &apos; Force return of binary field
+ End If
+ End With
+
+Exit_Function:
+ &apos;Assign the returned value.
+ _DFunction = vResult
+ Set oResult = Nothing
+ Set oStatement = Nothing
+ Exit Function
+Error_Function:
+ TraceError(TRACEFATAL, ERRDFUNCTION, _A2B_.CalledSub, 0, , sSQL)
+ Goto Exit_Function
+End Function &apos; DFunction V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _FilterOptionsDefault(ByVal plEncoding As Long) As String
+&apos; Return the default FilterOptions string for table/query export to csv
+
+Dim sFieldSeparator as string
+Const cstComma = &quot;,&quot;
+Const cstTextDelimitor = &quot;&quot;&quot;&quot;
+
+ If _DecimalPoint() = &quot;,&quot; Then sFieldSeparator = &quot;;&quot; Else sFieldSeparator = cstComma
+ _FilteroptionsDefault = Trim(Str(Asc(sFieldSeparator))) _
+ &amp; cstComma &amp; Trim(Str(Asc(cstTextDelimitor))) _
+ &amp; cstComma &amp; Trim(Str(plEncoding)) _
+ &amp; cstComma &amp; &quot;1&quot;
+
+End Function &apos; _FilterOptionsDefault V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _hasRecordset(ByVal psName As String) As Boolean
+&apos; Return True if psName if in the collection of Recordsets
+
+Dim oRecordset As Object
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Set oRecordset = RecordsetsColl.Item(psName)
+ _hasRecordset = True
+
+Exit_Function:
+ Exit Function
+Error_Function: &apos; Item by key aborted
+ _hasRecordset = False
+ GoTo Exit_Function
+End Function &apos; _hasRecordset V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub _LoadMetadata()
+&apos; Load essentially getTypeInfo() results from Metadata
+
+Dim sProduct As String
+Dim iInfo As Integer, oTypeInfo As Object, sName As String, lType As Integer
+
+Const cstMaxInfo = 40
+ ReDim _ColumnTypes(0 To cstMaxInfo)
+ ReDim _ColumnTypeNames(0 To cstMaxInfo)
+ ReDim _ColumnPrecisions(0 To cstMaxInfo)
+Const cstHSQLDB1 = &quot;HSQL Database Engine 1.&quot;
+Const cstHSQLDB2 = &quot;HSQL Database Engine 2.&quot;
+Const cstFirebird = &quot;sdbc:embedded:firebird&quot;
+Const cstMSAccess2003 = &quot;MS Jet 0&quot;
+Const cstMSAccess2007 = &quot;MS Jet 04.&quot;
+Const cstMYSQL = &quot;MySQL&quot;
+Const cstPOSTGRES = &quot;PostgreSQL&quot;
+Const cstSQLITE = &quot;SQLite&quot;
+
+ With com.sun.star.sdbc.DataType
+ _ColumnTypesReference = Array( _
+ .ARRAY _
+ , .BIGINT _
+ , .BINARY _
+ , .BIT _
+ , .BLOB _
+ , .BOOLEAN _
+ , .CHAR _
+ , .CLOB _
+ , .DATE _
+ , .DECIMAL _
+ , .DISTINCT _
+ , .DOUBLE _
+ , .FLOAT _
+ , .INTEGER _
+ , .LONGVARBINARY _
+ , .LONGVARCHAR _
+ , .NUMERIC _
+ , .OBJECT _
+ , .OTHER _
+ , .REAL _
+ , .REF _
+ , .SMALLINT _
+ , .SQLNULL _
+ , .STRUCT _
+ , .TIME _
+ , .TIMESTAMP _
+ , .TINYINT _
+ , .VARBINARY _
+ , .VARCHAR _
+ )
+ End With
+
+ With Metadata
+ sProduct = .getDatabaseProductName() &amp; &quot; &quot; &amp; .getDatabaseProductVersion
+ Select Case True
+ Case Len(sProduct) &gt; Len(cstHSQLDB1) And Left(sProduct, Len(cstHSQLDB1)) = cstHSQLDB1
+ _RDBMS = DBMS_HSQLDB1
+ _ColumnTypesAlias = Array(0, -5, -2, 16, -4, 16, 1, -1, 91, 3, 0, 8, 6, 4, -4, -1, 2, 0, 0, 7, 0, 5, 0, 0, 92, 93, -6, -3, 12)
+ _BinaryStream = True
+ Case Len(sProduct) &gt; Len(cstHSQLDB2) And Left(sProduct, Len(cstHSQLDB2)) = cstHSQLDB2
+ _RDBMS = DBMS_HSQLDB2
+ _ColumnTypesAlias = Array(0, -5, -3, -7, 2004, 16, 1, 2005, 91, 3, 0, 8, 8, 4, -3, 12, 2, 0, 0, 8, 0, 5, 0, 0, 92, 93, -6, -3, 12)
+ _BinaryStream = True
+ Case .URL = cstFirebird &apos; Only embedded 3.0
+ _RDBMS = DBMS_FIREBIRD
+ _ColumnTypesAlias = Array(0, -5, -2, 16, 2004, 16, 1, 2005, 91, 3, 0, 8, 6, 4, -4, 2005, 2, 0, 0, 8, 0, 5, 0, 0, 92, 93, 4, 2004, 12)
+ _BinaryStream = True
+ Case Len(sProduct) &gt; Len(cstMSAccess2007) And Left(sProduct, Len(cstMSAccess2007)) = cstMSAccess2007
+ _RDBMS = DBMS_MSACCESS2007
+ _ColumnTypesAlias = Array(0, 4, -2, 16, -2, 16, 12, 12, 93, 8, 0, 8, 6, 4, -3, 12, 2, 0, 0, 8, 0, 5, 0, 0, 93, 93, -6, -2, 12)
+ _BinaryStream = True
+ Case Len(sProduct) &gt; Len(cstMSAccess2003) And Left(sProduct, Len(cstMSAccess2003)) = cstMSAccess2003
+ _RDBMS = DBMS_MSACCESS2003
+ _ColumnTypesAlias = Array(0, 4, -2, 16, -2, 16, 12, 12, 93, 8, 0, 8, 6, 4, -3, 12, 2, 0, 0, 8, 0, 5, 0, 0, 93, 93, -6, -2, 12)
+ _BinaryStream = True
+ Case Len(sProduct) &gt; Len(cstMYSQL) And Left(sProduct, Len(cstMYSQL)) = cstMYSQL
+ _RDBMS = DBMS_MYSQL
+ _ColumnTypesAlias = Array(0, -5, -2, -7, -4, -7, 1, -1, 91, 3, 0, 8, 8, 4, -4, -1, 2, 0, 0, 7, 0, 5, 0, 0, 92, 93, -6, -3, -1)
+ _BinaryStream = False
+ Case Len(sProduct) &gt; Len(cstPOSTGRES) And Left(sProduct, Len(cstPOSTGRES)) = cstPOSTGRES
+ _RDBMS = DBMS_POSTGRES
+ _ColumnTypesAlias = Array(0, -5, -3, 16, -3, 16, 1, 12, 91, 8, 0, 8, 8, 4, -3, 12, 2, 0, 0, 7, 0, 5, 0, 0, 92, 93, 4, -3, 12)
+ _BinaryStream = True
+ Case Len(sProduct) &gt; Len(cstSQLITE) And Left(sProduct, Len(cstSQLITE)) = cstSQLITE
+ _RDBMS = DBMS_SQLITE
+ _ColumnTypesAlias = Array(0, -5, -4, -7, -4, -7, 1, -1, 91, 8, 0, 8, 6, 4, -4, -1, 8, 0, 0, 8, 0, 5, 0, 0, 92, 93, -6, -4, 12)
+ _BinaryStream = True
+ Case Else
+ _RDBMS = DBMS_UNKNOWN
+ _BinaryStream = True
+ End Select
+
+ iInfo = -1
+ Set oTypeInfo = MetaData.getTypeInfo()
+ With oTypeInfo
+ .next()
+ Do While Not .isAfterLast() And iInfo &lt; cstMaxInfo
+ sName = .getString(1)
+ lType = .getLong(2)
+ If _RDBMS = DBMS_POSTGRES And (Left(sName, 1) &lt;&gt; &quot;_&quot; Or lType &lt;&gt; -1) Then &apos; Skip
+ Else
+ iInfo = iInfo + 1
+ _ColumnTypeNames(iInfo) = sName
+ _ColumnTypes(iInfo) = lType
+ _ColumnPrecisions(iInfo) = CLng(.getLong(3))
+ End If
+ .next()
+ Loop
+ End With
+ ReDim Preserve _ColumnTypes(0 To iInfo)
+ ReDim Preserve _ColumnTypeNames(0 To iInfo)
+ ReDim Preserve _ColumnPrecisions(0 To iInfo)
+ End With
+
+End Sub &apos; _LoadMetadata V1.6.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputBinaryToHTML() As String
+&apos; Converts Binary value to HTML compatible string
+
+ _OutputBinaryToHTML = &quot;&amp;nbsp;&quot;
+
+End Function &apos; _OutputBinaryToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputBooleanToHTML(ByVal pbBool As Boolean) As String
+&apos; Converts input boolean value to HTML compatible string
+
+ _OutputBooleanToHTML = Iif(pbBool, &quot;&amp;#x2714;&quot;, &quot;&amp;#x2716;&quot;) &apos; ✔ and ✖
+
+End Function &apos; _OutputBooleanToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputClassToHTML(ByVal pvArray As Variant) As String
+&apos; Formats classes attribute of &lt;tr&gt; and &lt;td&gt; tags
+
+ If Not IsArray(pvArray) Then
+ _OutputClassToHTML = &quot;&quot;
+ ElseIf UBound(pvArray) &lt; LBound(pvArray) Then
+ _OutputClassToHTML = &quot;&quot;
+ Else
+ _OutputClassToHTML = &quot; class=&quot;&quot;&quot; &amp; Join(pvArray, &quot; &quot;) &amp; &quot;&quot;&quot;&quot;
+ End If
+
+End Function &apos; _OutputClassToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputDataToHTML(ByRef pvTable As Variant, ByVal pvName As String, ByVal piFile As Integer _
+ , ByRef Optional pvHeaders As Variant _
+ , ByRef Optional pvData As Variant _
+ ) As Boolean
+&apos; Write html tags around data found in pvTable
+&apos; Exit when error without execution stop (to avoid file remaining open ...)
+
+Dim oTableRS As Object, vData() As Variant, i As Integer, j As Integer
+Dim vFieldsBin() As Variant, iDataType As Integer, iNumRows As Integer, iNumFields As Integer, vDataCell As Variant
+Dim bDataArray As Boolean, sHeader As String
+Dim vTrClass() As Variant, vTdClass As Variant, iCountRows As Integer, iLastRow As Integer
+Const cstMaxRows = 200
+ On Local Error GoTo Error_Function
+
+ bDataArray = IsNull(pvTable)
+ Print #piFile, &quot; &lt;table class=&quot;&quot;dbdatatable&quot;&quot;&gt;&quot;
+ Print #piFile, &quot; &lt;caption&gt;&quot; &amp; pvName &amp; &quot;&lt;/caption&gt;&quot;
+
+ vFieldsBin() = Array()
+ If bDataArray Then
+ Set oTableRS = Nothing
+ iNumFields = UBound(pvHeaders) + 1
+ ReDim vFieldsBin(0 To iNumFields - 1)
+ For i = 0 To iNumFields - 1
+ vFieldsBin(i) = False
+ Next i
+ Else
+ Set oTableRS = pvTable.OpenRecordset( , , dbReadOnly)
+ iNumFields = oTableRS.Fields.Count
+ ReDim vFieldsBin(0 To iNumFields - 1)
+ With com.sun.star.sdbc.DataType
+ For i = 0 To iNumFields - 1
+ iDataType = oTableRS.Fields(i).DataType
+ vFieldsBin(i) = Utils._IsBinaryType(iDataType)
+ Next i
+ End With
+ End If
+
+ With oTableRS
+ Print #piFile, &quot; &lt;thead&gt;&quot;
+ Print #piFile, &quot; &lt;tr&gt;&quot;
+ For i = 0 To iNumFields - 1
+ If bDataArray Then sHeader = pvHeaders(i) Else sHeader = .Fields(i)._Name
+ Print #piFile, &quot; &lt;th scope=&quot;&quot;col&quot;&quot;&gt;&quot; &amp; sHeader &amp; &quot;&lt;/th&gt;&quot;
+ Next i
+ Print #piFile, &quot; &lt;/tr&gt;&quot;
+ Print #piFile, &quot; &lt;/thead&gt;&quot;
+ Print #piFile, &quot; &lt;tfoot&gt;&quot;
+ Print #piFile, &quot; &lt;/tfoot&gt;&quot;
+
+ Print #piFile, &quot; &lt;tbody&gt;&quot;
+ If bDataArray Then
+ iLastRow = UBound(pvData, 2) + 1
+ Else
+ .MoveLast
+ iLastRow = .RecordCount
+ .MoveFirst
+ End If
+ iCountRows = 0
+ Do While iCountRows &lt; iLastRow
+ If bDataArray Then
+ iNumRows = iLastRow
+ Else
+ vData() = .GetRows(cstMaxRows)
+ iNumRows = UBound(vData, 2) + 1
+ End If
+ For j = 0 To iNumRows - 1
+ iCountRows = iCountRows + 1
+ vTrClass() = Array()
+ If iCountRows = 1 Then vTrClass() = _AddArray(vTrClass, &quot;firstrow&quot;)
+ If iCountRows = iLastRow Then vTrClass() = _AddArray(vTrClass, &quot;lastrow&quot;)
+ If (iCountRows Mod 2) = 0 Then vTrClass() = _AddArray(vTrClass, &quot;even&quot;) Else vTrClass() = _AddArray(vTrClass, &quot;odd&quot;)
+ Print #piFile, &quot; &lt;tr&quot; &amp; _OutputClassToHTML(vTrClass) &amp; &quot;&gt;&quot;
+ For i = 0 To iNumFields - 1
+ vTdClass() = Array()
+ If i = 0 Then vTdClass() = _AddArray(vTdClass, &quot;firstcol&quot;)
+ If i = iNumFields - 1 Then vTdClass() = _AddArray(vTdClass, &quot;lastcol&quot;)
+ If Not vFieldsBin(i) Then
+ If bDataArray Then vDataCell = pvData(i, j) Else vDataCell = vData(i, j)
+ If vDataCell Is Nothing Then vDataCell = Null &apos; Necessary because Null object has not a VarType = vbNull
+ If VarType(vDataCell) = vbString Then &apos; Null string gives IsDate = True !
+ If Len(vDataCell) &gt; 0 And IsDate(vDataCell) Then vDataCell = CDate(vDataCell)
+ End If
+ Select Case VarType(vDataCell)
+ Case vbEmpty, vbNull
+ vTdClass() = _AddArray(vTdClass, &quot;null&quot;)
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _OutputNullToHTML() &amp; &quot;&lt;/td&gt;&quot;
+ Case vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbDecimal, vbUShort, vbULong, vbBigInt
+ vTdClass() = _AddArray(vTdClass, &quot;numeric&quot;)
+ If vDataCell &lt; 0 Then vTdClass() = _AddArray(vTdClass, &quot;negative&quot;)
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _OutputNumberToHTML(vDataCell) &amp; &quot;&lt;/td&gt;&quot;
+ Case vbBoolean
+ vTdClass() = _AddArray(vTdClass, &quot;bool&quot;)
+ If vDataCell = False Then vTdClass() = _AddArray(vTdClass, &quot;false&quot;)
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _OutputBooleanToHTML(vDataCell) &amp; &quot;&lt;/td&gt;&quot;
+ Case vbDate
+ vTdClass() = _AddArray(vTdClass, &quot;date&quot;)
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _OutputDateToHTML(vDataCell) &amp; &quot;&lt;/td&gt;&quot;
+ Case vbString
+ vTdClass() = _AddArray(vTdClass, &quot;char&quot;)
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _OutputStringToHTML(vDataCell) &amp; &quot;&lt;/td&gt;&quot;
+ Case Else
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _CStr(vDataCell) &amp; &quot;&lt;/td&gt;&quot;
+ End Select
+ Else &apos; Binary fields
+ Print #piFile, &quot; &lt;td&quot; &amp; _OutputClassToHTML(vTdClass) &amp; &quot;&gt;&quot; &amp; _OutputBinaryToHTML() &amp; &quot;&lt;/td&gt;&quot;
+ End If
+ Next i
+ Print #piFile, &quot; &lt;/tr&gt;&quot;
+ Next j
+ Loop
+
+ If Not bDataArray Then .mClose()
+ End With
+ Set oTableRS = Nothing
+
+ Print #piFile, &quot; &lt;/tbody&gt;&quot;
+ Print #piFile, &quot; &lt;/table&gt;&quot;
+ _OutputDataToHTML = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEWARNING, Err, &quot;_OutputDataToHTML&quot;, Erl)
+ _OutputDataToHTML = False
+ Resume Exit_Function
+End Function &apos; _OutputDataToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputDateToHTML(ByVal psDate As Date) As String
+&apos; Converts input date to HTML compatible string
+
+ _OutputDateToHTML = Format(psDate) &apos; With regional settings - Ignores time if = to 0
+
+End Function &apos; _OutputDateToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputNullToHTML() As String
+&apos; Converts Null value to HTML compatible string
+
+ _OutputNullToHTML = &quot;&amp;nbsp;&quot;
+
+End Function &apos; _OutputNullToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputNumberToHTML(ByVal pvNumber As Variant, ByVal Optional piPrecision As Integer) As String
+&apos; Converts input number to HTML compatible string
+
+Dim vNumber As Variant
+ If IsMissing(piPrecision) Then piPrecision = -1
+ If pvNumber = Int(pvNumber) Then
+ vNumber = Int(pvNumber)
+ Else
+ If piPrecision &gt;= 0 Then vNumber = (Int(pvNumber * 10 ^ piPrecision + 0.5)) / 10 ^ piPrecision Else vNumber = pvNumber
+ End If
+ _OutputNumberToHTML = Format(vNumber)
+
+End Function &apos; _OutputNumberToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputStringToHTML(ByVal psString As String) As String
+&apos; Converts input string to HTML compatible string
+&apos; - UTF-8 encoding
+&apos; - recognition of next patterns
+&apos; - &amp;quot; - &amp;amp; - &amp;apos; - &amp;lt; - &amp;gt;
+&apos; - &lt;pre&gt;
+&apos; - &lt;a href=&quot;...
+&apos; - &lt;br&gt;
+&apos; - &lt;img src=&quot;...
+&apos; - &lt;b&gt;, &lt;u&gt;, &lt;i&gt;
+
+Dim vPatterns As Variant
+Dim lCurrentChar as Long, lPattern As Long, lNextPattern As Long, sPattern As String
+Dim sOutput As String, sChar As String
+Dim sUrl As String, lNextQuote As Long, lUrl As Long, bQuote As Boolean, bTagEnd As Boolean
+Dim i As Integer, l As Long
+
+ vPatterns = Array( _
+ &quot;&amp;quot;&quot;, &quot;&amp;amp;&quot;, &quot;&amp;apos;&quot;, &quot;&amp;lt;&quot;, &quot;&amp;gt;&quot;, &quot;&amp;nbsp;&quot; _
+ , &quot;&lt;pre&gt;&quot;, &quot;&lt;/pre&gt;&quot;, &quot;&lt;br&gt;&quot; _
+ , &quot;&lt;a href=&quot;&quot;&quot;, &quot;&lt;a id=&quot;&quot;&quot;, &quot;&lt;/a&gt;&quot;, &quot;&lt;img src=&quot;&quot;&quot; _
+ , &quot;&lt;span class=&quot;&quot;&quot;, &quot;&lt;/span&gt;&quot; _
+ , &quot;&lt;b&gt;&quot;, &quot;&lt;/b&gt;&quot;, &quot;&lt;u&gt;&quot;, &quot;&lt;/u&gt;&quot;, &quot;&lt;i&gt;&quot;, &quot;&lt;/i&gt;&quot; _
+ )
+
+ lCurrentChar = 1
+ sOutput = &quot;&quot;
+
+ Do While lCurrentChar &lt;= Len(psString)
+ &apos; Where is next closest pattern ?
+ lPattern = Len(psString) + 1
+ sPattern = &quot;&quot;
+ For i = 0 To UBound(vPatterns)
+ lNextPattern = InStr(lCurrentChar, psString, vPatterns(i), 1) &apos; Text (not case-sensitive) string comparison
+ If lNextPattern &gt; 0 And lNextPattern &lt; lPattern Then
+ lPattern = lNextPattern
+ sPattern = Mid(psString, lPattern, Len(vPatterns(i)))
+ End If
+ Next i
+ &apos; Up to the next pattern or to the end of the string, UTF8-encode each character
+ For l = lCurrentChar To lPattern - 1
+ sChar = Mid(psString, l, 1)
+ sOutput = sOutput &amp; Utils._UTF8Encode(sChar)
+ Next l
+ &apos; Process hyperlink patterns and keep others
+ If Len(sPattern) &gt; 0 Then
+ Select Case LCase(sPattern)
+ Case &quot;&lt;a href=&quot;&quot;&quot;, &quot;&lt;a id=&quot;&quot;&quot;, &quot;&lt;img src=&quot;&quot;&quot;, &quot;&lt;span class=&quot;&quot;&quot;
+ &apos; Up to next quote, url-encode
+ lNextQuote = 0
+ lUrl = lPattern + Len(sPattern)
+ lNextQuote = InStr(lUrl, psString, &quot;&quot;&quot;&quot;, 1)
+ If lNextQuote = 0 Then lNextQuote = Len(psString) &apos; Should not happen but, if quoted string not closed ...
+ sUrl = Mid(psString, lUrl, lNextQuote - lUrl)
+ sOutput = sOutput &amp; sPattern &amp; sUrl &amp; &quot;&quot;&quot;&quot;
+ lCurrentChar = lNextQuote + 1
+ bQuote = False
+ bTagEnd = False
+ Do
+ sChar = Mid(psString, lCurrentChar, 1)
+ Select Case sChar
+ Case &quot;&quot;&quot;&quot;
+ bQuote = Not bQuote
+ sOutput = sOutput &amp; sChar
+ Case &quot;&gt;&quot; &apos; Tag end if not somewhere between quotes
+ If Not bQuote Then
+ bTagEnd = True
+ sOutput = sOutput &amp; sChar
+ Else
+ sOutput = sOutput &amp; _UTF8Encode(sChar)
+ End If
+ Case Else
+ sOutput = sOutput &amp; _UTF8Encode(sChar)
+ End Select
+ lCurrentChar = lCurrentChar + 1
+ If lCurrentChar &gt; Len(psString) Then bTagEnd = True &apos; Should not happen but, if tag not closed ...
+ Loop Until bTagEnd
+ Case Else
+ sOutput = sOutput &amp; sPattern
+ lCurrentChar = lPattern + Len(sPattern)
+ End Select
+ Else
+ lCurrentChar = Len(psString) + 1
+ End If
+ Loop
+
+ _OutputStringToHTML = sOutput
+
+End Function &apos; _OutputStringToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OutputToCalc(poData As Object _
+ , ByVal psOutputFile As String _
+ , ByVal psFilter As String _
+ , Optional ByVal plEncoding As Long _
+ ) As Boolean
+&apos; https://wiki.documentfoundation.org/Documentation/DevGuide/Spreadsheet_Documents#Database_Import
+&apos; https://wiki.documentfoundation.org/Documentation/DevGuide/Spreadsheet_Documents#Filter_Options
+
+Dim oCalcDoc As Object, oSheet As Object, vWin As Variant
+Dim vImportDesc() As Variant, iSource As Integer
+Dim oRange As Object, i As Integer, iCol As Integer, oColumns As Object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _OutputToCalc = False
+ If IsMissing(plEncoding) Then plEncoding = acUTF8Encoding
+ &apos; Create a new OO-Calc-Document
+ Set oCalcDoc = StarDesktop.LoadComponentFromURL( _
+ &quot;private:factory/scalc&quot; _
+ , &quot;_default&quot; ,0, Array() _
+ )
+
+ &apos; Get the unique spreadsheet
+ Set oSheet = oCalcDoc.Sheets(0)
+
+ &apos; Describe import
+ With poData
+ If ._Type = &quot;TABLEDEF&quot; Then
+ iSource = com.sun.star.sheet.DataImportMode.TABLE
+ Else
+ iSource = com.sun.star.sheet.DataImportMode.QUERY
+ End If
+ vImportDesc = Array( _
+ _MakePropertyValue(&quot;DatabaseName&quot;, URL) _
+ , _MakePropertyValue(&quot;SourceType&quot;, iSource) _
+ , _MakePropertyValue(&quot;SourceObject&quot;, ._Name) _
+ )
+ oSheet.Name = ._Name
+ End With
+
+ &apos; Import
+ oSheet.getCellByPosition(0, 0).doImport(vImportDesc())
+
+ Select Case psFilter
+ Case acFormatODS, acFormatXLS, acFormatXLSX &apos; Formatting
+ iCol = poData.Fields().Count
+ Set oRange = oSheet.getCellRangeByPosition(0, 0, iCol - 1, 0)
+ oRange.CharWeight = com.sun.star.awt.FontWeight.BOLD
+ oRange.CellBackColor = RGB(200, 200, 200)
+ oRange.HoriJustify = com.sun.star.table.CellHoriJustify.CENTER
+ Set oColumns = oRange.getColumns()
+ For i = 0 To iCol - 1
+ oColumns.getByIndex(i).OptimalWidth = True
+ Next i
+ oCalcDoc.storeAsUrl(psOutputFile, Array( _
+ _MakePropertyValue(&quot;FilterName&quot;, psFilter) _
+ , _MakePropertyValue(&quot;Overwrite&quot;, True) _
+ ))
+ Case Else
+ oCalcDoc.storeAsUrl(psOutputFile, Array( _
+ _MakePropertyValue(&quot;FilterName&quot;, psFilter) _
+ , _MakePropertyValue(&quot;FilterOptions&quot;, _FilterOptionsDefault(plEncoding)) _
+ , _MakePropertyValue(&quot;Overwrite&quot;, True) _
+ ))
+ End Select
+
+ oCalcDoc.close(False)
+ _OutputToCalc = True
+
+Exit_Function:
+ Set oColumns = Nothing
+ Set oRange = Nothing
+ Set oSheet = Nothing
+ Set oCalcDoc = Nothing
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, ERRDFUNCTION, _A2B_.CalledSub, 0, , sSQL)
+ Goto Exit_Function
+End Function &apos; OutputToCalc V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _OutputToHTML(ByRef pvTable As Variant, ByVal pvName As String, ByVal psOutputFile As String, ByVal psTemplateFile As String _
+ , ByRef Optional pvHeaders As Variant _
+ , ByRef Optional pvData As Variant _
+ ) As Boolean
+&apos; http://www.ehow.com/how_5652706_create-html-template-ms-access.html
+
+Dim bDataArray As Boolean
+Dim vMinimalTemplate As Variant, vTemplate As Variant
+Dim iFile As Integer, i As Integer, sLine As String, lBody As Long
+Const cstTitle = &quot;&lt;!--Template_Title--&gt;&quot;, cstBody = &quot;&lt;!--Template_Body--&gt;&quot;
+Const cstTitleAlt = &quot;&lt;!--AccessTemplate_Title--&gt;&quot;, cstBodyAlt = &quot;&lt;!--AccessTemplate_Body--&gt;&quot;
+
+ On Local Error GoTo Error_Function
+ vMinimalTemplate = Array( _
+ &quot;&lt;!DOCTYPE html&gt;&quot; _
+ , &quot;&lt;html&gt;&quot; _
+ , &quot; &lt;head&gt;&quot; _
+ , &quot; &lt;title&gt;&quot; &amp; cstTitle &amp; &quot;&lt;/title&gt;&quot; _
+ , &quot; &lt;/head&gt;&quot; _
+ , &quot; &lt;body&gt;&quot; _
+ , &quot; &quot; &amp; cstBody _
+ , &quot; &lt;/body&gt;&quot; _
+ , &quot;&lt;/html&gt;&quot; _
+ )
+
+ vTemplate = _ReadFileIntoArray(psTemplateFile)
+ If LBound(vTemplate) &gt; UBound(vTemplate) Then vTemplate() = vMinimalTemplate()
+
+ bDataArray = IsNull(pvTable)
+
+&apos; Write output file
+ iFile = FreeFile()
+ Open psOutputFile For Output Access Write Lock Read Write As #iFile
+ For i = 0 To UBound(vTemplate)
+ sLine = vTemplate(i)
+ sLine = Join(Split(sLine, cstTitleAlt), cstTitle)
+ sLine = Join(Split(sLine, cstBodyAlt), cstBody)
+ Select Case True
+ Case InStr(sLine, cstTitle) &gt; 0
+ sLine = Join(Split(sLine, cstTitle), pvName)
+ Print #iFile, sLine
+ Case InStr(sLine, cstBody) &gt; 0
+ lBody = InStr(sLine, cstBody)
+ If lBody &gt; 1 Then Print #iFile, Left(sLine, lBody - 1)
+ If bDataArray Then
+ _OutputDataToHTML(pvTable, pvName, iFile, pvHeaders, pvData)
+ Else
+ _OutputDataToHTML(pvTable, pvName, iFile)
+ End If
+ If Len(sLine) &gt; lBody + Len(cstBody) - 1 Then Print #iFile, Right(sLine, Len(sLine) - lBody + Len(cstBody) + 1)
+ Case Else
+ Print #iFile, sLine
+ End Select
+ Next i
+ Close #iFile
+
+ _OutputToHTML = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ _OutputToHTML = False
+ GoTo Exit_Function
+End Function &apos; _OutputToHTML V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ _PropertiesList = Array(&quot;Connect&quot;, &quot;Name&quot;, &quot;ObjectType&quot; _
+ , &quot;OnCreate&quot;, &quot;OnFocus&quot;, &quot;OnLoad&quot;, &quot;OnLoadFinished&quot;, &quot;OnModifyChanged&quot; _
+ , &quot;OnNew&quot;, &quot;OnPrepareUnload&quot;, &quot;OnPrepareViewClosing&quot;, &quot;OnSave&quot;, &quot;OnSaveAs&quot; _
+ , &quot;OnSaveAsDone&quot;, &quot;OnSaveAsFailed&quot;, &quot;OnSaveDone&quot;, &quot;OnSaveFailed&quot;, &quot;OnSaveTo&quot; _
+ , &quot;OnSaveToDone&quot;, &quot;OnSaveToFailed&quot;, &quot;OnSubComponentClosed&quot;, &quot;OnSubComponentOpened&quot; _
+ , &quot;OnTitleChanged&quot;, &quot;OnUnfocus&quot;, &quot;OnUnload&quot;, &quot;OnViewClosed&quot;, &quot;OnViewCreated&quot; _
+ , &quot;Version&quot; _
+ )
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+Dim i As Integer, vEvents As Variant, sEvent As String, vEvent As Variant
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Database.get&quot; &amp; psProperty)
+
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Connect&quot;)
+ If IsNull(Document) Then _PropertyGet = &quot;&quot; Else _PropertyGet = Document.Datasource.URL
+ &apos; Location = ConvertFromUrl(URL)
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = Title
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;OnCreate&quot;), UCase(&quot;OnFocus&quot;), UCase(&quot;OnLoad&quot;), UCase(&quot;OnLoadFinished&quot;), UCase(&quot;OnModifyChanged&quot;) _
+ , UCase(&quot;OnNew&quot;), UCase(&quot;OnPrepareUnload&quot;), UCase(&quot;OnPrepareViewClosing&quot;), UCase(&quot;OnSave&quot;), UCase(&quot;OnSaveAs&quot;) _
+ , UCase(&quot;OnSaveAsDone&quot;), UCase(&quot;OnSaveAsFailed&quot;), UCase(&quot;OnSaveDone&quot;), UCase(&quot;OnSaveFailed&quot;), UCase(&quot;OnSaveTo&quot;) _
+ , UCase(&quot;OnSaveToDone&quot;), UCase(&quot;OnSaveToFailed&quot;), UCase(&quot;OnSubComponentClosed&quot;), UCase(&quot;OnSubComponentOpened&quot;) _
+ , UCase(&quot;OnTitleChanged&quot;), UCase(&quot;OnUnfocus&quot;), UCase(&quot;OnUnload&quot;), UCase(&quot;OnViewClosed&quot;), UCase(&quot;OnViewCreated&quot;)
+ &apos; Find script event
+ sEvent = &quot;&quot;
+ If IsNull(Document) Then vEvents = Array() Else vEvents = Document.getEvents().ElementNames &apos; Returns an array
+ For i = 0 To UBound(vEvents)
+ If UCase(vEvents(i)) = UCase(psProperty) Then
+ sEvent = vEvents(i)
+ Exit For
+ End If
+ Next i
+ If sEvent = &quot;&quot; Then
+ _PropertyGet = &quot;&quot;
+ Else
+ vEvent = Document.getEvents().getByName(sEvent)
+ If IsEmpty(vEvent) Then
+ _PropertyGet = &quot;&quot;
+ ElseIf vEvent(0).Value &lt;&gt; &quot;Script&quot; Then
+ _PropertyGet = &quot;&quot;
+ Else
+ _PropertyGet = vEvent(1).Value
+ End If
+ End If
+ Case UCase(&quot;Version&quot;)
+ _PropertyGet = MetaData.getDatabaseProductName() &amp; &quot; &quot; &amp; MetaData.getDatabaseProductVersion
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Database.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Database._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _ReplaceSquareBrackets(ByVal psSql As String) As String
+&apos; Returns psSql after substitution of [] by quote character
+&apos; [] square brackets in (single) quoted strings not affected
+
+Dim sQuote As String &apos;RDBMS specific quote character
+Dim vSubStrings() As Variant, i As Integer
+Const cstSingleQuote = &quot;&apos;&quot;
+
+ sQuote = MetaData.IdentifierQuoteString
+ If sQuote = &quot; &quot; Then &apos; IdentifierQuoteString returns a space &quot; &quot; if identifier quoting is not supported.
+ _ReplaceSquareBrackets = Trim(psSql)
+ Exit Function
+ End If
+ vSubStrings() = Split(psSql, cstSingleQuote)
+ For i = 0 To UBound(vSubStrings)
+ If (i Mod 2) = 0 Or (i = UBound(vSubStrings)) Then &apos; Only even substrings are parsed for square brackets. Last substring is parsed anyway
+ vSubStrings(i) = Join(Split(vSubStrings(i), &quot;[&quot;), sQuote)
+ vSubStrings(i) = Join(Split(vSubStrings(i), &quot;]&quot;), sQuote)
+ End If
+ Next i
+
+ _ReplaceSquareBrackets = Trim(Join(vSubStrings, cstSingleQuote))
+
+End Function &apos; ReplaceSquareBrackets V1.1.0
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Dialog.xba b/wizards/source/access2base/Dialog.xba
new file mode 100644
index 000000000..69caed33c
--- /dev/null
+++ b/wizards/source/access2base/Dialog.xba
@@ -0,0 +1,818 @@
+<?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="Dialog" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be DIALOG
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _Shortcut As String
+Private _Dialog As Object &apos; com.sun.star.io.XInputStreamProvider
+Private _Storage As String &apos; GLOBAL or DOCUMENT
+Private _Library As String
+Private UnoDialog As Object &apos; com.sun.star.awt.XControl
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJDIALOG
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ Set _Dialog = Nothing
+ _Storage = &quot;&quot;
+ _Library = &quot;&quot;
+ Set UnoDialog = Nothing
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Caption() As Variant
+ Caption = _PropertyGet(&quot;Caption&quot;)
+End Property &apos; Caption (get)
+
+Property Let Caption(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Caption&quot;, pvValue)
+End Property &apos; Caption (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Height() As Variant
+ Height = _PropertyGet(&quot;Height&quot;)
+End Property &apos; Height (get)
+
+Property Let Height(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Height&quot;, pvValue)
+End Property &apos; Height (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get IsLoaded() As Boolean
+ IsLoaded = _PropertyGet(&quot;IsLoaded&quot;)
+End Property
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnFocusGained() As Variant
+ OnFocusGained = _PropertyGet(&quot;OnFocusGained&quot;)
+End Property &apos; OnFocusGained (get)
+
+Property Let OnFocusGained(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnFocusGained&quot;, pvValue)
+End Property &apos; OnFocusGained (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnFocusLost() As Variant
+ OnFocusLost = _PropertyGet(&quot;OnFocusLost&quot;)
+End Property &apos; OnFocusLost (get)
+
+Property Let OnFocusLost(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnFocusLost&quot;, pvValue)
+End Property &apos; OnFocusLost (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnKeyPressed() As Variant
+ OnKeyPressed = _PropertyGet(&quot;OnKeyPressed&quot;)
+End Property &apos; OnKeyPressed (get)
+
+Property Let OnKeyPressed(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnKeyPressed&quot;, pvValue)
+End Property &apos; OnKeyPressed (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnKeyReleased() As Variant
+ OnKeyReleased = _PropertyGet(&quot;OnKeyReleased&quot;)
+End Property &apos; OnKeyReleased (get)
+
+Property Let OnKeyReleased(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnKeyReleased&quot;, pvValue)
+End Property &apos; OnKeyReleased (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseDragged() As Variant
+ OnMouseDragged = _PropertyGet(&quot;OnMouseDragged&quot;)
+End Property &apos; OnMouseDragged (get)
+
+Property Let OnMouseDragged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseDragged&quot;, pvValue)
+End Property &apos; OnMouseDragged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseEntered() As Variant
+ OnMouseEntered = _PropertyGet(&quot;OnMouseEntered&quot;)
+End Property &apos; OnMouseEntered (get)
+
+Property Let OnMouseEntered(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseEntered&quot;, pvValue)
+End Property &apos; OnMouseEntered (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseExited() As Variant
+ OnMouseExited = _PropertyGet(&quot;OnMouseExited&quot;)
+End Property &apos; OnMouseExited (get)
+
+Property Let OnMouseExited(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseExited&quot;, pvValue)
+End Property &apos; OnMouseExited (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseMoved() As Variant
+ OnMouseMoved = _PropertyGet(&quot;OnMouseMoved&quot;)
+End Property &apos; OnMouseMoved (get)
+
+Property Let OnMouseMoved(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseMoved&quot;, pvValue)
+End Property &apos; OnMouseMoved (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMousePressed() As Variant
+ OnMousePressed = _PropertyGet(&quot;OnMousePressed&quot;)
+End Property &apos; OnMousePressed (get)
+
+Property Let OnMousePressed(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMousePressed&quot;, pvValue)
+End Property &apos; OnMousePressed (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnMouseReleased() As Variant
+ OnMouseReleased = _PropertyGet(&quot;OnMouseReleased&quot;)
+End Property &apos; OnMouseReleased (get)
+
+Property Let OnMouseReleased(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnMouseReleased&quot;, pvValue)
+End Property &apos; OnMouseReleased (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OptionGroup(ByVal Optional pvGroupName As Variant) As Variant
+&apos; Return either an error or an object of type OPTIONGROUP based on its name
+&apos; A group is determined by the successive TabIndexes of the radio button
+&apos; The name of the group = the name of its first element
+
+ Utils._SetCalledSub(&quot;Dialog.OptionGroup&quot;)
+ If IsMissing(pvGroupName) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Set OptionGroup = Nothing
+ If Not Utils._CheckArgument(pvGroupName, 1, vbString) Then Goto Exit_Function
+
+Dim iAllCount As Integer, iRadioLast As Integer, iGroupCount As Integer, iBegin As Integer, iEnd As Integer
+Dim oRadios() As Object, sGroupName As String
+Dim i As Integer, j As Integer, bFound As Boolean, ocControl As Object, oRadio As Object, iTabIndex As Integer
+Dim ogGroup As Object, vGroup() As Variant, vIndex() As Variant
+ iAllCount = Controls.Count
+ If iAllCount &gt; 0 Then
+ iRadioLast = -1
+ ReDim oRadios(0 To iAllCount - 1)
+ For i = 0 To iAllCount - 1 &apos; Store all RadioButtons objects
+ Set ocControl = Controls(i)
+ If ocControl._SubType = CTLRADIOBUTTON Then
+ iRadioLast = iRadioLast + 1
+ Set oRadios(iRadioLast) = ocControl
+ End If
+ Next i
+ Else
+ Goto Error_Arg &apos; No control in dialog
+ End If
+
+ If iRadioLast &lt; 0 then Goto Error_Arg &apos; No radio buttons in the dialog
+
+ &apos;Resort oRadio array based on tab indexes
+ If iRadioLast &gt; 0 Then
+ For i = 0 To iRadioLast - 1 &apos; Bubble sort
+ For j = i + 1 To iRadioLast
+ If oRadios(i).TabIndex &gt; oRadios(j).TabIndex Then
+ Set oRadio = oRadios(i)
+ Set oRadios(i) = oRadios(j)
+ Set oRadios(j) = oRadio
+ End If
+ Next j
+ Next i
+ End If
+
+ &apos;Scan Names to find match with argument
+ bFound = False
+ For i = 0 To iRadioLast
+ If UCase(oRadios(i)._Name) = UCase(pvGroupName) Then
+ Select Case i
+ Case 0 : bFound = True
+ Case Else
+ If oRadios(i).TabIndex &gt; oRadios(i - 1).TabIndex + 1 Then
+ bFound = True
+ Else
+ Goto Error_Arg &apos; same group as preceding item although name correct
+ End If
+ End Select
+ If bFound Then
+ iBegin = i
+ iEnd = i
+ sGroupName = oRadios(i)._Name
+ End If
+ ElseIf bFound Then
+ If oRadios(i).TabIndex = oRadios(i - 1).TabIndex + 1 Then iEnd = i
+ End If
+ Next i
+
+ If bFound Then &apos; Create OptionGroup
+ iGroupCount = iEnd - iBegin + 1
+ Set ogGroup = New OptionGroup
+ ReDim vGroup(0 To iGroupCount - 1)
+ ReDim vIndex(0 To iGroupCount - 1)
+ With ogGroup
+ ._This = ogGroup
+ ._Name = sGroupName
+ ._Count = iGroupCount
+ ._ButtonsGroup = vGroup
+ ._ButtonsIndex = vIndex
+ For i = 0 To iGroupCount - 1
+ Set ._ButtonsGroup(i) = oRadios(iBegin + i).ControlModel
+ ._ButtonsIndex(i) = i
+ Next i
+ ._ParentType = CTLPARENTISDIALOG
+ ._ParentComponent = UnoDialog
+ End With
+ Else Goto Error_Arg
+ End If
+
+ Set OptionGroup = ogGroup
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.OptionGroup&quot;)
+ Exit Function
+Error_Arg:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(1, pvGroupName))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog.OptionGroup&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; OptionGroup V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Page() As Variant
+ Page = _PropertyGet(&quot;Page&quot;)
+End Property &apos; Page (get)
+
+Property Let Page(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Page&quot;, pvValue)
+End Property &apos; Page (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Parent() As Object
+ Parent = _Parent
+End Function &apos; Parent (get) V6.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Const cstThisSub = &quot;Dialog.Properties&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Visible() As Variant
+ Visible = _PropertyGet(&quot;Visible&quot;)
+End Property &apos; Visible (get)
+
+Property Let Visible(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Visible&quot;, pvValue)
+End Property &apos; Visible (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Width() As Variant
+ Width = _PropertyGet(&quot;Width&quot;)
+End Property &apos; Width (get)
+
+Property Let Width(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Width&quot;, pvValue)
+End Property &apos; Width (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function Controls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Return a Control object with name or index = pvIndex
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Dialog.Controls&quot;)
+
+Dim ocControl As Variant, sParentShortcut As String, iControlCount As Integer
+Dim oCounter As Variant, sControls() As Variant, i As Integer, bFound As Boolean, sIndex As String
+Dim j As Integer
+
+ Set ocControl = Nothing
+ If Not IsLoaded Then Goto Trace_Error_NotOpen
+ Set ocControl = New Control
+ Set ocControl._This = ocControl
+ Set ocControl._Parent = _This
+ ocControl._ParentType = CTLPARENTISDIALOG
+ sParentShortcut = _Shortcut
+ sControls() = UnoDialog.Model.getElementNames()
+ iControlCount = UBound(sControls) + 1
+
+ If IsMissing(pvIndex) Then &apos; No argument, return Collection object
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLCONTROLS
+ oCounter._Count = iControlCount
+ Set oCounter._Parent = _This
+ Set Controls = oCounter
+ Goto Exit_Function
+ End If
+
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+
+ &apos; Start building the ocControl object
+ &apos; Determine exact name
+
+ Select Case VarType(pvIndex)
+ Case vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal
+ If pvIndex &lt; 0 Or pvIndex &gt; iControlCount - 1 Then Goto Trace_Error_Index
+ ocControl._Name = sControls(pvIndex)
+ Case vbString &apos; Check control name validity (non case sensitive)
+ bFound = False
+ sIndex = UCase(Utils._Trim(pvIndex))
+ For i = 0 To iControlCount - 1
+ If UCase(sControls(i)) = sIndex Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If bFound Then ocControl._Name = sControls(i) Else Goto Trace_NotFound
+ End Select
+
+ ocControl._Shortcut = sParentShortcut &amp; &quot;!&quot; &amp; Utils._Surround(ocControl._Name)
+ Set ocControl.ControlModel = UnoDialog.Model.getByName(ocControl._Name)
+ Set ocControl.ControlView = UnoDialog.getControl(ocControl._Name)
+ ocControl._ImplementationName = ocControl.ControlModel.getImplementationName()
+ ocControl._FormComponent = UnoDialog
+
+ ocControl._Initialize()
+ Set Controls = ocControl
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.Controls&quot;)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(iArg, pvIndex))
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_Error_NotOpen:
+ TraceError(TRACEFATAL, ERRDIALOGNOTSTARTED, Utils._CalledSub(), 0, , _Name)
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERRCONTROLNOTFOUND, Utils._CalledSub(), 0, , Array(pvIndex, pvIndex))
+ Set Controls = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog.Controls&quot;, Erl)
+ Set Controls = Nothing
+ GoTo Exit_Function
+End Function &apos; Controls
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub EndExecute(ByVal Optional pvReturn As Variant)
+&apos; Stop executing the dialog
+
+If _ErrorHandler() Then On Local Error Goto Error_Sub
+ Utils._SetCalledSub(&quot;Dialog.endExecute&quot;)
+
+ If IsMissing(pvReturn) Then pvReturn = 0
+ If Not Utils._CheckArgument(pvReturn, 1, Utils._AddNumeric(), , False) Then Goto Trace_Error
+
+Dim lExecute As Long
+ lExecute = CLng(pvReturn)
+ If IsNull(_Dialog) Then Goto Error_Execute
+ If IsNull(UnoDialog) Then Goto Error_Not_Started
+ Call UnoDialog.endDialog(lExecute)
+
+Exit_Sub:
+ Utils._ResetCalledSub(&quot;Dialog.endExecute&quot;)
+ Exit Sub
+Trace_Error:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(&quot;1&quot;, Utils._CStr(pvReturn)))
+ Goto Exit_Sub
+Error_Execute:
+ TraceError(TRACEFATAL, ERRDIALOGUNDEFINED, Utils._CalledSub(), 0)
+ Goto Exit_Sub
+Error_Not_Started:
+ TraceError(TRACEWARNING, ERRDIALOGNOTSTARTED, Utils._CalledSub(), 0, 1, _Name)
+ Goto Exit_Sub
+Error_Sub:
+ TraceError(TRACEABORT, Err, &quot;Dialog.endExecute&quot;, Erl)
+ GoTo Exit_Sub
+End Sub &apos; EndExecute
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Execute() As Long
+&apos; Execute dialog
+
+&apos;If _ErrorHandler() Then On Local Error Goto Error_Function
+&apos;Seems smart not to trap errors: debugging of dialog events otherwise made very difficult !
+ Utils._SetCalledSub(&quot;Dialog.Execute&quot;)
+
+Dim lExecute As Long
+ If IsNull(_Dialog) Then Goto Error_Execute
+ If IsNull(UnoDialog) Then Goto Error_Not_Started
+ lExecute = UnoDialog.execute()
+
+ Select Case lExecute
+ Case 1 : Execute = dlgOK
+ Case 0 : Execute = dlgCancel
+ Case Else : Execute = lExecute
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.Execute&quot;)
+ Exit Function
+Error_Execute:
+ TraceError(TRACEFATAL, ERRDIALOGUNDEFINED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Not_Started:
+ TraceError(TRACEWARNING, ERRDIALOGNOTSTARTED, Utils._CalledSub(), 0, 1, _Name)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog.Execute&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Execute
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Dialog.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;Dialog.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Move( ByVal Optional pvLeft As Variant _
+ , ByVal Optional pvTop As Variant _
+ , ByVal Optional pvWidth As Variant _
+ , ByVal Optional pvHeight As Variant _
+ ) As Variant
+&apos; Execute Move method
+ Utils._SetCalledSub(&quot;Dialog.Move&quot;)
+ On Local Error Goto Error_Function
+ Move = False
+Dim iArgNr As Integer
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;Move&quot;) : iArgNr = 1
+ Case UCase(&quot;Dialog.Move&quot;) : iArgNr = 0
+ End Select
+ If IsMissing(pvLeft) Then pvLeft = -1
+ If IsMissing(pvTop) Then pvTop = -1
+ If IsMissing(pvWidth) Then pvWidth = -1
+ If IsMissing(pvHeight) Then pvHeight = -1
+ If Not Utils._CheckArgument(pvLeft, iArgNr + 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvTop, iArgNr + 2, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWidth, iArgNr + 3, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvHeight, iArgNr + 4, Utils._AddNumeric()) Then Goto Exit_Function
+
+Dim iArg As Integer, iWrong As Integer &apos; Check arguments values
+ iArg = 0
+ If pvHeight &lt; -1 Then
+ iArg = 4 : iWrong = pvHeight
+ ElseIf pvWidth &lt; -1 Then
+ iArg = 3 : iWrong = pvWidth
+ ElseIf pvTop &lt; -1 Then
+ iArg = 2 : iWrong = pvTop
+ ElseIf pvLeft &lt; -1 Then
+ iArg = 1 : iWrong = pvLeft
+ End If
+ If iArg &gt; 0 Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(iArgNr + iArg, iWrong))
+ Goto Exit_Function
+ End If
+
+Dim iPosSize As Integer
+ iPosSize = 0
+ If pvLeft &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.X
+ If pvTop &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.Y
+ If pvWidth &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.WIDTH
+ If pvHeight &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.HEIGHT
+ If iPosSize &gt; 0 Then UnoDialog.setPosSize(pvLeft, pvTop, pvWidth, pvHeight, iPosSize)
+ Move = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.Move&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog.Move&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Move
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;Dialog.setProperty&quot;)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(&quot;Dialog.setProperty&quot;)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Start() As Boolean
+&apos; Create dialog
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Dialog.Start&quot;)
+
+Dim oStart As Object
+ Start = False
+ If IsNull(_Dialog) Then Goto Error_Start
+ If Not IsNull(UnoDialog) Then Goto Error_Yet_Started
+ Set oStart = CreateUnoDialog(_Dialog)
+ If IsNull(oStart) Then
+ Goto Error_Start
+ Else
+ Start = True
+ Set UnoDialog = oStart
+ With _A2B_
+ If .hasItem(COLLALLDIALOGS, _Name) Then .Dialogs.Remove(_Name) &apos; Inserted to solve errors, when aborts between start and terminate
+ .Dialogs.Add(UnoDialog, UCase(_Name))
+ End With
+ End If
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.Start&quot;)
+ Exit Function
+Error_Start:
+ TraceError(TRACEFATAL, ERRDIALOGUNDEFINED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Yet_Started:
+ TraceError(TRACEWARNING, ERRDIALOGSTARTED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog.Start&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Start
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Terminate() As Boolean
+&apos; Close dialog
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Dialog.Terminate&quot;)
+
+ Terminate = False
+ If IsNull(_Dialog) Then Goto Error_Terminate
+ If IsNull(UnoDialog) Then Goto Error_Not_Started
+ UnoDialog.Dispose()
+ Set UnoDialog = Nothing
+ _A2B_.Dialogs.Remove(_Name)
+ Terminate = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.Terminate&quot;)
+ Exit Function
+Error_Terminate:
+ TraceError(TRACEFATAL, ERRDIALOGUNDEFINED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Not_Started:
+ TraceError(TRACEWARNING, ERRDIALOGNOTSTARTED, Utils._CalledSub(), 0, 1, _Name)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog.Terminate&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Terminate
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetListener(ByVal psProperty As String) As String
+&apos; Return the X...Listener corresponding with the property in argument
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;)
+ _GetListener = &quot;XFocusListener&quot;
+ Case UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;)
+ _GetListener = &quot;XKeyListener&quot;
+ Case UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseMoved&quot;)
+ _GetListener = &quot;XMouseMotionListener&quot;
+ Case UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ _GetListener = &quot;XMouseListener&quot;
+ End Select
+
+End Function &apos; _GetListener V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ If IsLoaded Then
+ _PropertiesList = Array(&quot;Caption&quot;, &quot;Height&quot;, &quot;IsLoaded&quot;, &quot;Name&quot; _
+ , &quot;OnFocusGained&quot;, &quot;OnFocusLost&quot;, &quot;OnKeyPressed&quot;, &quot;OnKeyReleased&quot;, &quot;OnMouseDragged&quot; _
+ , &quot;OnMouseEntered&quot;, &quot;OnMouseExited&quot;, &quot;OnMouseMoved&quot;, &quot;OnMousePressed&quot;, &quot;OnMouseReleased&quot; _
+ , &quot;ObjectType&quot;, &quot;Page&quot;, &quot;Visible&quot;, &quot;Width&quot; _
+ )
+ Else
+ _PropertiesList = Array(&quot;IsLoaded&quot;, &quot;Name&quot; _
+ )
+ End If
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Dialog.get&quot; &amp; psProperty)
+
+Dim oDialogEvents As Object, sEventName As String
+
+&apos;Execute
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Name&quot;), UCase(&quot;IsLoaded&quot;)
+ Case Else
+ If IsNull(UnoDialog) Then Goto Trace_Error_Dialog
+ End Select
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Caption&quot;)
+ _PropertyGet = UnoDialog.getTitle()
+ Case UCase(&quot;Height&quot;)
+ _PropertyGet = UnoDialog.getPosSize().Height
+ Case UCase(&quot;IsLoaded&quot;)
+ _PropertyGet = _A2B_.hasItem(COLLALLDIALOGS, _Name)
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ Set oDialogEvents = unoDialog.Model.getEvents()
+ sEventName = &quot;com.sun.star.awt.&quot; &amp; _GetListener(psProperty) &amp; &quot;::&quot; &amp; Utils._GetEventName(psProperty)
+ If oDialogEvents.hasByName(sEventName) Then
+ _PropertyGet = oDialogEvents.getByName(sEventName).ScriptCode
+ Else
+ _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;Page&quot;)
+ _PropertyGet = UnoDialog.Model.Step
+ Case UCase(&quot;Visible&quot;)
+ _PropertyGet = UnoDialog.IsVisible()
+ Case UCase(&quot;Width&quot;)
+ _PropertyGet = UnoDialog.getPosSize().Width
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Error_Dialog:
+ TraceError(TRACEFATAL, ERRDIALOGNOTSTARTED, Utils._CalledSub(), 0, 1, _Name)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+
+ Utils._SetCalledSub(&quot;Dialog.set&quot; &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _PropertySet = True
+
+Dim oDialogEvents As Object, sEventName As String, oEvent As Object, sListener As String, sEvent As String
+
+&apos;Execute
+Dim iArgNr As Integer
+
+ If _IsLeft(_A2B_.CalledSub, &quot;Dialog.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ If IsNull(UnoDialog) Then Goto Trace_Error_Dialog
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Caption&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ UnoDialog.setTitle(pvValue)
+ Case UCase(&quot;Height&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ UnoDialog.setPosSize(0, 0, 0, pvValue, com.sun.star.awt.PosSize.HEIGHT)
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If Not Utils._RegisterDialogEventScript(UnoDialog.Model _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue _
+ ) Then GoTo Trace_Error_Dialog
+ Case UCase(&quot;Page&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Then Goto Trace_Error_Value
+ UnoDialog.Model.Step = pvValue
+ Case UCase(&quot;Visible&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ UnoDialog.setVisible(pvValue)
+ Case UCase(&quot;Width&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric()) Then Goto Trace_Error_Value
+ UnoDialog.setPosSize(0, 0, pvValue, 0, com.sun.star.awt.PosSize.WIDTH)
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Dialog.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error_Dialog:
+ TraceError(TRACEFATAL, ERRDIALOGNOTSTARTED, Utils._CalledSub(), 0, 1, _Name)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Dialog._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/DoCmd.xba b/wizards/source/access2base/DoCmd.xba
new file mode 100644
index 000000000..ded67fe59
--- /dev/null
+++ b/wizards/source/access2base/DoCmd.xba
@@ -0,0 +1,2662 @@
+<?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="DoCmd" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+Type _FindParams
+ FindRecord As Integer &apos; Set to 1 at first invocation of FindRecord
+ FindWhat As Variant
+ Match As Integer
+ MatchCase As Boolean
+ Search As Integer
+ SearchAsFormatted As Boolean &apos; Must be False
+ FindFirst As Boolean
+ OnlyCurrentField As Integer
+ Form As String &apos; Shortcut
+ GridControl As String &apos; Shortcut
+ Target As String &apos; Shortcut
+ LastRow As Long &apos; Last row explored - 0 = before first
+ LastColumn As Integer &apos; Last column explored - 0 ... N-1 index in next arrays; 0 if OnlyCurrentField = acCurrent
+ ColumnNames() As String &apos; Array of column names in grid with boundfield and of same type as FindWhat
+ ResultSetIndex() As Integer &apos; Array of column numbers in ResultSet
+End Type
+
+Type _Window
+ Frame As Object &apos; com.sun.star.comp.framework.Frame
+ _Name As String &apos; Object Name
+ WindowType As Integer &apos; One of the object types
+ DocumentType As String &apos; Writer, Calc, ... - Only if WindowType = acDocument
+End Type
+
+REM VBA allows call to actions with missing arguments e.g. OpenForm(&quot;aaa&quot;,,&quot;[field]=2&quot;)
+REM in StarBasic IsMissing requires Variant parameters
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ApplyFilter( _
+ ByVal Optional pvFilter As Variant _
+ , ByVal Optional pvSQL As Variant _
+ , ByVal Optional pvControlName As Variant _
+ ) As Boolean
+&apos; Set filter on open table, query, form or subform (if pvControlName present)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;ApplyFilter&quot;
+ Utils._SetCalledSub(cstThisSub)
+ ApplyFilter = False
+
+ If IsMissing(pvFilter) And IsMissing(pvSQL) Then Call _TraceArguments()
+ If IsMissing(pvFilter) Then pvFilter = &quot;&quot;
+ If Not Utils._CheckArgument(pvFilter, 1, vbString) Then Goto Exit_Function
+ If IsMissing(pvSQL) Then pvSQL = &quot;&quot;
+ If Not Utils._CheckArgument(pvSQL, 1, vbString) Then Goto Exit_Function
+ If IsMissing(pvControlName) Then pvControlName = &quot;&quot;
+ If Not Utils._CheckArgument(pvControlName, 1, vbString) Then Goto Exit_Function
+
+Dim sFilter As String, oWindow As Object, oDatabase As Object, oTarget As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+ If pvSQL &lt;&gt; &quot;&quot; _
+ Then sFilter = oDatabase._ReplaceSquareBrackets(pvSQL) _
+ Else sFilter = oDatabase._ReplaceSquareBrackets(pvFilter)
+
+ Set oWindow = _SelectWindow()
+ With oWindow
+ Select Case .WindowType
+ Case acForm
+ Set oTarget = _DatabaseForm(._Name, pvControlName)
+ Case acQuery, acTable
+ If pvControlName &lt;&gt; &quot;&quot; Then Goto Exit_Function
+ If IsNull(.Frame.Controller.FormOperations) Then Goto Error_NotApplicable
+ &apos; FormOperations returns &lt;Null&gt; in OpenOffice
+ Set oTarget = .Frame.Controller.FormOperations.Cursor
+ Case Else &apos; Ignore action
+ Goto Exit_Function
+ End Select
+ End With
+
+ With oTarget
+ .Filter = sFilter
+ .ApplyFilter = True
+ .reload()
+ End With
+ ApplyFilter = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; ApplyFilter V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function mClose(Optional ByVal pvObjectType As Variant _
+ , Optional ByVal pvObjectName As Variant _
+ , Optional ByVal pvSave As Variant _
+ ) As Boolean
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Const cstThisSub = &quot;Close&quot;
+ Utils._SetCalledSub(cstThisSub)
+ mClose = False
+ If IsMissing(pvObjectType) Or IsMissing(pvObjectName) Then Call _TraceArguments()
+ If IsMissing(pvSave) Then pvSave = acSavePrompt
+ If Not (Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), _
+ Array(acTable, acQuery, acForm, acReport)) _
+ And Utils._CheckArgument(pvObjectName, 2, vbString) _
+ And Utils._CheckArgument(pvSave, 3, Utils._AddNumeric(), Array(acSavePrompt)) _
+ ) Then Goto Exit_Function
+
+Dim sObjects() As String, sObjectName As String, oController As Object, oObject As Object
+Dim i As Integer, bFound As Boolean, lComponent As Long
+Dim oDatabase As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ Select Case pvObjectType
+ Case acForm
+ sObjects = Application._GetAllHierarchicalNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.FORM
+ Case acTable
+ sObjects = oDatabase.Connection.getTables.ElementNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.TABLE
+ Case acQuery
+ sObjects = oDatabase.Connection.getQueries.ElementNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.QUERY
+ Case acReport
+ sObjects = oDatabase.Document.getReportDocuments.ElementNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.REPORT
+ End Select
+ bFound = False
+ For i = 0 To UBound(sObjects)
+ If UCase(pvObjectName) = UCase(sObjects(i)) Then
+ sObjectName = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+
+ Select Case pvObjectType
+ Case acForm
+ Set oController = oDatabase.Document.getFormDocuments.getByHierarchicalName(sObjectName)
+ mClose = oController.close()
+ Case acTable, acQuery &apos; Not optimal but it works !!
+ Set oController = oDatabase.Document.CurrentController
+ Set oObject = oController.loadComponent(lComponent, sObjectName, False)
+ oObject.frame.close(False)
+ mClose = True
+ Case acReport
+ Set oController = oDatabase.Document.getReportDocuments.getByName(sObjectName)
+ mClose = oController.close()
+ End Select
+
+
+Exit_Function:
+ Set oObject = Nothing
+ Set oController = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Close&quot;, Erl)
+ GoTo Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRCLOSEOBJECT, Utils._CalledSub(), 0, , Array(_GetLabel(Array(&quot;Table&quot;, &quot;Query&quot;, &quot;Form&quot;, &quot;Report&quot;)(pvObjectType)), pvObjectName))
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(Array(&quot;Table&quot;, &quot;Query&quot;, &quot;Form&quot;, &quot;Report&quot;)(pvObjectType)), pvObjectName))
+ Goto Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+End Function &apos; (m)Close V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CopyObject(ByVal Optional pvSourceDatabase As Variant _
+ , ByVal Optional pvNewName As Variant _
+ , ByVal Optional pvSourceType As Variant _
+ , ByVal Optional pvSourceName As Variant _
+ ) As Boolean
+&apos; Copies tables and queries into identical (new) objects
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;CopyObject&quot;
+ Utils._SetCalledSub(cstThisSub)
+ CopyObject = False
+
+ If IsMissing(pvSourceDatabase) Then pvSourceDatabase = &quot;&quot;
+ If VarType(pvSourceDatabase) &lt;&gt; vbString Then
+ If Not Utils._CheckArgument(pvSourceDatabase, 1, OBJDATABASE) Then Goto Exit_Function
+ End If
+ If IsMissing(pvNewName) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvNewName, 2, vbString) Then Goto Exit_Function
+ If IsMissing(pvSourceType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSourceType, 1, Utils._AddNumeric(), Array(acQuery, acTable) _
+ ) Then Goto Exit_Function
+ If IsMissing(pvSourceName) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSourceName, 2, vbString) Then Goto Exit_Function
+
+Dim oSource As Object, oSourceDatabase As Object, oTarget As Object, oDatabase As Object, bSameDatabase As Boolean
+Dim oSourceTable As Object, oSourceColumns As Object, oSourceCol As Object, oTargetCol As Object, iRDBMS As Integer
+Dim oSourceKeys As Object, oSourceKey As Object, oTargetKey As Object
+Dim i As Integer, j As Integer, sSql As String, vPrimaryKeys() As Variant
+Dim vNameComponents() As Variant, iNames As Integer, sSurround As String
+Dim vInputField As Variant, vFieldBinary() As Variant, vOutputField As Variant
+Dim oInput as Object, oOutput As Object, iNbFields As Integer, vValue As Variant
+Dim vBinary As Variant, lInputSize As Long, lOutputSize As Long
+Dim lInputRecs As Long, lInputMax As Long, vField As Variant, bProgressMeter As Boolean, sFile As String
+
+Const cstMaxBinlength = 2 * 65535
+Const cstChunkSize = 2 * 65535
+Const cstProgressMeterLimit = 100
+
+ Set oDatabase = Application._CurrentDb()
+ bSameDatabase = False
+ If VarType(pvSourceDatabase) = vbString Then
+ If pvSourceDatabase = &quot;&quot; Then
+ Set oSourceDatabase = oDatabase
+ bSameDatabase = True
+ Else
+ Set oSourceDatabase = Application.OpenDatabase(ConvertToUrl(pvSourceDatabase), &quot;&quot;, &quot;&quot;, True)
+ If IsNull(oSourceDatabase) Then Goto Exit_Function
+ End If
+ Else
+ Set oSourceDatabase = pvSourceDatabase
+ End If
+
+ With oDatabase
+ iRDBMS = ._RDBMS
+ If ._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ Select Case pvSourceType
+
+ Case acQuery
+ Set oSource = oSourceDatabase.QueryDefs(pvSourceName, True)
+ If IsNull(oSource) Then Goto Error_NotFound
+ Set oTarget = .QueryDefs(pvNewName, True)
+ If Not IsNull(oTarget) Then .Connection.getQueries.dropByName(oTarget.Name) &apos; a query with same name exists already ... drop it
+ If oSource.Query.EscapeProcessing Then
+ Set oTarget = .CreateQueryDef(pvNewName, oSource.SQL)
+ Else
+ Set oTarget = .CreateQueryDef(pvNewName, oSource.SQL, dbSQLPassThrough)
+ End If
+ &apos; Save .odb document
+ .Document.store()
+
+ Case acTable
+ Set oSource = oSourceDatabase.TableDefs(pvSourceName, True)
+ If IsNull(oSource) Then Goto Error_NotFound
+ Set oTarget = .TableDefs(pvNewName, True)
+ &apos; A table with same name exists already ... drop it
+ If Not IsNull(oTarget) Then .Connection.getTables.dropByName(oTarget.Name)
+ &apos; Copy source table columns
+ Set oSourceTable = oSource.Table
+ Set oTarget = .Connection.getTables.createDataDescriptor
+ oTarget.Description = oSourceTable.Description
+ vNameComponents = Split(pvNewName, &quot;.&quot;)
+ iNames = UBound(vNameComponents)
+ If iNames &gt;= 2 Then oTarget.CatalogName = vNameComponents(iNames - 2) Else oTarget.CatalogName = &quot;&quot;
+ If iNames &gt;= 1 Then oTarget.SchemaName = vNameComponents(iNames - 1) Else oTarget.SchemaName = &quot;&quot;
+ oTarget.Name = vNameComponents(iNames)
+ oTarget.Type = oSourceTable.Type
+ Set oSourceColumns = oSourceTable.Columns
+ Set oTargetCol = oTarget.Columns.createDataDescriptor
+ For i = 0 To oSourceColumns.getCount() - 1
+ &apos; Append each individual column to the table descriptor
+ Set oSourceCol = oSourceColumns.getByIndex(i)
+ _ConvertDataDescriptor oSourceCol, oSourceDatabase._RDBMS, oTargetCol, oDatabase
+ oTarget.Columns.appendByDescriptor(oTargetCol)
+ Next i
+
+ &apos; Copy keys
+ Set oSourceKeys = oSourceTable.Keys
+ Set oTargetKey = oTarget.Keys.createDataDescriptor()
+ For i = 0 To oSourceKeys.getCount() - 1
+ &apos; Append each key to table descriptor
+ Set oSourceKey = oSourceKeys.getByIndex(i)
+ oTargetKey.DeleteRule = oSourceKey.DeleteRule
+ oTargetKey.Name = oSourceKey.Name
+ oTargetKey.ReferencedTable = oSourceKey.ReferencedTable
+ oTargetKey.Type = oSourceKey.Type
+ oTargetKey.UpdateRule = oSourceKey.UpdateRule
+ Set oTargetCol = oTargetKey.Columns.createDataDescriptor()
+ For j = 0 To oSourceKey.Columns.getCount() - 1
+ Set oSourceCol = oSourceKey.Columns.getByIndex(j)
+ _ConvertDataDescriptor oSourceCol, oSourceDatabase._RDBMS, oTargetCol, oDatabase, True
+ oTargetKey.Columns.appendByDescriptor(oTargetCol)
+ Next j
+ oTarget.Keys.appendByDescriptor(oTargetKey)
+ Next i
+ &apos; Duplicate table whole design
+ .Connection.getTables.appendByDescriptor(oTarget)
+
+ &apos; Copy data
+ Select Case bSameDatabase
+ Case True
+ &apos; Build SQL statement to copy data
+ sSurround = Utils._Surround(oSource.Name)
+ sSql = &quot;INSERT INTO &quot; &amp; Utils._Surround(pvNewName) &amp; &quot; SELECT &quot; &amp; sSurround &amp; &quot;.* FROM &quot; &amp; sSurround
+ DoCmd.RunSQL(sSql)
+ Case False
+ &apos; Copy data row by row and field by field
+ &apos; As it is slow ... display a progress meter
+ Set oInput = oSourceDatabase.OpenRecordset(oSource.Name, , , dbReadOnly)
+ Set oOutput = .Openrecordset(pvNewName)
+
+ With oInput
+ If Not ( ._BOF And ._EOF ) Then
+ .MoveLast
+ lInputMax = .RecordCount
+ lInputRecs = 0
+ .MoveFirst
+ bProgressMeter = ( lInputMax &gt; cstProgressMeterLimit )
+
+ iNbFields = .Fields().Count - 1
+ vFieldBinary = Array()
+ ReDim vFieldBinary(0 To iNbFields)
+ For i = 0 To iNbFields
+ vFieldBinary(i) = Utils._IsBinaryType(.Fields(i).Column.Type)
+ Next i
+ Else
+ bProgressMeter = False
+ End If
+ If bProgressMeter Then Application.SysCmd acSysCmdInitMeter, pvNewName &amp; &quot; 0 %&quot;, lInputMax
+ Do While Not .EOF()
+ oOutput.RowSet.moveToInsertRow()
+ oOutput._EditMode = dbEditAdd
+ For i = 0 To iNbFields
+ Set vInputField = .Fields(i)
+ Set vOutputField = oOutput.Fields(i)
+ If vFieldBinary(i) Then
+ lInputSize = vInputField.FieldSize
+ If lInputSize &lt;= cstMaxBinlength Then
+ vField = Utils._getResultSetColumnValue(.RowSet, i + 1, True)
+ Utils._updateResultSetColumnValue(iRDBMS, oOutput.RowSet, i + 1, vField)
+ ElseIf oDatabase._BinaryStream Then
+ &apos; Typically for SQLite where binary fields are limited
+ If lInputSize &gt; vOutputField._Precision Then
+ TraceError(TRACEWARNING, ERRPRECISION, Utils._CalledSub(), 0, 1, Array(vOutputField._Name, lInputRecs + 1))
+ Utils._updateResultSetColumnValue(iRDBMS, oOutput.RowSet, i + 1, Null)
+ Else
+ sFile = Utils._GetRandomFileName(&quot;BINARY&quot;)
+ vInputField._WriteAll(sFile, &quot;WriteAllBytes&quot;)
+ vOutputField._ReadAll(sFile, &quot;ReadAllBytes&quot;)
+ Kill ConvertToUrl(sFile)
+ End If
+ End If
+ Else
+ vField = Utils._getResultSetColumnValue(.RowSet, i + 1)
+ If VarType(vField) = vbString Then
+ If Len(vField) &gt; vOutputField._Precision Then
+ TraceError(TRACEWARNING, ERRPRECISION, Utils._CalledSub(), 0, 1, Array(vOutputField._Name, lInputRecs + 1))
+ End If
+ End If
+ &apos; Update is done anyway, if too long, with truncation
+ Utils._updateResultSetColumnValue(iRDBMS, oOutput.RowSet, i + 1, vField)
+ End If
+ Next i
+
+ If oOutput.RowSet.IsNew And oOutput.RowSet.IsModified Then oOutput.RowSet.insertRow()
+ oOutput._EditMode = dbEditNone
+ lInputRecs = lInputRecs + 1
+ If bProgressMeter Then
+ If lInputRecs Mod (lInputMax / 100) = 0 Then
+ Application.SysCmd acSysCmdUpdateMeter, pvNewName &amp; &quot; &quot; &amp; CStr(CLng(lInputRecs * 100 / lInputMax)) &amp; &quot;%&quot;, lInputRecs
+ End If
+ End If
+ .MoveNext
+ Loop
+ End With
+
+ oOutput.mClose()
+ Set oOutput = Nothing
+ oInput.mClose()
+ Set oInput = Nothing
+ if bProgressMeter Then Application.SysCmd acSysCmdClearStatus
+ End Select
+
+ Case Else
+ End Select
+ End With
+
+ CopyObject = True
+
+Exit_Function:
+ &apos; Avoid closing the current database or the database object given as source argument
+ If VarType(pvSourceDatabase) = vbString And Not bSameDatabase Then
+ If Not IsNull(oSourceDatabase) Then oSourceDatabase.mClose()
+ End If
+ Set oSourceDatabase = Nothing
+ If Not IsNull(oOutput) Then oOutput.mClose()
+ Set oOutput = Nothing
+ If Not IsNull(oInput) Then oInput.mClose()
+ Set oInput = Nothing
+ Set oSourceCol = Nothing
+ Set oSourceKey = Nothing
+ Set oSourceKeys = Nothing
+ Set oSource = Nothing
+ Set oSourceTable = Nothing
+ Set oSourceColumns = Nothing
+ Set oTargetCol = Nothing
+ Set oTargetKey = Nothing
+ Set oTarget = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(Iif(pvSourceType = acQuery, _GetLabel(&quot;QUERY&quot;), _GetLabel(&quot;TABLE&quot;)), pvSourceName))
+ Goto Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; CopyObject V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function FindNext() As Boolean
+&apos; Must be called after a FindRecord
+&apos; Execute instructions set in FindRecord object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ FindNext = False
+ Utils._SetCalledSub(&quot;FindNext&quot;)
+
+Dim ofForm As Object, ocGrid As Object
+Dim i As Integer, lInitialRow As Long, lFindRow As Long
+Dim bFound As Boolean, b2ndRound As Boolean, bStop As Boolean
+Dim vFindValue As Variant, oFindrecord As Object
+
+ Set oFindRecord = _A2B_.FindRecord
+ If IsNull(oFindRecord) Then GoTo Error_FindRecord
+ With oFindRecord
+
+ If .FindRecord = 0 Then Goto Error_FindRecord
+ .FindRecord = 0
+ Set ofForm = getObject(.Form)
+ If ofForm._Type = OBJCONTROL Then Set ofForm = ofForm.Form &apos; Bug Tombola
+ Set ocGrid = getObject(.GridControl)
+
+ &apos; Move cursor to the initial row. Operation based on last FindRecord, not on user interactions done inbetween
+ If ofForm.DatabaseForm.RowCount &lt;= 0 then Goto Exit_Function &apos; Dataset is empty
+
+ lInitialRow = .LastRow &apos; Used if Search = acSearchAll
+
+ bFound = False
+ lFindRow = .LastRow
+ b2ndRound = False
+ Do
+ &apos; Last column ? Go to next row
+ If .LastColumn &gt;= UBound(.ColumnNames) Then
+ bStop = False
+ If ofForm.DatabaseForm.isAfterLast() And .Search = acUp Then
+ ofForm.DatabaseForm.last()
+ ElseIf ofForm.DatabaseForm.isLast() And .Search = acSearchAll Then
+ ofForm.DatabaseForm.first()
+ b2ndRound = True
+ ElseIf ofForm.DatabaseForm.isBeforeFirst() And (.Search = acDown Or .Search = acSearchAll) Then
+ ofForm.DatabaseForm.first()
+ ElseIf ofForm.DatabaseForm.isFirst() And .search = acUp Then
+ ofForm.DatabaseForm.beforeFirst()
+ bStop = True
+ ElseIf ofForm.DatabaseForm.isLast() And .search = acDown Then
+ ofForm.DatabaseForm.afterLast()
+ bStop = True
+ ElseIf .Search = acUp Then
+ ofForm.DatabaseForm.previous()
+ Else
+ ofForm.DatabaseForm.next()
+ End If
+ lFindRow = ofForm.DatabaseForm.getRow()
+ If bStop Or (.Search = acSearchAll And lFindRow &gt;= lInitialRow And b2ndRound) Then
+ ofForm.DatabaseForm.absolute(lInitialRow)
+ Exit Do
+ End If
+ .LastColumn = 0
+ Else
+ .LastColumn = .LastColumn + 1
+ End If
+
+ &apos; Examine column contents
+ If .LastColumn &lt;= UBound(.ColumnNames) Then
+ For i = .LastColumn To UBound(.ColumnNames)
+ vFindValue = Utils._getResultSetColumnValue(ofForm.DatabaseForm.createResultSet(), .ResultSetIndex(i))
+ Select Case VarType(.FindWhat)
+ Case vbDate, vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal
+ bFound = ( .FindWhat = vFindValue )
+ Case vbString
+ If VarType(vFindValue) = vbString Then
+ Select Case .Match
+ Case acStart
+ If .MatchCase Then
+ bFound = ( Left(.FindWhat, Len(.FindWhat)) = vFindValue )
+ Else
+ bFound = ( UCase(Left(.FindWhat, Len(.FindWhat))) = UCase(vFindValue) )
+ End If
+ Case acAnyWhere
+ If .MatchCase Then
+ bFound = ( InStr(1, vFindValue, .FindWhat, 0) &gt; 0 )
+ Else
+ bFound = ( InStr(vFindValue, .FindWhat) &gt; 0 )
+ End If
+ Case acEntire
+ If .MatchCase Then
+ bFound = ( .FindWhat = vFindValue )
+ Else
+ bFound = ( UCase(.FindWhat) = UCase(vFindValue) )
+ End If
+ End Select
+ Else
+ bFound = False
+ End If
+ End Select
+ If bFound Then
+ .LastColumn = i
+ Exit For
+ End If
+ Next i
+ End If
+ Loop While Not bFound
+
+ .LastRow = lFindRow
+ If bFound Then
+ ocGrid.Controls(.ColumnNames(.LastColumn)).setFocus()
+ .FindRecord = 1
+ FindNext = True
+ End If
+
+ End With
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;FindNext&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;FindNext&quot;, Erl)
+ GoTo Exit_Function
+Error_FindRecord:
+ TraceError(TRACEERRORS, ERRFINDRECORD, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; FindNext V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function FindRecord(Optional ByVal pvFindWhat As Variant _
+ , Optional ByVal pvMatch As Variant _
+ , Optional ByVal pvMatchCase As Variant _
+ , Optional ByVal pvSearch As Variant _
+ , Optional ByVal pvSearchAsFormatted As Variant _
+ , Optional ByVal pvTargetedField As Variant _
+ , Optional ByVal pvFindFirst As Variant _
+ ) As Boolean
+
+&apos;Find a value (string or other) in the underlying data of a gridcontrol
+&apos;Search in all columns or only in one single control
+&apos; see pvTargetedField = acAll or acCurrent
+&apos; pvTargetedField may also be a shortcut to a GridControl or one of its subcontrols
+&apos;Initialize _Findrecord structure in Database root and call FindNext() to set cursor on found value
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ FindRecord = False
+
+ Utils._SetCalledSub(&quot;FindRecord&quot;)
+ If IsMissing(pvFindWhat) Or pvFindWhat = &quot;&quot; Then Call _TraceArguments()
+ If IsMissing(pvMatch) Then pvMatch = acEntire
+ If IsMissing(pvMatchCase) Then pvMatchCase = False
+ If IsMissing(pvSearch) Then pvSearch = acSearchAll
+ If IsMissing(pvSearchAsFormatted) Then pvSearchAsFormatted = False &apos; Anyway only False supported
+ If IsMissing(pvTargetedField) Then pvTargetedField = acCurrent
+ If IsMissing(pvFindFirst) Then pvFindFirst = True
+ If Not (Utils._CheckArgument(pvFindWhat, 1, Utils._AddNumeric(Array(vbString, vbDate))) _
+ And Utils._CheckArgument(pvMatch, 2, Utils._AddNumeric(), Array(acAnywhere, acEntire, acStart)) _
+ And Utils._CheckArgument(pvMatchCase, 3, vbBoolean) _
+ And Utils._CheckArgument(pvSearch, 4, Utils._AddNumeric(), Array(acDown, acSearchAll, acUp)) _
+ And Utils._CheckArgument(pvSearchAsFormatted, 5, vbBoolean, Array(False)) _
+ And Utils._CheckArgument(pvTargetedField, 6, Utils._AddNumeric(vbString)) _
+ And Utils._CheckArgument(pvFindFirst, 7, vbBoolean) _
+ ) Then Exit Function
+ If VarType(pvTargetedField) &lt;&gt; vbString Then
+ If Not Utils._CheckArgument(pvTargetedField, 6, Utils._AddNumeric(), Array(acAll, acCurrent)) Then Exit Function
+ End If
+
+Dim ocTarget As Object, i As Integer, j As Integer, vNames() As Variant, iCount As Integer, vIndexes() As Variant
+Dim vColumn As Variant, vDataField As Variant, ofParentForm As Variant, oColumns As Object, vParentGrid As Object
+Dim bFound As Boolean, ocGridControl As Object, iFocus As Integer
+Dim oFindRecord As _FindParams
+ With oFindRecord
+ .FindRecord = 0
+ .FindWhat = pvFindWhat
+ .Match = pvMatch
+ .MatchCase = pvMatchCase
+ .Search = pvSearch
+ .SearchAsFormatted = pvSearchAsFormatted
+ .FindFirst = pvFindFirst
+
+ &apos; Determine target
+ &apos; Either: pvTargetedField = Grid =&gt; search all fields
+ &apos; pvTargetedField = Control in Grid =&gt; search only in that column
+ &apos; pvTargetedField = acAll or acCurrent =&gt; determine focus
+ Select Case True
+
+ Case VarType(pvTargetedField) = vbString
+ Set ocTarget = getObject(pvTargetedField)
+
+ If ocTarget.SubType = CTLGRIDCONTROL Then
+ .OnlyCurrentField = acAll
+ .GridControl = ocTarget._Shortcut
+ .Target = .GridControl
+ ofParentForm = getObject(_getUpperShortcut(ocTarget._Shortcut, ocTarget._Name))
+ If IsNull(ofParentForm.DatabaseForm) Then Goto Error_DatabaseForm
+ Set oColumns = ofParentForm.DatabaseForm.createResultSet().Columns
+ iCount = -1
+ For i = 0 To ocTarget.ControlModel.Count - 1
+ Set vColumn = ocTarget.ControlModel.getByIndex(i)
+ Set vDataField = vColumn.BoundField &apos; examine field type
+ If Not IsNull(vDataField) Then
+ If _CheckColumnType(pvFindWhat, vDataField) Then
+ iCount = iCount + 1
+ ReDim Preserve vNames(0 To iCount)
+ vNames(iCount) = vColumn.Name
+ ReDim Preserve vIndexes(0 To iCount)
+ For j = 0 To oColumns.Count - 1
+ If vDataField.Name = oColumns.ElementNames(j) Then
+ vIndexes(iCount) = j + 1
+ Exit For
+ End If
+ Next j
+ End If
+ End If
+ Next i
+
+ ElseIf ocTarget._Type = OBJCONTROL Then &apos; Control within a grid tbc
+ If IsNull(ocTarget.ControlModel.BoundField) Then Goto Error_Target &apos; Control MUST be bound to a database record or query
+ &apos; BoundField is in ControlModel, thanks PASTIM !
+ .OnlyCurrentField = acCurrent
+ vParentGrid = getObject(_getUpperShortcut(ocTarget._Shortcut, ocTarget._Name))
+ If vParentGrid.SubType &lt;&gt; CTLGRIDCONTROL Then Goto Error_Target
+ .GridControl = vParentGrid._Shortcut
+ ofParentForm = getObject(_getUpperShortcut(vParentGrid._Shortcut, vParentGrid._Name))
+ If ofParentForm._Type = OBJCONTROL Then Set ofParentForm = ofParentForm.Form &apos; Bug Tombola
+ If IsNull(ofParentForm.DatabaseForm) Then Goto Error_DatabaseForm
+ .Target = ocTarget._Shortcut
+ Set vDataField = ocTarget.ControlModel.BoundField
+ If Not _CheckColumnType(pvFindWhat, vDataField) Then Goto Error_Target
+ ReDim vNames(0), vIndexes(0)
+ vNames(0) = ocTarget._Name
+ Set oColumns = ofParentForm.DatabaseForm.createResultSet().Columns
+ For j = 0 To oColumns.Count - 1
+ If vDataField.Name = oColumns.ElementNames(j) Then
+ vIndexes(0) = j + 1
+ Exit For
+ End If
+ Next j
+ End If
+
+ Case Else &apos; Determine focus
+ iCount = Application.Forms()._Count
+ If iCount = 0 Then Goto Error_ActiveForm
+ bFound = False
+ For i = 0 To iCount - 1 &apos; Determine form having the focus
+ Set ofParentForm = Application.Forms(i)
+ If ofParentForm.Component.CurrentController.Frame.IsActive() Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Error_ActiveForm
+ If IsNull(ofParentForm.DatabaseForm) Then Goto Error_DatabaseForm
+ iCount = ofParentForm.Controls().Count
+ bFound = False
+ For i = 0 To iCount - 1
+ Set ocGridControl = ofParentForm.Controls(i)
+ If ocGridControl.SubType = CTLGRIDCONTROL Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Error_NoGrid
+ .GridControl= ocGridControl._Shortcut
+ iFocus = -1
+ iFocus = ocGridControl.ControlView.getCurrentColumnPosition() &apos; Deprecated but no alternative found !!
+
+ If pvTargetedField = acAll Or iFocus &lt; 0 Or iFocus &gt;= ocGridControl.ControlModel.Count Then &apos; Has a control within the grid the focus ? NO
+ .OnlyCurrentField = acAll
+ Set oColumns = ofParentForm.DatabaseForm.createResultSet().Columns
+ iCount = -1
+ For i = 0 To ocGridControl.ControlModel.Count - 1
+ Set vColumn = ocGridControl.ControlModel.getByIndex(i)
+ Set vDataField = vColumn.BoundField &apos; examine field type
+ If Not IsNull(vDataField) Then
+ If _CheckColumnType(pvFindWhat, vDataField) Then
+ iCount = iCount + 1
+ ReDim Preserve vNames(0 To iCount)
+ vNames(iCount) = vColumn.Name
+ ReDim Preserve vIndexes(0 To iCount)
+ For j = 0 To oColumns.Count - 1
+ If vDataField.Name = oColumns.ElementNames(j) Then
+ vIndexes(iCount) = j + 1
+ Exit For
+ End If
+ Next j
+ End If
+ End If
+ Next i
+
+ Else &apos; Has a control within the grid the focus ? YES
+ .OnlyCurrentField = acCurrent
+ Set vColumn = ocGridControl.ControlModel.getByIndex(iFocus)
+ Set ocTarget = ocGridControl.Controls(vColumn.Name)
+ .Target = ocTarget._Shortcut
+ Set vDataField = ocTarget.ControlModel.BoundField
+ If IsNull(vDataField) Then Goto Error_Target &apos; Control MUST be bound to a database record or query
+ If Not _CheckColumnType(pvFindWhat, vDataField) Then Goto Error_Target
+ ReDim vNames(0), vIndexes(0)
+ vNames(0) = ocTarget._Name
+ Set oColumns = ofParentForm.DatabaseForm.createResultSet().Columns
+ For j = 0 To oColumns.Count - 1
+ If vDataField.Name = oColumns.ElementNames(j) Then
+ vIndexes(0) = j + 1
+ Exit For
+ End If
+ Next j
+ End If
+
+ End Select
+
+ .Form = ofParentForm._Shortcut
+ .LastColumn = UBound(vNames)
+ .ColumnNames = vNames
+ .ResultSetIndex = vIndexes
+ If pvFindFirst Then
+ Select Case pvSearch
+ Case acDown, acSearchAll
+ ofParentForm.DatabaseForm.beforeFirst()
+ .LastRow = 0
+ Case acUp
+ ofParentForm.DatabaseForm.afterLast()
+ .LastRow = ofParentForm.DatabaseForm.RowCount + 1
+ End Select
+ Else
+ Select Case True
+ Case ofParentForm.DatabaseForm.isBeforeFirst And (pvSearch = acSearchAll Or pvSearch = acDown)
+ .LastRow = 0
+ Case ofParentForm.DatabaseForm.isAfterLast And pvSearch = acUp
+ ofParentForm.DatabaseForm.last() &apos; RowCount produces a wrong value as long as last record has not been reached
+ .LastRow = ofParentForm.DatabaseForm.RowCount + 1
+ Case Else
+ .LastRow = ofParentForm.DatabaseForm.getRow()
+ End Select
+ End If
+
+ .FindRecord = 1
+
+ End With
+ Set _A2B_.FindRecord = oFindRecord
+ FindRecord = DoCmd.Findnext()
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;FindRecord&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;FindRecord&quot;, Erl)
+ GoTo Exit_Function
+Error_ActiveForm:
+ TraceError(TRACEERRORS, ERRNOACTIVEFORM, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_DatabaseForm:
+ TraceError(TRACEFATAL, ERRDATABASEFORM, Utils._CalledSub(), 0, 1, vParentForm._Name)
+ Goto Exit_Function
+Error_Target:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(6, pvTargetedField))
+ Goto Exit_Function
+Error_NoGrid:
+ TraceError(TRACEFATAL, ERRNOGRIDINFORM, Utils._CalledSub(), 0, 1, vParentForm._Name)
+ Goto Exit_Function
+End Function &apos; FindRecord V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function GetHiddenAttribute(ByVal Optional pvObjectType As Variant _
+ , ByVal Optional pvObjectName As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;GetHiddenAttribute&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ If IsMissing(pvObjectType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), _
+ Array(acDiagram, acForm, acQuery, acTable, acReport, acBasicIDE, acDatabaseWindow, acDocument) _
+ ) Then Goto Exit_Function
+ If IsMissing(pvObjectName) Then
+ Select Case pvObjectType
+ Case acForm, acQuery, acTable, acReport, acDocument : Call _TraceArguments()
+ Case Else
+ End Select
+ pvObjectName = &quot;&quot;
+ Else
+ If Not Utils._CheckArgument(pvObjectName, 2, vbString) Then Goto Exit_Function
+ End If
+
+Dim oWindow As Object
+ Set oWindow = _SelectWindow(pvObjectType, pvObjectName)
+ If IsNull(oWindow.Frame) Then Goto Error_NotFound
+ GetHiddenAttribute = Not oWindow.Frame.ContainerWindow.isVisible()
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;OBJECT&quot;), pvObjectName))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; GetHiddenAttribute V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function GoToControl(Optional ByVal pvControlName As Variant) As Boolean
+&apos; Set the focus on the named control on the active form.
+&apos; Return False if the control does not exist or is disabled,
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;GoToControl&quot;)
+ If IsMissing(pvControlName) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvControlName, 1, vbString) Then Goto Exit_Function
+
+ GoToControl = False
+Dim oWindow As Object, ofForm As Object, ocControl As Object
+Dim i As Integer, iCount As Integer
+ Set oWindow = _SelectWindow()
+ If oWindow.WindowType = acForm Then
+ Set ofForm = Application.Forms(oWindow._Name)
+ iCount = ofForm.Controls().Count
+ For i = 0 To iCount - 1
+ ocControl = ofForm.Controls(i)
+ If UCase(ocControl._Name) = UCase(pvControlName) Then
+ If Methods.hasProperty(ocControl, &quot;Enabled&quot;) Then
+ If ocControl.Enabled Then
+ ocControl.setFocus()
+ GoToControl = True
+ Exit For
+ End If
+ End If
+ End If
+ Next i
+ End If
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;GoToControl&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;GoToControl&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; GoToControl V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function GoToRecord(Optional ByVal pvObjectType As Variant _
+ , Optional ByVal pvObjectName As Variant _
+ , Optional ByVal pvRecord As Variant _
+ , Optional ByVal pvOffset As Variant _
+ ) As Boolean
+
+&apos;Move to record indicated by pvRecord/pvOffset in the window designated by pvObjectType and pvObjectName
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ GoToRecord = False
+
+Const cstThisSub = &quot;GoTorecord&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvObjectName) Then pvObjectName = &quot;&quot;
+ If IsMissing(pvObjectType) Then pvObjectType = acActiveDataObject
+ If IsMissing(pvRecord) Then pvRecord = acNext
+ If IsMissing(pvOffset) Then pvOffset = 1
+ If Not (Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric() _
+ , Array(acActiveDataObject, acDataForm, acDataQuery, acDataTable)) _
+ And Utils._CheckArgument(pvObjectName, 2, vbString) _
+ And Utils._CheckArgument(pvRecord, 3, Utils._AddNumeric() _
+ , Array(acFirst, acGoTo, acLast, acNewRec, acNext, acPrevious)) _
+ And Utils._CheckArgument(pvOffset, 4, Utils._AddNumeric()) _
+ ) Then Goto Exit_Function
+ If pvObjectType = acActiveDataObject And pvObjectName &lt;&gt; &quot;&quot; Then Goto Error_Target
+ If pvOffset &lt; 0 And pvRecord &lt;&gt; acGoTo Then Goto Error_Offset
+
+Dim ofForm As Object, oGeneric As Object, oResultSet As Object, oWindow As Object
+Dim i As Integer, iCount As Integer, bFound As Boolean, lOffset As Long
+Dim sObjectName, iLengthName As Integer
+ Select Case pvObjectType
+ Case acActiveDataObject
+ Set oWindow = _SelectWindow()
+ With oWindow
+ Select Case .WindowType
+ Case acForm
+ Set oResultSet = _DatabaseForm(._Name, &quot;&quot;)
+ Case acQuery, acTable
+ If IsNull(.Frame.Controller.FormOperations) Then Goto Error_NotApplicable
+ &apos; FormOperations returns &lt;Null&gt; in OpenOffice
+ Set oResultSet = .Frame.Controller.FormOperations.Cursor
+ Case Else &apos; Ignore action
+ Goto Exit_Function
+ End Select
+ End With
+ Case acDataForm
+ &apos; pvObjectName can be &quot;myForm&quot;, &quot;Forms!myForm&quot;, &quot;Forms!myForm!mySubform&quot; or &quot;Forms!myForm!mySubform.Form&quot;
+ sObjectName = UCase(pvObjectName)
+ iLengthName = Len(sObjectName)
+ Select Case True
+ Case iLengthName &gt; 6 And Left(sObjectName, 6) = &quot;FORMS!&quot; And Right(sObjectName, 5) = &quot;.FORM&quot;
+ Set ofForm = getObject(pvObjectName)
+ If ofForm._Type &lt;&gt; OBJSUBFORM Then Goto Error_Target
+ Case iLengthName &gt; 6 And Left(sObjectName, 6) = &quot;FORMS!&quot;
+ Set oGeneric = getObject(pvObjectName)
+ If oGeneric._Type = OBJFORM Or oGeneric._Type = OBJSUBFORM Then
+ Set ofForm = oGeneric
+ ElseIf oGeneric.SubType = CTLSUBFORM Then
+ Set ofForm = oGeneric.Form
+ Else Goto Error_Target
+ End If
+ Case sObjectName = &quot;&quot;
+ Call _TraceArguments()
+ Case Else
+ Set ofForm = Application.Forms(pvObjectName)
+ End Select
+ Set oResultSet = ofForm.DatabaseForm
+ Case acDataQuery
+ Set oWindow = _SelectWindow(acQuery, pvObjectName)
+ If IsNull(oWindow.Frame.Controller.FormOperations) Then Goto Error_NotApplicable
+ &apos; FormOperations returns &lt;Null&gt; in OpenOffice
+ Set oResultSet = oWindow.Frame.Controller.FormOperations.Cursor
+ Case acDataTable
+ Set oWindow = _SelectWindow(acTable, pvObjectName)
+ If IsNull(oWindow.Frame.Controller.FormOperations) Then Goto Error_NotApplicable
+ Set oResultSet = oWindow.Frame.Controller.FormOperations.Cursor
+ Case Else
+ End Select
+
+ &apos; Check if current row updated =&gt; Save it
+ If oResultSet.IsNew Then
+ oResultSet.insertRow()
+ ElseIf oResultSet.IsModified Then
+ oResultSet.updateRow()
+ End If
+
+ lOffset = pvOffset
+ Select Case pvRecord
+ Case acFirst : GoToRecord = oResultSet.first()
+ Case acGoTo : GoToRecord = oResultSet.absolute(lOffset)
+ Case acLast : GoToRecord = oResultSet.last()
+ Case acNewRec
+ oResultSet.last() &apos; To simulate the behaviour in the UI
+ oResultSet.moveToInsertRow()
+ GoToRecord = True
+ Case acNext
+ If lOffset = 1 Then
+ GoToRecord = oResultSet.next()
+ Else
+ GoToRecord = oResultSet.relative(lOffset)
+ End If
+ Case acPrevious
+ If lOffset = 1 Then
+ GoToRecord = oResultSet.previous()
+ Else
+ GoToRecord = oResultSet.relative(- lOffset)
+ End If
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_Target:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(2, pvObjectName))
+ Goto Exit_Function
+Error_Offset:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(4, pvOffset))
+ Goto Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+End Function &apos; GoToRecord
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Maximize() As Boolean
+&apos; Maximize the window having the focus
+ Utils._SetCalledSub(&quot;Maximize&quot;)
+
+Dim oWindow As Object
+ Maximize = False
+ Set oWindow = _SelectWindow()
+ If Not IsNull(oWindow.Frame) Then
+ If Utils._hasUNOProperty(oWindow.Frame.ContainerWindow, &quot;IsMaximized&quot;) Then oWindow.Frame.ContainerWindow.IsMaximized = True &apos; Ignored when &lt;= OO3.2
+ Maximize = True
+ End If
+
+ Utils._ResetCalledSub(&quot;Maximize&quot;)
+ Exit Function
+End Function &apos; Maximize V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Minimize() As Boolean
+&apos; Maximize the form having the focus
+ Utils._SetCalledSub(&quot;Minimize&quot;)
+
+Dim oWindow As Object
+ Minimize = False
+ Set oWindow = _SelectWindow()
+ If Not IsNull(oWindow.Frame) Then
+ If Utils._hasUNOProperty(oWindow.Frame.ContainerWindow, &quot;IsMinimized&quot;) Then oWindow.Frame.ContainerWindow.IsMinimized = True
+ Minimize = True
+ End If
+
+ Utils._ResetCalledSub(&quot;Minimize&quot;)
+ Exit Function
+End Function &apos; Minimize V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function MoveSize(ByVal Optional pvLeft As Variant _
+ , ByVal Optional pvTop As Variant _
+ , ByVal Optional pvWidth As Variant _
+ , ByVal Optional pvHeight As Variant _
+ ) As Variant
+&apos; Execute MoveSize action
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;MoveSize&quot;)
+ MoveSize = False
+ If IsMissing(pvLeft) Then pvLeft = -1
+ If IsMissing(pvTop) Then pvTop = -1
+ If IsMissing(pvWidth) Then pvWidth = -1
+ If IsMissing(pvHeight) Then pvHeight = -1
+ If Not Utils._CheckArgument(pvLeft, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvTop, 2, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWidth, 3, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvHeight, 4, Utils._AddNumeric()) Then Goto Exit_Function
+
+Dim iArg As Integer, iWrong As Integer &apos; Check arguments values
+ iArg = 0
+ If pvHeight &lt; -1 Then
+ iArg = 4 : iWrong = pvHeight
+ ElseIf pvWidth &lt; -1 Then
+ iArg = 3 : iWrong = pvWidth
+ ElseIf pvTop &lt; -1 Then
+ iArg = 2 : iWrong = pvTop
+ ElseIf pvLeft &lt; -1 Then
+ iArg = 1 : iWrong = pvLeft
+ End If
+ If iArg &gt; 0 Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(iArg, iWrong))
+ Goto Exit_Function
+ End If
+
+Dim iPosSize As Integer
+ iPosSize = 0
+ If pvLeft &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.X
+ If pvTop &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.Y
+ If pvWidth &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.WIDTH
+ If pvHeight &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.HEIGHT
+
+Dim oWindow As Object
+ Set oWindow = _SelectWindow()
+ With oWindow
+ If Not IsNull(.Frame) Then
+ If Utils._hasUNOProperty(.Frame.ContainerWindow, &quot;IsMaximized&quot;) Then &apos; Ignored when &lt;= OO3.2
+ .Frame.ContainerWindow.IsMaximized = False
+ .Frame.ContainerWindow.IsMinimized = False
+ End If
+ .Frame.ContainerWindow.setPosSize(pvLeft, pvTop, pvWidth, pvHeight, iPosSize)
+ MoveSize = True
+ End If
+ End With
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;MoveSize&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;MoveSize&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; MoveSize V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenForm(Optional ByVal pvFormName As Variant _
+ , Optional ByVal pvView As Variant _
+ , Optional ByVal pvFilterName As Variant _
+ , Optional ByVal pvWhereCondition As Variant _
+ , Optional ByVal pvDataMode As Variant _
+ , Optional ByVal pvWindowMode As Variant _
+ , Optional ByVal pvOpenArgs As Variant _
+ ) As Variant
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(&quot;OpenForm&quot;)
+ If IsMissing(pvFormName) Then Call _TraceArguments()
+ If IsMissing(pvView) Then pvView = acNormal
+ If IsMissing(pvFilterName) Then pvFilterName = &quot;&quot;
+ If IsMissing(pvWhereCondition) Then pvWhereCondition = &quot;&quot;
+ If IsMissing(pvDataMode) Then pvDataMode = acFormPropertySettings
+ If IsMissing(pvWindowMode) Then pvWindowMode = acWindowNormal
+ If IsMissing(pvOpenArgs) Then pvOpenArgs = &quot;&quot;
+ Set OpenForm = Nothing
+ If Not (Utils._CheckArgument(pvFormName, 1, vbString) _
+ And Utils._CheckArgument(pvView, 2, Utils._AddNumeric(), Array(acNormal, acPreview, acDesign)) _
+ And Utils._CheckArgument(pvFilterName, 3, vbString) _
+ And Utils._CheckArgument(pvWhereCondition, 4, vbString) _
+ And Utils._CheckArgument(pvDataMode, 5, Utils._AddNumeric(), Array(acFormAdd, acFormEdit, acFormPropertySettings, acFormReadOnly)) _
+ And Utils._CheckArgument(pvWindowMode, 6, Utils._AddNumeric(), Array(acDialog, acHidden, acIcon, acWindowNormal)) _
+ ) Then Goto Exit_Function
+
+Dim ofForm As Object, sWarning As String
+Dim oDatabase As Object, oOpenForm As Object, bOpenMode As Boolean, oController As Object
+
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+ Set ofForm = Application.AllForms(pvFormName)
+ If ofForm.IsLoaded Then
+ sWarning = _GetLabel(&quot;ERR&quot; &amp; ERRFORMYETOPEN)
+ sWarning = Join(Split(sWarning, &quot;%0&quot;), ofForm._Name)
+ TraceLog(TRACEANY, &quot;OpenForm: &quot; &amp; sWarning)
+ Set OpenForm = ofForm
+ Goto Exit_Function
+ End If
+&apos; Open the form
+ Select Case pvView
+ Case acNormal, acPreview: bOpenMode = False
+ Case acDesign : bOpenMode = True
+ End Select
+ Set oController = oDatabase.Document.CurrentController
+ Set oOpenForm = oController.loadComponent(com.sun.star.sdb.application.DatabaseObject.FORM, ofForm._Name, bOpenMode)
+
+&apos; Apply the filters (FilterName) AND (WhereCondition)
+Dim sFilter As String, oForm As Object, oFormsCollection As Object
+ If pvFilterName = &quot;&quot; And pvWhereCondition = &quot;&quot; Then
+ sFilter = &quot;&quot;
+ ElseIf pvFilterName = &quot;&quot; Or pvWhereCondition = &quot;&quot; Then
+ sFilter = pvFilterName &amp; pvWhereCondition
+ Else
+ sFilter = &quot;(&quot; &amp; pvFilterName &amp; &quot;) And (&quot; &amp; pvWhereCondition &amp; &quot;)&quot;
+ End If
+ Set oFormsCollection = oOpenForm.DrawPage.Forms
+ If oFormsCollection.getCount() &gt; 0 Then Set oForm = oFormsCollection.getByIndex(0) Else Set oForm = Nothing
+ If Not IsNull(oForm) Then
+ If sFilter &lt;&gt; &quot;&quot; Then
+ oForm.Filter = oDatabase._ReplaceSquareBrackets(sFilter)
+ oForm.ApplyFilter = True
+ oForm.reload()
+ ElseIf oForm.Filter &lt;&gt; &quot;&quot; Then &apos; If a filter has been set previously it must be removed
+ oForm.Filter = &quot;&quot;
+ oForm.ApplyFilter = False
+ oForm.reload()
+ End If
+ End If
+
+&apos;Housekeeping
+ Set ofForm = Application.AllForms(pvFormName) &apos; Redone to reinitialize all properties of ofForm now FormName is open
+ With ofForm
+ If Not IsNull(.DatabaseForm) Then
+ Select Case pvDataMode
+ Case acFormAdd
+ .AllowAdditions = True
+ .AllowDeletions = False
+ .AllowEdits = False
+ Case acFormEdit
+ .AllowAdditions = True
+ .AllowDeletions = True
+ .AllowEdits = True
+ Case acFormReadOnly
+ .AllowAdditions = False
+ .AllowDeletions = False
+ .AllowEdits = False
+ Case acFormPropertySettings
+ End Select
+ End If
+ .Visible = ( pvWindowMode &lt;&gt; acHidden )
+ ._OpenArgs = pvOpenArgs
+ &apos;To avoid AOO 3.4 bug See http://user.services.openoffice.org/en/forum/viewtopic.php?f=13&amp;t=53751
+ .Component.CurrentController.ViewSettings.ShowOnlineLayout = True
+ End With
+
+ Set OpenForm = ofForm
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OpenForm&quot;)
+ Set ofForm = Nothing
+ Set oOpenForm = Nothing
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenForm&quot;, Erl)
+ Set OpenForm = Nothing
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1)
+ Goto Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERROPENFORM, Utils._CalledSub(), 0, , pvFormName)
+ Set OpenForm = Nothing
+ Goto Exit_Function
+End Function &apos; OpenForm V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenQuery(Optional ByVal pvQueryName As Variant _
+ , Optional ByVal pvView As Variant _
+ , Optional ByVal pvDataMode As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(&quot;OpenQuery&quot;)
+ If IsMissing(pvQueryName) Then Call _TraceArguments()
+ If IsMissing(pvView) Then pvView = acViewNormal
+ If IsMissing(pvDataMode) Then pvDataMode = acEdit
+ OpenQuery = DoCmd._OpenObject(&quot;Query&quot;, pvQueryName, pvView, pvDataMode)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OpenQuery&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenQuery&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; OpenQuery
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenReport(Optional ByVal pvReportName As Variant _
+ , Optional ByVal pvView As Variant _
+ , Optional ByVal pvDataMode As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(&quot;OpenReport&quot;)
+ If IsMissing(pvReportName) Then Call _TraceArguments()
+ If IsMissing(pvView) Then pvView = acViewNormal
+ If IsMissing(pvDataMode) Then pvDataMode = acEdit
+ OpenReport = DoCmd._OpenObject(&quot;Report&quot;, pvReportName, pvView, pvDataMode)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OpenReport&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenReport&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; OpenReport
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenSQL(Optional ByVal pvSQL As Variant _
+ , Optional ByVal pvOption As Variant _
+ ) As Boolean
+&apos; Return True if the execution of the SQL statement was successful
+&apos; SQL must contain a SELECT query
+&apos; pvOption can force pass through mode
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(&quot;OpenSQL&quot;)
+
+ OpenSQL = False
+ If IsMissing(pvSQL) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSQL, 1, vbString) Then Goto Exit_Function
+Const cstNull = -1
+ If IsMissing(pvOption) Then
+ pvOption = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOption, 2, Utils._AddNumeric(), dbSQLPassThrough) Then Goto Exit_Function
+ End If
+
+ OpenSQL = Application._CurrentDb.OpenSQL(pvSQL, pvOption)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OpenSQL&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenSQL&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; OpenSQL V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenTable(Optional ByVal pvTableName As Variant _
+ , Optional ByVal pvView As Variant _
+ , Optional ByVal pvDataMode As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(&quot;OpenTable&quot;)
+ If IsMissing(pvTableName) Then Call _TraceArguments()
+ If IsMissing(pvView) Then pvView = acViewNormal
+ If IsMissing(pvDataMode) Then pvDataMode = acEdit
+ OpenTable = DoCmd._OpenObject(&quot;Table&quot;, pvTableName, pvView, pvDataMode)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OpenTable&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenTable&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; OpenTable
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OutputTo(ByVal pvObjectType As Variant _
+ , ByVal Optional pvObjectName As Variant _
+ , ByVal Optional pvOutputFormat As Variant _
+ , ByVal Optional pvOutputFile As Variant _
+ , ByVal Optional pvAutoStart As Variant _
+ , ByVal Optional pvTemplateFile As Variant _
+ , ByVal Optional pvEncoding As Variant _
+ , ByVal Optional pvQuality As Variant _
+ ) As Boolean
+REM https://wiki.openoffice.org/wiki/Framework/Article/Filter/FilterList_OOo_3_0
+REM https://wiki.documentfoundation.org/Documentation/DevGuide/Spreadsheet_Documents#Filter_Options
+REM https://msdn.microsoft.com/en-us/library/ms709353%28v=vs.85%29.aspx
+&apos;Supported: acFormatPDF, acFormatODT, acFormatDOC, acFormatHTML for forms
+&apos; acFormatHTML, acFormatODS, acFormatXLS, acFormatXLSX, acFormatTXT for tables and queries
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;OutputTo&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ OutputTo = False
+
+ If Not Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), Array(acOutputTable, acOutputQuery, acOutputForm)) Then Goto Exit_Function
+ If IsMissing(pvObjectName) Then pvObjectName = &quot;&quot;
+ If Not Utils._CheckArgument(pvObjectName, 2, vbString) Then Goto Exit_Function
+ If IsMissing(pvOutputFormat) Then pvOutputFormat = &quot;&quot;
+ If Not Utils._CheckArgument(pvOutputFormat, 3, vbString) Then Goto Exit_Function
+ If pvOutputFormat &lt;&gt; &quot;&quot; Then
+ If Not Utils._CheckArgument(UCase(pvOutputFormat), 3, vbString, Array( _
+ UCase(acFormatPDF), UCase(acFormatODT), UCase(acFormatDOC), UCase(acFormatHTML) _
+ , UCase(acFormatODS), UCase(acFormatXLS), UCase(acFormatXLSX), UCase(acFormatTXT) _
+ , &quot;PDF&quot;, &quot;ODT&quot;, &quot;DOC&quot;, &quot;HTML&quot;, &quot;ODS&quot;, &quot;XLS&quot;, &quot;XLSX&quot;, &quot;TXT&quot;, &quot;CSV&quot;, &quot;&quot; _
+ )) Then Goto Exit_Function &apos; A 2nd time to allow case unsensitivity
+ End If
+ If IsMissing(pvOutputFile) Then pvOutputFile = &quot;&quot;
+ If Not Utils._CheckArgument(pvOutputFile, 4, vbString) Then Goto Exit_Function
+ If IsMissing(pvAutoStart) Then pvAutoStart = False
+ If Not Utils._CheckArgument(pvAutoStart, 5, vbBoolean) Then Goto Exit_Function
+ If IsMissing(pvTemplateFile) Then pvTemplateFile = &quot;&quot;
+ If Not Utils._CheckArgument(pvTemplateFile, 6, vbString) Then Goto Exit_Function
+ If IsMissing(pvEncoding) Then pvEncoding = 0
+ If Not Utils._CheckArgument(pvEncoding, 7, _AddNumeric()) Then Goto Exit_Function
+ If IsMissing(pvQuality) Then pvQuality = acExportQualityPrint
+ If Not Utils._CheckArgument(pvQuality, 7, _AddNumeric(), Array(acExportQualityPrint, acExportQualityScreen)) Then Goto Exit_Function
+
+ If pvObjectType = acOutputTable Or pvObjectType = acOutputQuery Then
+ OutputTo = Application._CurrentDb().OutputTo( _
+ pvObjectType _
+ , pvObjectName _
+ , pvOutputFormat _
+ , pvOutputFile _
+ , pvAutoStart _
+ , pvTemplateFile _
+ , pvEncoding _
+ , pvQuality _
+ )
+ GoTo Exit_Function
+ End If
+
+Dim vWindow As Variant, sOutputFile As String, ofForm As Object, i As Integer, bFound As Boolean
+ &apos;Find applicable form
+ If pvObjectName = &quot;&quot; Then
+ vWindow = _SelectWindow()
+ If vWindow.WindowType &lt;&gt; acOutoutForm Then Goto Error_Action
+ Set ofForm = Application.Forms(vWindow._Name)
+ Else
+ bFound = False
+ For i = 0 To Application.Forms()._Count - 1
+ Set ofForm = Application.Forms(i)
+ If UCase(ofForm._Name) = UCase(pvObjectName) Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Error_NotFound
+ End If
+
+ &apos;Determine format and parameters
+Dim sOutputFormat As String, sFilter As String, oFilterData As Object, oExport As Object, sSuffix As String
+ If pvOutputFormat = &quot;&quot; Then
+ sOutputFormat = _PromptFormat(Array(&quot;PDF&quot;, &quot;ODT&quot;, &quot;DOC&quot;, &quot;HTML&quot;)) &apos; Prompt user for format
+ If sOutputFormat = &quot;&quot; Then Goto Exit_Function
+ Else
+ sOutputFormat = UCase(pvOutputFormat)
+ End If
+ Select Case sOutputFormat
+ Case UCase(acFormatPDF), &quot;PDF&quot;
+ sFilter = acFormatPDF
+ oFilterData = Array( _
+ _MakePropertyValue (&quot;ExportFormFields&quot;, False), _
+ )
+ sSuffix = &quot;pdf&quot;
+ Case UCase(acFormatDOC), &quot;DOC&quot;
+ sFilter = acFormatDOC
+ oFilterData = Array()
+ sSuffix = &quot;doc&quot;
+ Case UCase(acFormatODT), &quot;ODT&quot;
+ sFilter = acFormatODT
+ oFilterData = Array()
+ sSuffix = &quot;odt&quot;
+ Case UCase(acFormatHTML), &quot;HTML&quot;
+ sFilter = acFormatHTML
+ oFilterData = Array()
+ sSuffix = &quot;html&quot;
+ End Select
+ oExport = Array( _
+ _MakePropertyValue(&quot;Overwrite&quot;, True), _
+ _MakePropertyValue(&quot;FilterName&quot;, sFilter), _
+ _MakePropertyValue(&quot;FilterData&quot;, oFilterData), _
+ )
+
+ &apos;Determine output file
+ If pvOutputFile = &quot;&quot; Then &apos; Prompt file picker to user
+ sOutputFile = _PromptFilePicker(sSuffix)
+ If sOutputFile = &quot;&quot; Then Goto Exit_Function
+ Else
+ sOutputFile = pvOutputFile
+ End If
+ sOutputFile = ConvertToURL(sOutputFile)
+
+ &apos;Create file
+ On Local Error Goto Error_File
+ ofForm.Component.storeToURL(sOutputFile, oExport)
+ On Local Error Goto Error_Function
+
+ &apos;Launch application, if requested
+ If pvAutoStart Then Call _ShellExecute(sOutputFile)
+
+ OutputTo = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;OBJECT&quot;), pvObjectName))
+ Goto Exit_Function
+Error_Action:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_File:
+ TraceError(TRACEFATAL, ERRFILENOTCREATED, Utils._CalledSub(), 0, , sOutputFile)
+ GoTo Exit_Function
+End Function &apos; OutputTo V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Quit(Optional ByVal pvSave As Variant) As Variant
+&apos; Quit the application
+&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming §5.8.1
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Quit&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ If IsMissing(pvSave) Then pvSave = acQuitSaveAll
+ If Not Utils._CheckArgument(pvSave, 1, Utils._AddNumeric(), _
+ Array(acQuitPrompt, acQuitSaveAll, acQuitSaveNone) _
+ ) Then Goto Exit_Function
+
+Dim oDatabase As Object, oDoc As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+ If Not IsNull(oDatabase) Then
+ Set oDoc = oDatabase.Document
+ Select Case pvSave
+ Case acQuitPrompt
+ If MsgBox(_GetLabel(&quot;QUIT&quot;), vbYesNo + vbQuestion, _GetLabel(&quot;QUITSHORT&quot;)) = vbNo Then Exit Function
+ Case acQuitSaveNone
+ oDoc.setModified(False)
+ Case Else
+ End Select
+ If HasUnoInterfaces(oDoc, &quot;com.sun.star.util.XCloseable&quot;) Then
+ If (oDoc.isModified) Then
+ If (oDoc.hasLocation AND (Not oDoc.isReadOnly)) Then
+ oDoc.store()
+ End If
+ End If
+ oDoc.close(true)
+ Else
+ oDoc.dispose()
+ End If
+ End If
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Set oDatabase = Nothing
+ Set oDoc = Nothing
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ Set OpenForm = Nothing
+ GoTo Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+End Function &apos; Quit V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub RunApp(Optional ByVal pvCommandLine As Variant)
+&apos; Convert to URL and execute the Command Line
+
+ If _ErrorHandler() Then On Local Error Goto Error_Sub
+
+ Utils._SetCalledSub(&quot;RunApp&quot;)
+
+ If IsMissing(pvCommandLine) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvCommandLine, 1, vbString) Then Goto Exit_Sub
+
+ _ShellExecute(ConvertToURL(pvCommandLine))
+
+Exit_Sub:
+ Utils._ResetCalledSub(&quot;RunApp&quot;)
+ Exit Sub
+Error_Sub:
+ TraceError(TRACEABORT, Err, &quot;RunApp&quot;, Erl)
+ GoTo Exit_Sub
+End Sub &apos; RunApp V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function RunCommand(Optional pvCommand As Variant, Optional pbReturnCommand As Boolean) As Variant
+&apos; Execute command via DispatchHelper
+&apos; pbReturnCommand = internal parameter to only return the exact command string (always absent if uno prefix present in pvCommand)
+
+ If _ErrorHandler() Then On Local Error Goto Exit_Function &apos; Avoid any abort
+Const cstThisSub = &quot;RunCommand&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iVBACommand As Integer, sOOCommand As String, sDispatch As String
+ If IsMissing(pvCommand) Then Call _TraceArguments()
+ If Not ( Utils._CheckArgument(pvCommand, 1, Utils._AddNumeric(vbString)) ) Then Goto Exit_Function
+ If IsMissing(pbReturnCommand) Then pbReturnCommand = False
+
+ RunCommand = True
+
+Const cstUnoPrefix = &quot;.uno:&quot;
+ If VarType(pvCommand) = vbString Then
+ sOOCommand = pvCommand
+ iVBACommand = -1
+ If _IsLeft(sOOCommand, cstUnoPrefix) Then
+ Call _DispatchCommand(sOOCommand)
+ Goto Exit_Function
+ End If
+ Else
+ sOOCommand = &quot;&quot;
+ iVBACommand = pvCommand
+ End If
+
+ Select Case True
+ Case iVBACommand = acCmdAboutMicrosoftAccess Or UCase(sOOCommand) = &quot;ABOUT&quot; : sDispatch = &quot;About&quot;
+ Case iVBACommand = acCmdAboutOpenOffice Or UCase(sOOCommand) = &quot;ABOUT&quot; : sDispatch = &quot;About&quot;
+ Case iVBACommand = acCmdAboutLibreOffice Or UCase(sOOCommand) = &quot;ABOUT&quot; : sDispatch = &quot;About&quot;
+ Case UCase(sOOCommand) = &quot;ACTIVEHELP&quot; : sDispatch = &quot;ActiveHelp&quot;
+ Case UCase(sOOCommand) = &quot;ADDDIRECT&quot; : sDispatch = &quot;AddDirect&quot;
+ Case UCase(sOOCommand) = &quot;ADDFIELD&quot; : sDispatch = &quot;AddField&quot;
+ Case UCase(sOOCommand) = &quot;AUTOCONTROLFOCUS&quot; : sDispatch = &quot;AutoControlFocus&quot;
+ Case UCase(sOOCommand) = &quot;AUTOFILTER&quot; : sDispatch = &quot;AutoFilter&quot;
+ Case UCase(sOOCommand) = &quot;AUTOPILOTADDRESSDATASOURCE&quot; : sDispatch = &quot;AutoPilotAddressDataSource&quot;
+ Case UCase(sOOCommand) = &quot;BASICBREAK&quot; : sDispatch = &quot;BasicBreak&quot;
+ Case iVBACommand = acCmdVisualBasicEditor Or UCase(sOOCommand) = &quot;BASICIDEAPPEAR&quot; : sDispatch = &quot;BasicIDEAppear&quot;
+ Case UCase(sOOCommand) = &quot;BASICSTOP&quot; : sDispatch = &quot;BasicStop&quot;
+ Case iVBACommand = acCmdBringToFront Or UCase(sOOCommand) = &quot;BRINGTOFRONT&quot; : sDispatch = &quot;BringToFront&quot;
+ Case UCase(sOOCommand) = &quot;CHECKBOX&quot; : sDispatch = &quot;CheckBox&quot;
+ Case UCase(sOOCommand) = &quot;CHOOSEMACRO&quot; : sDispatch = &quot;ChooseMacro&quot;
+ Case iVBACommand = acCmdClose Or UCase(sOOCommand) = &quot;CLOSEDOC&quot; : sDispatch = &quot;CloseDoc&quot;
+ Case UCase(sOOCommand) = &quot;CLOSEWIN&quot; : sDispatch = &quot;CloseWin&quot;
+ Case iVBACommand = acCmdToolbarsCustomize Or UCase(sOOCommand) = &quot;CONFIGUREDIALOG&quot; : sDispatch = &quot;ConfigureDialog&quot;
+ Case UCase(sOOCommand) = &quot;CONTROLPROPERTIES&quot; : sDispatch = &quot;ControlProperties&quot;
+ Case iVBACommand = acCmdChangeToCommandButton Or UCase(sOOCommand) = &quot;CONVERTTOBUTTON&quot; : sDispatch = &quot;ConvertToButton&quot;
+ Case iVBACommand = acCmdChangeToCheckBox Or UCase(sOOCommand) = &quot;CONVERTTOCHECKBOX&quot; : sDispatch = &quot;ConvertToCheckBox&quot;
+ Case iVBACommand = acCmdChangeToComboBox Or UCase(sOOCommand) = &quot;CONVERTTOCOMBO&quot; : sDispatch = &quot;ConvertToCombo&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOCURRENCY&quot; : sDispatch = &quot;ConvertToCurrency&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTODATE&quot; : sDispatch = &quot;ConvertToDate&quot;
+ Case iVBACommand = acCmdChangeToTextBox Or UCase(sOOCommand) = &quot;CONVERTTOEDIT&quot; : sDispatch = &quot;ConvertToEdit&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOFILECONTROL&quot; : sDispatch = &quot;ConvertToFileControl&quot;
+ Case iVBACommand = acCmdChangeToLabel Or UCase(sOOCommand) = &quot;CONVERTTOFIXED&quot; : sDispatch = &quot;ConvertToFixed&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOFORMATTED&quot; : sDispatch = &quot;ConvertToFormatted&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOGROUP&quot; : sDispatch = &quot;ConvertToGroup&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOIMAGEBTN&quot; : sDispatch = &quot;ConvertToImageBtn&quot;
+ Case iVBACommand = acCmdChangeToImage Or UCase(sOOCommand) = &quot;CONVERTTOIMAGECONTROL&quot; : sDispatch = &quot;ConvertToImageControl&quot;
+ Case iVBACommand = acCmdChangeToListBox Or UCase(sOOCommand) = &quot;CONVERTTOLIST&quot; : sDispatch = &quot;ConvertToList&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTONAVIGATIONBAR&quot; : sDispatch = &quot;ConvertToNavigationBar&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTONUMERIC&quot; : sDispatch = &quot;ConvertToNumeric&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOPATTERN&quot; : sDispatch = &quot;ConvertToPattern&quot;
+ Case iVBACommand = acCmdChangeToOptionButton Or UCase(sOOCommand) = &quot;CONVERTTORADIO&quot; : sDispatch = &quot;ConvertToRadio&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOSCROLLBAR&quot; : sDispatch = &quot;ConvertToScrollBar&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOSPINBUTTON&quot; : sDispatch = &quot;ConvertToSpinButton&quot;
+ Case UCase(sOOCommand) = &quot;CONVERTTOTIME&quot; : sDispatch = &quot;ConvertToTime&quot;
+ Case iVBACommand = acCmdCopy Or UCase(sOOCommand) = &quot;COPY&quot; : sDispatch = &quot;Copy&quot;
+ Case UCase(sOOCommand) = &quot;CURRENCYFIELD&quot; : sDispatch = &quot;CurrencyField&quot;
+ Case iVBACommand = acCmdCut Or UCase(sOOCommand) = &quot;CUT&quot; : sDispatch = &quot;Cut&quot;
+ Case UCase(sOOCommand) = &quot;DATEFIELD&quot; : sDispatch = &quot;DateField&quot;
+ Case iVBACommand = acCmdCreateRelationship Or UCase(sOOCommand) = &quot;DBADDRELATION &quot; : sDispatch = &quot;DBAddRelation &quot;
+ Case UCase(sOOCommand) = &quot;DBCONVERTTOVIEW &quot; : sDispatch = &quot;DBConvertToView &quot;
+ Case iVBACommand = acCmdDelete Or UCase(sOOCommand) = &quot;DBDELETE &quot; : sDispatch = &quot;DBDelete &quot;
+ Case UCase(sOOCommand) = &quot;DBDIRECTSQL &quot; : sDispatch = &quot;DBDirectSQL &quot;
+ Case UCase(sOOCommand) = &quot;DBDSADVANCEDSETTINGS &quot; : sDispatch = &quot;DBDSAdvancedSettings &quot;
+ Case UCase(sOOCommand) = &quot;DBDSCONNECTIONTYPE &quot; : sDispatch = &quot;DBDSConnectionType &quot;
+ Case iVBACommand = acCmdDatabaseProperties Or UCase(sOOCommand) = &quot;DBDSPROPERTIES &quot; : sDispatch = &quot;DBDSProperties &quot;
+ Case UCase(sOOCommand) = &quot;DBEDIT &quot; : sDispatch = &quot;DBEdit &quot;
+ Case iVBACommand = acCmdSQLView Or UCase(sOOCommand) = &quot;DBEDITSQLVIEW &quot; : sDispatch = &quot;DBEditSqlView &quot;
+ Case iVBACommand = acCmdRemove Or UCase(sOOCommand) = &quot;DBFORMDELETE &quot; : sDispatch = &quot;DBFormDelete &quot;
+ Case iVBACommand = acCmdDesignView Or UCase(sOOCommand) = &quot;DBFORMEDIT &quot; : sDispatch = &quot;DBFormEdit &quot;
+ Case iVBACommand = acCmdFormView Or UCase(sOOCommand) = &quot;DBFORMOPEN &quot; : sDispatch = &quot;DBFormOpen &quot;
+ Case UCase(sOOCommand) = &quot;DBFORMRENAME &quot; : sDispatch = &quot;DBFormRename &quot;
+ Case iVBACommand = acCmdNewObjectForm Or UCase(sOOCommand) = &quot;DBNEWFORM &quot; : sDispatch = &quot;DBNewForm &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWFORMAUTOPILOT &quot; : sDispatch = &quot;DBNewFormAutoPilot &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWQUERY &quot; : sDispatch = &quot;DBNewQuery &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWQUERYAUTOPILOT &quot; : sDispatch = &quot;DBNewQueryAutoPilot &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWQUERYSQL &quot; : sDispatch = &quot;DBNewQuerySql &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWREPORT &quot; : sDispatch = &quot;DBNewReport &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWREPORTAUTOPILOT &quot; : sDispatch = &quot;DBNewReportAutoPilot &quot;
+ Case iVBACommand = acCmdNewObjectTable Or UCase(sOOCommand) = &quot;DBNEWTABLE &quot; : sDispatch = &quot;DBNewTable &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWTABLEAUTOPILOT &quot; : sDispatch = &quot;DBNewTableAutoPilot &quot;
+ Case iVBACommand = acCmdNewObjectView Or UCase(sOOCommand) = &quot;DBNEWVIEW &quot; : sDispatch = &quot;DBNewView &quot;
+ Case UCase(sOOCommand) = &quot;DBNEWVIEWSQL &quot; : sDispatch = &quot;DBNewViewSQL &quot;
+ Case iVBACommand = acCmdOpenDatabase Or UCase(sOOCommand) = &quot;DBOPEN &quot; : sDispatch = &quot;DBOpen &quot;
+ Case iVBACommand = acCmdRemove Or UCase(sOOCommand) = &quot;DBQUERYDELETE &quot; : sDispatch = &quot;DBQueryDelete &quot;
+ Case iVBACommand = acCmdDesignView Or UCase(sOOCommand) = &quot;DBQUERYEDIT &quot; : sDispatch = &quot;DBQueryEdit &quot;
+ Case iVBACommand = acCmdNewObjectQuery Or UCase(sOOCommand) = &quot;DBQUERYOPEN &quot; : sDispatch = &quot;DBQueryOpen &quot;
+ Case UCase(sOOCommand) = &quot;DBQUERYRENAME &quot; : sDispatch = &quot;DBQueryRename &quot;
+ Case UCase(sOOCommand) = &quot;DBREFRESHTABLES &quot; : sDispatch = &quot;DBRefreshTables &quot;
+ Case iVBACommand = acCmdShowAllRelationships Or UCase(sOOCommand) = &quot;DBRELATIONDESIGN &quot; : sDispatch = &quot;DBRelationDesign &quot;
+ Case UCase(sOOCommand) = &quot;DBRENAME &quot; : sDispatch = &quot;DBRename &quot;
+ Case iVBACommand = acCmdRemove Or UCase(sOOCommand) = &quot;DBREPORTDELETE &quot; : sDispatch = &quot;DBReportDelete &quot;
+ Case iVBACommand = acCmdDesignView Or UCase(sOOCommand) = &quot;DBREPORTEDIT &quot; : sDispatch = &quot;DBReportEdit &quot;
+ Case iVBACommand = acCmdNewObjectReport Or UCase(sOOCommand) = &quot;DBREPORTOPEN &quot; : sDispatch = &quot;DBReportOpen &quot;
+ Case UCase(sOOCommand) = &quot;DBREPORTRENAME &quot; : sDispatch = &quot;DBReportRename &quot;
+ Case iVBACommand = acCmdSelectAll Or UCase(sOOCommand) = &quot;DBSELECTALL &quot; : sDispatch = &quot;DBSelectAll &quot;
+ Case UCase(sOOCommand) = &quot;DBSHOWDOCINFOPREVIEW &quot; : sDispatch = &quot;DBShowDocInfoPreview &quot;
+ Case UCase(sOOCommand) = &quot;DBSHOWDOCPREVIEW &quot; : sDispatch = &quot;DBShowDocPreview &quot;
+ Case iVBACommand = acCmdRemoveTable Or UCase(sOOCommand) = &quot;DBTABLEDELETE &quot; : sDispatch = &quot;DBTableDelete &quot;
+ Case iVBACommand = acCmdDesignView Or UCase(sOOCommand) = &quot;DBTABLEEDIT &quot; : sDispatch = &quot;DBTableEdit &quot;
+ Case UCase(sOOCommand) = &quot;DBTABLEFILTER &quot; : sDispatch = &quot;DBTableFilter &quot;
+ Case iVBACommand = acCmdOpenTable Or UCase(sOOCommand) = &quot;DBTABLEOPEN &quot; : sDispatch = &quot;DBTableOpen &quot;
+ Case iVBACommand = acCmdRename Or UCase(sOOCommand) = &quot;DBTABLERENAME &quot; : sDispatch = &quot;DBTableRename &quot;
+ Case UCase(sOOCommand) = &quot;DBUSERADMIN &quot; : sDispatch = &quot;DBUserAdmin &quot;
+ Case UCase(sOOCommand) = &quot;DBVIEWFORMS &quot; : sDispatch = &quot;DBViewForms &quot;
+ Case UCase(sOOCommand) = &quot;DBVIEWQUERIES &quot; : sDispatch = &quot;DBViewQueries &quot;
+ Case UCase(sOOCommand) = &quot;DBVIEWREPORTS &quot; : sDispatch = &quot;DBViewReports &quot;
+ Case UCase(sOOCommand) = &quot;DBVIEWTABLES &quot; : sDispatch = &quot;DBViewTables &quot;
+ Case iVBACommand = acCmdDelete Or UCase(sOOCommand) = &quot;DELETE&quot; : sDispatch = &quot;Delete&quot;
+ Case iVBACommand = acCmdDeleteRecord Or UCase(sOOCommand) = &quot;DELETERECORD&quot; : sDispatch = &quot;DeleteRecord&quot;
+ Case UCase(sOOCommand) = &quot;DESIGNERDIALOG&quot; : sDispatch = &quot;DesignerDialog&quot;
+ Case UCase(sOOCommand) = &quot;EDIT&quot; : sDispatch = &quot;Edit&quot;
+ Case UCase(sOOCommand) = &quot;FIRSTRECORD&quot; : sDispatch = &quot;FirstRecord&quot;
+ Case UCase(sOOCommand) = &quot;FONTDIALOG&quot; : sDispatch = &quot;FontDialog&quot;
+ Case UCase(sOOCommand) = &quot;FONTHEIGHT&quot; : sDispatch = &quot;FontHeight&quot;
+ Case UCase(sOOCommand) = &quot;FORMATTEDFIELD&quot; : sDispatch = &quot;FormattedField&quot;
+ Case UCase(sOOCommand) = &quot;FORMFILTER&quot; : sDispatch = &quot;FormFilter&quot;
+ Case iVBACommand = acCmdApplyFilterSort Or UCase(sOOCommand) = &quot;FORMFILTERED&quot; : sDispatch = &quot;FormFiltered&quot;
+ Case UCase(sOOCommand) = &quot;FORMFILTEREXECUTE&quot; : sDispatch = &quot;FormFilterExecute&quot;
+ Case UCase(sOOCommand) = &quot;FORMFILTEREXIT&quot; : sDispatch = &quot;FormFilterExit&quot;
+ Case UCase(sOOCommand) = &quot;FORMFILTERNAVIGATOR&quot; : sDispatch = &quot;FormFilterNavigator&quot;
+ Case UCase(sOOCommand) = &quot;FORMPROPERTIES&quot; : sDispatch = &quot;FormProperties&quot;
+ Case UCase(sOOCommand) = &quot;FULLSCREEN&quot; : sDispatch = &quot;FullScreen&quot;
+ Case UCase(sOOCommand) = &quot;GALLERY&quot; : sDispatch = &quot;Gallery&quot;
+ Case UCase(sOOCommand) = &quot;GRID&quot; : sDispatch = &quot;Grid&quot;
+ Case iVBACommand = acCmdSnapToGrid Or UCase(sOOCommand) = &quot;GRIDUSE&quot; : sDispatch = &quot;GridUse&quot;
+ Case iVBACommand = acCmdViewGrid Or UCase(sOOCommand) = &quot;GRIDVISIBLE&quot; : sDispatch = &quot;GridVisible&quot;
+ Case UCase(sOOCommand) = &quot;GROUPBOX&quot; : sDispatch = &quot;GroupBox&quot;
+ Case UCase(sOOCommand) = &quot;HELPINDEX&quot; : sDispatch = &quot;HelpIndex&quot;
+ Case UCase(sOOCommand) = &quot;HELPSUPPORT&quot; : sDispatch = &quot;HelpSupport&quot;
+ Case iVBACommand = acCmdInsertHyperlink Or UCase(sOOCommand) = &quot;HYPERLINKDIALOG&quot; : sDispatch = &quot;HyperlinkDialog&quot;
+ Case UCase(sOOCommand) = &quot;IMAGEBUTTON&quot; : sDispatch = &quot;Imagebutton&quot;
+ Case UCase(sOOCommand) = &quot;IMAGECONTROL&quot; : sDispatch = &quot;ImageControl&quot;
+ Case UCase(sOOCommand) = &quot;LABEL&quot; : sDispatch = &quot;Label&quot;
+ Case iVBACommand = acCmdMaximumRecords Or UCase(sOOCommand) = &quot;LASTRECORD&quot; : sDispatch = &quot;LastRecord&quot;
+ Case UCase(sOOCommand) = &quot;LISTBOX&quot; : sDispatch = &quot;ListBox&quot;
+ Case UCase(sOOCommand) = &quot;MACRODIALOG&quot; : sDispatch = &quot;MacroDialog&quot;
+ Case UCase(sOOCommand) = &quot;MACROORGANIZER&quot; : sDispatch = &quot;MacroOrganizer&quot;
+ Case UCase(sOOCommand) = &quot;NAVIGATIONBAR&quot; : sDispatch = &quot;NavigationBar&quot;
+ Case iVBACommand = acCmdObjectBrowser Or UCase(sOOCommand) = &quot;NAVIGATOR&quot; : sDispatch = &quot;Navigator&quot;
+ Case UCase(sOOCommand) = &quot;NEWDOC&quot; : sDispatch = &quot;NewDoc&quot;
+ Case UCase(sOOCommand) = &quot;NEWRECORD&quot; : sDispatch = &quot;NewRecord&quot;
+ Case UCase(sOOCommand) = &quot;NEXTRECORD&quot; : sDispatch = &quot;NextRecord&quot;
+ Case UCase(sOOCommand) = &quot;NUMERICFIELD&quot; : sDispatch = &quot;NumericField&quot;
+ Case UCase(sOOCommand) = &quot;OPEN&quot; : sDispatch = &quot;Open&quot;
+ Case UCase(sOOCommand) = &quot;OPTIONSTREEDIALOG&quot; : sDispatch = &quot;OptionsTreeDialog&quot;
+ Case UCase(sOOCommand) = &quot;ORGANIZER&quot; : sDispatch = &quot;Organizer&quot;
+ Case UCase(sOOCommand) = &quot;PARAGRAPHDIALOG&quot; : sDispatch = &quot;ParagraphDialog&quot;
+ Case iVBACommand = acCmdPaste Or UCase(sOOCommand) = &quot;PASTE&quot; : sDispatch = &quot;Paste&quot;
+ Case iVBACommand = acCmdPasteSpecial Or UCase(sOOCommand) = &quot;PASTESPECIAL &quot; : sDispatch = &quot;PasteSpecial &quot;
+ Case UCase(sOOCommand) = &quot;PATTERNFIELD&quot; : sDispatch = &quot;PatternField&quot;
+ Case UCase(sOOCommand) = &quot;PREVRECORD&quot; : sDispatch = &quot;PrevRecord&quot;
+ Case iVBACommand = acCmdPrint Or UCase(sOOCommand) = &quot;PRINT&quot; : sDispatch = &quot;Print&quot;
+ Case UCase(sOOCommand) = &quot;PRINTDEFAULT&quot; : sDispatch = &quot;PrintDefault&quot;
+ Case UCase(sOOCommand) = &quot;PRINTERSETUP&quot; : sDispatch = &quot;PrinterSetup&quot;
+ Case iVBACommand = acCmdPrintPreview Or UCase(sOOCommand) = &quot;PRINTPREVIEW&quot; : sDispatch = &quot;PrintPreview&quot;
+ Case UCase(sOOCommand) = &quot;PUSHBUTTON&quot; : sDispatch = &quot;Pushbutton&quot;
+ Case UCase(sOOCommand) = &quot;QUIT&quot; : sDispatch = &quot;Quit&quot;
+ Case UCase(sOOCommand) = &quot;RADIOBUTTON&quot; : sDispatch = &quot;RadioButton&quot;
+ Case iVBACommand = acCmdSaveRecord Or UCase(sOOCommand) = &quot;RECSAVE&quot; : sDispatch = &quot;RecSave&quot;
+ Case iVBACommand = acCmdFind Or UCase(sOOCommand) = &quot;RECSEARCH&quot; : sDispatch = &quot;RecSearch&quot;
+ Case iVBACommand = acCmdUndo Or UCase(sOOCommand) = &quot;RECUNDO&quot; : sDispatch = &quot;RecUndo&quot;
+ Case iVBACommand = acCmdRefresh Or UCase(sOOCommand) = &quot;REFRESH&quot; : sDispatch = &quot;Refresh&quot;
+ Case UCase(sOOCommand) = &quot;RELOAD&quot; : sDispatch = &quot;Reload&quot;
+ Case iVBACommand = acCmdRemoveFilterSort Or UCase(sOOCommand) = &quot;REMOVEFILTERSORT&quot; : sDispatch = &quot;RemoveFilterSort&quot;
+ Case iVBACommand = acCmdRunMacro Or UCase(sOOCommand) = &quot;RUNMACRO&quot; : sDispatch = &quot;RunMacro&quot;
+ Case iVBACommand = acCmdSave Or UCase(sOOCommand) = &quot;SAVE&quot; : sDispatch = &quot;Save&quot;
+ Case UCase(sOOCommand) = &quot;SAVEALL&quot; : sDispatch = &quot;SaveAll&quot;
+ Case iVBACommand = acCmdSaveAs Or UCase(sOOCommand) = &quot;SAVEAS&quot; : sDispatch = &quot;SaveAs&quot;
+ Case UCase(sOOCommand) = &quot;SAVEBASICAS&quot; : sDispatch = &quot;SaveBasicAs&quot;
+ Case UCase(sOOCommand) = &quot;SCRIPTORGANIZER&quot; : sDispatch = &quot;ScriptOrganizer&quot;
+ Case UCase(sOOCommand) = &quot;SCROLLBAR&quot; : sDispatch = &quot;ScrollBar&quot;
+ Case iVBACommand = acCmdFind Or UCase(sOOCommand) = &quot;SEARCHDIALOG&quot; : sDispatch = &quot;SearchDialog&quot;
+ Case iVBACommand = acCmdSelectAll Or UCase(sOOCommand) = &quot;SELECTALL&quot; : sDispatch = &quot;SelectAll&quot;
+ Case iVBACommand = acCmdSelectAllRecords Or UCase(sOOCommand) = &quot;SELECTALL&quot; : sDispatch = &quot;SelectAll&quot;
+ Case iVBACommand = acCmdSendToBack Or UCase(sOOCommand) = &quot;SENDTOBACK&quot; : sDispatch = &quot;SendToBack&quot;
+ Case UCase(sOOCommand) = &quot;SHOWFMEXPLORER&quot; : sDispatch = &quot;ShowFmExplorer&quot;
+ Case UCase(sOOCommand) = &quot;SIDEBAR&quot; : sDispatch = &quot;Sidebar&quot;
+ Case iVBACommand = acCmdSortDescending Or UCase(sOOCommand) = &quot;SORTDOWN&quot; : sDispatch = &quot;SortDown&quot;
+ Case iVBACommand = acCmdSortAscending Or UCase(sOOCommand) = &quot;SORTUP&quot; : sDispatch = &quot;Sortup&quot;
+ Case UCase(sOOCommand) = &quot;SPINBUTTON&quot; : sDispatch = &quot;SpinButton&quot;
+ Case UCase(sOOCommand) = &quot;STATUSBARVISIBLE&quot; : sDispatch = &quot;StatusBarVisible&quot;
+ Case UCase(sOOCommand) = &quot;SWITCHCONTROLDESIGNMODE&quot; : sDispatch = &quot;SwitchControlDesignMode&quot;
+ Case iVBACommand = acCmdTabOrder Or UCase(sOOCommand) = &quot;TABDIALOG&quot; : sDispatch = &quot;TabDialog&quot;
+ Case UCase(sOOCommand) = &quot;USEWIZARDS&quot; : sDispatch = &quot;UseWizards&quot;
+ Case UCase(sOOCommand) = &quot;VERSIONDIALOG&quot; : sDispatch = &quot;VersionDialog&quot;
+ Case UCase(sOOCommand) = &quot;VIEWDATASOURCEBROWSER&quot; : sDispatch = &quot;ViewDataSourceBrowser&quot;
+ Case iVBACommand = acCmdDatasheetView Or UCase(sOOCommand) = &quot;VIEWFORMASGRID&quot; : sDispatch = &quot;ViewFormAsGrid&quot;
+ Case iVBACommand = acCmdZoomSelection Or UCase(sOOCommand) = &quot;ZOOM&quot; : sDispatch = &quot;Zoom&quot;
+ Case Else
+ If iVBACommand &gt;= 0 Then Goto Exit_Function
+ sDispatch = pvCommand
+ End Select
+
+ If pbReturnCommand Then RunCommand = cstUnoPrefix &amp; sDispatch Else Call _DispatchCommand(cstUnoPrefix &amp; sDispatch)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ GoTo Exit_Function
+End Function &apos; RunCommand V0.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function RunSQL(Optional ByVal pvSQL As Variant _
+ , Optional ByVal pvOption As Variant _
+ ) As Boolean
+&apos; Return True if the execution of the SQL statement was successful
+&apos; SQL must contain an ACTION query
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Utils._SetCalledSub(&quot;RunSQL&quot;)
+
+ RunSQL = False
+ If IsMissing(pvSQL) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvSQL, 1, vbString) Then Goto Exit_Function
+Const cstNull = -1
+ If IsMissing(pvOption) Then
+ pvOption = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOption, 2, Utils._AddNumeric(), Array(cstNull, dbSQLPassThrough)) Then Goto Exit_Function
+ End If
+
+ RunSQL = Application._CurrentDb.RunSQL(pvSQL, pvOption)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;RunSQL&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;RunSQL&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; RunSQL V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SelectObject( ByVal Optional pvObjectType As Variant _
+ , ByVal Optional pvObjectName As Variant _
+ , ByVal Optional pvInDatabaseWindow As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;SelectObject&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ If IsMissing(pvObjectType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), _
+ Array(acDiagram, acForm, acQuery, acTable, acReport, acBasicIDE, acDatabaseWindow, acDocument) _
+ ) Then Goto Exit_Function
+ If IsMissing(pvObjectName) Then
+ Select Case pvObjectType
+ Case acForm, acQuery, acTable, acReport, acDocument : Call _TraceArguments()
+ Case Else
+ End Select
+ pvObjectName = &quot;&quot;
+ Else
+ If Not Utils._CheckArgument(pvObjectName, 2, vbString) Then Goto Exit_Function
+ End If
+ If Not IsMissing(pvInDatabaseWindow) Then
+ If Not Utils._CheckArgument(pvInDatabaseWindow, 3, vbBoolean, False) Then Goto Exit_Function
+ End If
+
+Dim oWindow As Object
+ Set oWindow = _SelectWindow(pvObjectType, pvObjectName)
+ If IsNull(oWindow.Frame) Then Goto Error_NotFound
+ With oWindow.Frame.ContainerWindow
+ If .isVisible() = False Then .setVisible(True)
+ .IsMinimized = False
+ .setFocus()
+ .setEnable(True) &apos; Added to try to bypass desynchro issue in Linux
+ .toFront() &apos; Added to force window change in Linux
+ End With
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;OBJECT&quot;), pvObjectName))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; SelectObject V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SendObject(ByVal Optional pvObjectType As Variant _
+ , ByVal Optional pvObjectName As Variant _
+ , ByVal Optional pvOutputFormat As Variant _
+ , ByVal Optional pvTo As Variant _
+ , ByVal Optional pvCc As Variant _
+ , ByVal Optional pvBcc As Variant _
+ , ByVal Optional pvSubject As Variant _
+ , ByVal Optional pvMessageText As Variant _
+ , ByVal Optional pvEditMessage As Variant _
+ , ByVal Optional pvTemplateFile As Variant _
+ ) As Boolean
+&apos;Supported: acFormatPDF, acFormatODT, acFormatDOC, acFormatHTML for forms
+&apos;To be prepared: acFormatCSV and acFormatODS for tables/queries ?
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;SendObject&quot;)
+ SendObject = False
+
+ If IsMissing(pvObjectType) Then pvObjectType = acSendNoObject
+ If Not Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), Array(acSendNoObject, acSendForm)) Then Goto Exit_Function
+ If IsMissing(pvObjectName) Then pvObjectName = &quot;&quot;
+ If Not Utils._CheckArgument(pvObjectName, 2,vbString) Then Goto Exit_Function
+ If IsMissing(pvOutputFormat) Then pvOutputFormat = &quot;&quot;
+ If Not Utils._CheckArgument(pvOutputFormat, 3, vbString) Then Goto Exit_Function
+ If pvOutputFormat &lt;&gt; &quot;&quot; Then
+ If Not Utils._CheckArgument(UCase(pvOutputFormat), 3, vbString, Array( _
+ UCase(acFormatPDF), UCase(acFormatODT), UCase(acFormatDOC), UCase(acFormatHTML) _
+ , &quot;PDF&quot;, &quot;ODT&quot;, &quot;DOC&quot;, &quot;HTML&quot;, &quot;&quot; _
+ )) Then Goto Exit_Function &apos; A 2nd time to allow case unsensitivity
+ End If
+ If IsMissing(pvTo) Then pvTo = &quot;&quot;
+ If Not Utils._CheckArgument(pvTo, 4, vbString) Then Goto Exit_Function
+ If IsMissing(pvCc) Then pvCc = &quot;&quot;
+ If Not Utils._CheckArgument(pvCc, 5, vbString) Then Goto Exit_Function
+ If IsMissing(pvBcc) Then pvBcc = &quot;&quot;
+ If Not Utils._CheckArgument(pvBcc, 6, vbString) Then Goto Exit_Function
+ If IsMissing(pvSubject) Then pvSubject = &quot;&quot;
+ If Not Utils._CheckArgument(pvSubject, 7, vbString) Then Goto Exit_Function
+ If IsMissing(pvMessageText) Then pvMessageText = &quot;&quot;
+ If Not Utils._CheckArgument(pvMessageText, 8, vbString) Then Goto Exit_Function
+ If IsMissing(pvEditMessage) Then pvEditMessage = True
+ If Not Utils._CheckArgument(pvEditMessage, 9, vbBoolean) Then Goto Exit_Function
+ If IsMissing(pvTemplateFile) Then pvTemplateFile = &quot;&quot;
+ If Not Utils._CheckArgument(pvTemplateFile, 10, vbString, &quot;&quot;) Then Goto Exit_Function
+
+Dim vTo() As Variant, vCc() As Variant, vBcc() As Variant, oWindow As Object
+Dim sDirectory As String, sOutputFile As String, sSuffix As String, sOutputFormat As String
+Const cstSemiColon = &quot;;&quot;
+ If pvTo &lt;&gt; &quot;&quot; Then vTo() = Split(pvTo, cstSemiColon) Else vTo() = Array()
+ If pvCc &lt;&gt; &quot;&quot; Then vCc() = Split(pvCc, cstSemiColon) Else vCc() = Array()
+ If pvBcc &lt;&gt; &quot;&quot; Then vBcc() = Split(pvBcc, cstSemiColon) Else vBcc() = Array()
+ Select Case True
+ Case pvObjectType = acSendNoObject And pvObjectName = &quot;&quot;
+ SendObject = _SendWithoutAttachment(vTo, vCc, vBcc, pvSubject, pvMessageText)
+ Case Else
+ If pvObjectType = acSendNoObject And pvObjectName &lt;&gt; &quot;&quot; Then
+ If Not FileExists(pvObjectName) Then Goto Error_File
+ sOutputFile = pvObjectName
+ Else &apos; OutputFile has to be created
+ If pvObjectType &lt;&gt; acSendNoObject And pvObjectName = &quot;&quot; Then
+ oWindow = _SelectWindow()
+ If oWindow.WindowType &lt;&gt; acSendForm Then Goto Error_Action
+ pvObjectType = acSendForm
+ pvObjectName = oWindow._Name
+ End If
+ sDirectory = Utils._getTempDirectoryURL()
+ If Right(sDirectory, 1) &lt;&gt; &quot;/&quot; Then sDirectory = sDirectory &amp; &quot;/&quot;
+ If pvOutputFormat = &quot;&quot; Then
+ sOutputFormat = _PromptFormat(Array(&quot;PDF&quot;, &quot;ODT&quot;, &quot;DOC&quot;, &quot;HTML&quot;)) &apos; Prompt user for format
+ If sOutputFormat = &quot;&quot; Then Goto Exit_Function
+ Else
+ sOutputFormat = UCase(pvOutputFormat)
+ End If
+ Select Case sOutputFormat
+ Case UCase(acFormatPDF), &quot;PDF&quot; : sSuffix = &quot;pdf&quot;
+ Case UCase(acFormatDOC), &quot;DOC&quot; : sSuffix = &quot;doc&quot;
+ Case UCase(acFormatODT), &quot;ODT&quot; : sSuffix = &quot;odt&quot;
+ Case UCase(acFormatHTML), &quot;HTML&quot; : sSuffix = &quot;html&quot;
+ End Select
+ sOutputFile = sDirectory &amp; pvObjectName &amp; &quot;.&quot; &amp; sSuffix
+ If Not OutputTo(pvObjectType, pvObjectName, sOutputFormat, sOutputFile, False) Then Goto Exit_Function
+ End If
+ SendObject = _SendWithAttachment(vTo, vCc, vBcc, pvSubject, Array(sOutputFile), pvMessageText, pvEditMessage)
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SendObject&quot;)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;OBJECT&quot;), pvObjectName))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SendObject&quot;, Erl)
+ GoTo Exit_Function
+Error_Action:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_File:
+ TraceError(TRACEFATAL, ERRFILEACCESS, Utils._CalledSub(), 0, , pvObjectName)
+ Goto Exit_Function
+End Function &apos; SendObject V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SetHiddenAttribute(ByVal Optional pvObjectType As Variant _
+ , ByVal Optional pvObjectName As Variant _
+ , ByVal Optional pvHidden As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ SetHiddenAttribute = False
+Const cstThisSub = &quot;SetHiddenAttribute&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ If IsMissing(pvObjectType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvObjectType, 1, Utils._AddNumeric(), _
+ Array(acDiagram, acForm, acQuery, acTable, acReport, acBasicIDE, acDatabaseWindow), acDocument _
+ ) Then Goto Exit_Function
+ If IsMissing(pvObjectName) Then
+ Select Case pvObjectType
+ Case acForm, acQuery, acTable, acReport, acDocument : Call _TraceArguments()
+ Case Else
+ End Select
+ pvObjectName = &quot;&quot;
+ Else
+ If Not Utils._CheckArgument(pvObjectName, 2, vbString) Then Goto Exit_Function
+ End If
+ If IsMissing(pvHidden) Then
+ pvHidden = True
+ Else
+ If Not Utils._CheckArgument(pvHidden, 3, vbBoolean) Then Goto Exit_Function
+ End If
+
+Dim oWindow As Object
+ Set oWindow = _SelectWindow(pvObjectType, pvObjectName)
+ If IsNull(oWindow.Frame) Then Goto Error_NotFound
+ oWindow.Frame.ContainerWindow.setVisible(Not pvHidden)
+ SetHiddenAttribute = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;OBJECT&quot;), pvObjectName))
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; SetHiddenAttribute V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SetOrderBy( _
+ ByVal Optional pvOrder As Variant _
+ , ByVal Optional pvControlName As Variant _
+ ) As Boolean
+&apos; Sort ann open table, query, form or subform (if pvControlName present)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;SetOrderBy&quot;
+ Utils._SetCalledSub(cstThisSub)
+ SetOrderBy = False
+
+ If IsMissing(pvOrder) Then pvOrder = &quot;&quot;
+ If Not Utils._CheckArgument(pvOrder, 1, vbString) Then Goto Exit_Function
+ If IsMissing(pvControlName) Then pvControlName = &quot;&quot;
+ If Not Utils._CheckArgument(pvControlName, 1, vbString) Then Goto Exit_Function
+
+Dim sOrder As String, oWindow As Object, oDatabase As Object, oTarget As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+ sOrder = oDatabase._ReplaceSquareBrackets(pvOrder)
+
+ Set oWindow = _SelectWindow()
+ With oWindow
+ Select Case .WindowType
+ Case acForm
+ Set oTarget = _DatabaseForm(._Name, pvControlName)
+ Case acQuery, acTable
+ If pvControlName &lt;&gt; &quot;&quot; Then Goto Exit_Function
+ If IsNull(.Frame.Controller.FormOperations) Then Goto Error_NotApplicable
+ &apos; FormOperations returns &lt;Null&gt; in OpenOffice
+ Set oTarget = .Frame.Controller.FormOperations.Cursor
+ Case Else &apos; Ignore action
+ Goto Exit_Function
+ End Select
+ End With
+
+ With oTarget
+ .Order = sOrder
+ .reload()
+ End With
+ SetOrderBy = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; SetOrderBy V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ShowAllrecords() As Boolean
+&apos; Removes any existing filter that exists on the current table, query or form
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;ShowAllRecords&quot;
+ Utils._SetCalledSub(cstThisSub)
+ ShowAllRecords = False
+
+Dim oWindow As Object, oDatabase As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+ Set oWindow = _SelectWindow()
+ Select Case oWindow.WindowType
+ Case acForm, acQuery, acTable
+ RunCommand(acCmdRemoveFilterSort)
+ ShowAllrecords = True
+ Case Else &apos; Ignore action
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; ShowAllrecords V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _CheckColumnType(pvFindWhat As Variant, vDataField As Variant) As Boolean
+&apos; Return true if both arguments of the same type
+&apos; vDataField is a ResultSet column
+
+Dim bFound As Boolean
+ bFound = False
+ With com.sun.star.sdbc.DataType
+ Select Case vDataField.Type
+ Case .DATE, .TIME, .TIMESTAMP
+ If VarType(pvFindWhat) = vbDate Then bFound = True
+ Case .TINYINT, .SMALLINT, .INTEGER, .BIGINT, .FLOAT, .REAL, .DOUBLE, .NUMERIC, .DECIMAL
+ If Utils._InList(VarType(pvFindWhat), Utils._AddNumeric()) Then bFound = True
+ Case .CHAR, .VARCHAR, .LONGVARCHAR
+ If VarType(pvFindWhat) = vbString Then bFound = True
+ Case Else
+ End Select
+ End With
+
+ _CheckColumnType = bFound
+
+End Function &apos; _CheckColumnType V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Sub _ConvertDataDescriptor( ByRef poSource As Object _
+ , ByVal piSourceRDBMS As Integer _
+ , ByRef poTarget As Object _
+ , ByRef poDatabase As Object _
+ , ByVal Optional pbKey As Boolean _
+ )
+&apos; Convert source column descriptor to target descriptor
+&apos; If RDMSs identical, simply move property by property
+&apos; Otherwise
+&apos; - Use Type conversion tables (cfr. DataTypes By RDBMS.ods case study)
+&apos; - Select among synonyms the entry with the lowest Precision at least &gt;= source Precision
+&apos; - Derive TypeName and Precision values
+
+Dim vTypesReference() As Variant, vTypes() As Variant, vTypeNames() As Variant
+Dim i As Integer, iType As Integer, iTypeAlias As Integer
+Dim iNbTypes As Integer, iBestFit As Integer, lFitPrecision As Long, lPrecision As Long
+
+ On Local Error Goto Error_Sub
+ If IsMissing(pbKey) Then pbKey = False
+
+ poTarget.Name = poSource.Name
+ poTarget.Description = poSource.Description
+ If Not pbKey Then
+ poTarget.ControlDefault = poSource.ControlDefault
+ poTarget.FormatKey = poSource.FormatKey
+ poTarget.HelpText = poSource.HelpText
+ poTarget.Hidden = poSource.Hidden
+ End If
+ poTarget.IsCurrency = poSource.IsCurrency
+ poTarget.IsNullable = poSource.IsNullable
+ poTarget.Scale = poSource.Scale
+
+ If piSourceRDBMS = poDatabase._RDBMS Or poDatabase._RDBMS = DBMS_UNKNOWN Then
+ poTarget.Type = poSource.Type
+ poTarget.Precision = poSource.Precision
+ poTarget.TypeName = poSource.TypeName
+ Goto Exit_Sub
+ End If
+
+ &apos; Search DataType compatibility
+ With poDatabase
+ &apos; Find source datatype entry in Reference array
+ iType = -1
+ For i = 0 To UBound(._ColumnTypesReference)
+ If ._ColumnTypesReference(i) = poSource.Type Then
+ iType = i
+ Exit For
+ End If
+ Next i
+ If iType = -1 Then Goto Error_Compatibility
+ iTypeAlias = ._ColumnTypesAlias(iType)
+ &apos; Find best choice for the datatype of the target column
+ iNbTypes = UBound(._ColumnTypes)
+ iBestFit = -1
+ lFitPrecision = -2 &apos; Some POSTGRES datatypes have a precision of -1
+ For i = 0 To iNbTypes
+ If ._ColumnTypes(i) = iTypeAlias Then &apos; Minimal fit = correct datatype
+ lPrecision = ._ColumnPrecisions(i)
+ If iBestFit = -1 _
+ Or (iBestFit &gt; -1 And poSource.Precision &gt; 0 And lPrecision &gt;= poSource.Precision And lPrecision &lt; lFitPrecision) _
+ Or (iBestFit &gt; -1 And poSource.Precision = 0 And lPrecision &gt; lFitPrecision) Then &apos; First fit or better fit
+ iBestFit = i
+ lFitPrecision = lPrecision
+ End If
+ End If
+ Next i
+ If iBestFit = -1 Then Goto Error_Compatibility
+ poTarget.Type = iTypeAlias
+ poTarget.Precision = lFitPrecision
+ poTarget.TypeName = ._ColumnTypeNames(iBestFit)
+ End With
+
+Exit_Sub:
+ Exit Sub
+Error_Compatibility:
+ TraceError(TRACEFATAL, ERRCOMPATIBILITY, Utils._CalledSub(), 0, 1, poSource.Name)
+ Goto Exit_Sub
+Error_Sub:
+ TraceError(TRACEABORT, Err, &quot;_ConvertDataDescriptor&quot;, Erl)
+ Goto Exit_Sub
+End Sub &apos; ConvertDataDescriptor V1.6.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _DatabaseForm(psForm As String, psControl As String)
+&apos;Return DatabaseForm element of Form object (based on psForm which is known as a real form name)
+&apos;or of SubForm object (based on psControl which is checked for being a subform)
+
+Dim oForm As Object, oControl As Object, sControls() As String, iControlCount As Integer
+Dim bFound As Boolean, i As Integer, sName As String
+
+ Set oForm = Application.Forms(psForm)
+ If psControl &lt;&gt; &quot;&quot; Then &apos; Search subform
+ With oForm.DatabaseForm
+ iControlCount = .getCount()
+ bFound = False
+ If iControlCount &gt; 0 Then
+ sControls() = .getElementNames()
+ sName = UCase(Utils._Trim(psControl))
+ For i = 0 To iControlCount - 1
+ If UCase(sControls(i)) = sName Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ End If
+ End With
+ If bFound Then sName = sControls(i) Else Goto Trace_NotFound
+ Set oControl = oForm.Controls(sName)
+ If oControl._SubType &lt;&gt; CTLSUBFORM Then Goto Trace_SubFormNotFound
+ Set _DatabaseForm = oControl.Form.DatabaseForm
+ Else
+ Set _DatabaseForm = oForm.DatabaseForm
+ End If
+
+Exit_Function:
+ Exit Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERRCONTROLNOTFOUND, Utils._CalledSub(), 0, , Array(psControl, psForm))
+ Goto Exit_Function
+Trace_SubFormNotFound:
+ TraceError(TRACEFATAL, ERRSUBFORMNOTFOUND, Utils._CalledSub(), 0, , Array(psControl, psForm))
+ Goto Exit_Function
+End Function &apos; _DatabaseForm V1.2.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub _DispatchCommand(ByVal psCommand As String)
+&apos; Execute command given as argument - &quot;.uno:&quot; is presumed already present
+Dim oDocument As Object, oDispatcher As Object, oArgs() As new com.sun.star.beans.PropertyValue, sTargetFrameName As String
+Dim oResult As Variant
+Dim sCommand As String
+
+ Set oDocument = _SelectWindow().Frame
+ Set oDispatcher = createUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;)
+ sTargetFrameName = &quot;&quot;
+ oResult = oDispatcher.executeDispatch(oDocument, psCommand, sTargetFrameName, 0, oArgs())
+
+End Sub &apos; _DispatchCommand V1.3.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _getUpperShortcut(ByVal psShortcut As String, ByVal psLastComponent As String) As String
+&apos; Return &quot;Forms!myForm&quot; from &quot;Forms!myForm!datField&quot; and &quot;datField&quot;
+
+ If Len(psShortcut) &gt; Len(psLastComponent) Then
+ _getUpperShortcut = Split(psShortcut, &quot;!&quot; &amp; Utils._Surround(psLastComponent))(0)
+ Else
+ _getUpperShortcut = psShortcut
+ End If
+
+End Function &apos; _getUpperShortcut
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _OpenObject(ByVal psObjectType As String _
+ , ByVal pvObjectName As Variant _
+ , ByVal pvView As Variant _
+ , ByVal pvDataMode As Variant _
+ ) As Boolean
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ _OpenObject = False
+ If Not (Utils._CheckArgument(pvObjectName, 1, vbString) _
+ And Utils._CheckArgument(pvView, 2, Utils._AddNumeric(), Array(acViewNormal, acViewPreview, acViewDesign)) _
+ And Utils._CheckArgument(pvDataMode, 3, Utils._AddNumeric(), Array(acEdit)) _
+ ) Then Goto Exit_Function
+Dim oDatabase As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+Dim sObjects() As String, sObjectName As String, oController As Object, oObject As Object
+Dim i As Integer, bFound As Boolean, lComponent As Long, oQuery As Object
+
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ Select Case psObjectType
+ Case &quot;Table&quot;
+ sObjects = oDatabase.Connection.getTables.ElementNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.TABLE
+ Case &quot;Query&quot;
+ sObjects = oDatabase.Connection.getQueries.ElementNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.QUERY
+ Case &quot;Report&quot;
+ sObjects = oDatabase.Document.getReportDocuments.ElementNames()
+ lComponent = com.sun.star.sdb.application.DatabaseObject.REPORT
+ End Select
+ bFound = False
+ For i = 0 To UBound(sObjects)
+ If UCase(pvObjectName) = UCase(sObjects(i)) Then
+ sObjectName = sObjects(i)
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+
+ If psObjectType = &quot;Query&quot; Then &apos; Processing for action query
+ Set oQuery = Application._CurrentDb().QueryDefs(pvObjectName)
+ If oQuery.pType &lt;&gt; dbQSelect Then
+ _OpenObject = oQuery.Execute()
+ GoTo Exit_Function
+ End If
+ End If
+ Set oController = oDatabase.Document.CurrentController
+ Set oObject = oController.loadComponent(lComponent, sObjectName, ( pvView = acViewDesign ))
+ _OpenObject = True
+
+Exit_Function:
+ Set oObject = Nothing
+ Set oQuery = Nothing
+ Set oController = Nothing
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OpenObject&quot;, Erl)
+ GoTo Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERROPENOBJECT, Utils._CalledSub(), 0, , Array(_GetLabel(psObjectType), pvObjectName))
+ Goto Exit_Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0, 1)
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(psObjectType), pvObjectName))
+ Goto Exit_Function
+End Function &apos; _OpenObject V0.8.9
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PromptFormat(ByVal pvList As Variant) As String
+&apos; Return user selection in Format dialog
+
+Dim oDialog As Object, iOKCancel As Integer, oControl As Object
+
+ Set oDialog = CreateUnoDialog(Utils._GetDialogLib().dlgFormat)
+ oDialog.Title = _GetLabel(&quot;DLGFORMAT_TITLE&quot;)
+
+ Set oControl = oDialog.Model.getByName(&quot;lblFormat&quot;)
+ oControl.Label = _GetLabel(&quot;DLGFORMAT_LBLFORMAT_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGFORMAT_LBLFORMAT_HELP&quot;)
+
+ Set oControl = oDialog.Model.getByName(&quot;cboFormat&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGFORMAT_LBLFORMAT_HELP&quot;)
+
+ Set oControl = oDialog.Model.getByName(&quot;cmdOK&quot;)
+ oControl.Label = _GetLabel(&quot;DLGFORMAT_CMDOK_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGFORMAT_CMDOK_HELP&quot;)
+
+ Set oControl = oDialog.Model.getByName(&quot;cmdCancel&quot;)
+ oControl.Label = _GetLabel(&quot;DLGFORMAT_CMDCANCEL_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGFORMAT_CMDCANCEL_HELP&quot;)
+
+ Set oControl = oDialog.Model.getByName(&quot;cboFormat&quot;)
+ If UBound(pvList) &gt;= 0 Then
+ oControl.Text = pvList(0)
+ oControl.StringItemList = pvList
+ Else
+ oControl.Text = &quot;&quot;
+ oControl.StringItemList = Array()
+ End If
+
+ iOKCancel = oDialog.Execute()
+ Select Case iOKCancel
+ Case 1 &apos; OK
+ _PromptFormat = oControl.Text
+ Case 0 &apos; Cancel
+ _PromptFormat = &quot;&quot;
+ Case Else
+ End Select
+ oDialog.Dispose()
+
+End Function &apos; _PromptFormat V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _SelectWindow(Optional ByVal piWindowType As Integer, Optional ByVal psWindow As String) As Object
+&apos; No argument: find active window
+&apos; 2 arguments: find corresponding window
+&apos; Return a _Window object type describing the found window
+
+Dim oEnum As Object, oDesk As Object, oComp As Object, oFrame As Object, i As Integer
+Dim bFound As Boolean, bActive As Boolean, sName As String, iType As Integer, sDocumentType As String
+Dim sImplementation As String, vLocation() As Variant
+Dim oWindow As _Window
+Dim vPersistent As Variant, oForm As Object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ bActive = IsMissing(piWindowType)
+ If IsMissing(psWindow) Then psWindow = &quot;&quot;
+ Set oWindow.Frame = Nothing
+ oWindow.DocumentType = &quot;&quot;
+ If bActive Then
+ oWindow.WindowType = acDefault
+ oWindow._Name = &quot;&quot;
+ Else
+ oWindow.WindowType = piWindowType
+ Select Case piWindowType
+ Case acBasicIDE, acDatabaseWindow : oWindow._Name = &quot;&quot;
+ Case Else : oWindow._Name = psWindow
+ End Select
+ End If
+ iType = acDefault
+ sDocumentType = &quot;&quot;
+
+ Set oDesk = CreateUnoService(&quot;com.sun.star.frame.Desktop&quot;)
+ Set oEnum = oDesk.Components().createEnumeration
+ Do While oEnum.hasMoreElements
+ Set oComp = oEnum.nextElement
+ If Utils._hasUNOProperty(oComp, &quot;ImplementationName&quot;) Then sImplementation = oComp.ImplementationName Else sImplementation = &quot;&quot;
+ Select Case sImplementation
+ Case &quot;com.sun.star.comp.basic.BasicIDE&quot;
+ Set oFrame = oComp.CurrentController.Frame
+ iType = acBasicIDE
+ sName = &quot;&quot;
+ Case &quot;com.sun.star.comp.dba.ODatabaseDocument&quot;
+ Set oFrame = oComp.CurrentController.Frame
+ iType = acDatabaseWindow
+ sName = &quot;&quot;
+ Case &quot;SwXTextDocument&quot;
+ If HasUnoInterfaces(oComp, &quot;com.sun.star.frame.XModule&quot;) Then
+ Select Case oComp.Identifier
+ Case &quot;com.sun.star.sdb.FormDesign&quot; &apos; Form
+ iType = acForm
+ Case &quot;com.sun.star.sdb.TextReportDesign&quot; &apos; Report
+ iType = acReport
+ Case &quot;com.sun.star.text.TextDocument&quot; &apos; Writer
+ vLocation = Split(oComp.getLocation(), &quot;/&quot;)
+ If UBound(vLocation) &gt;= 0 Then sName = Join(Split(vLocation(UBound(vLocation)), &quot;%20&quot;), &quot; &quot;) Else sName = &quot;&quot;
+ iType = acDocument
+ sDocumentType = docWriter
+ End Select
+ If iType = acForm Then &apos; Identify persistent Form name
+ vPersistent = Split(oComp.StringValue, &quot;/&quot;)
+ sName = _GetHierarchicalName(vPersistent(UBound(vPersistent) - 1))
+ ElseIf iType = acReport Then &apos; Identify Report name
+ For i = 0 To UBound(oComp.Args())
+ If oComp.Args(i).Name = &quot;DocumentTitle&quot; Then
+ sName = oComp.Args(i).Value
+ Exit For
+ End If
+ Next i
+ End If
+ Set oFrame = oComp.CurrentController.Frame
+ End If
+ Case &quot;org.openoffice.comp.dbu.ODatasourceBrowser&quot;
+ Set oFrame = oComp.Frame
+ If Not IsEmpty(oComp.Selection) Then &apos; Empty for (F4) DatasourceBrowser !!
+ For i = 0 To UBound(oComp.Selection())
+ If oComp.Selection(i).Name = &quot;Command&quot; Then
+ sName = oComp.Selection(i).Value
+ ElseIf oComp.Selection(i).Name = &quot;CommandType&quot; Then
+ Select Case oComp.selection(i).Value
+ Case com.sun.star.sdb.CommandType.TABLE
+ iType = acTable
+ Case com.sun.star.sdb.CommandType.QUERY
+ iType = acQuery
+ Case com.sun.star.sdb.CommandType.COMMAND
+ iType = acQuery &apos; SQL for future use ?
+ End Select
+ End If
+ Next i
+ &apos; Else ignore
+ End If
+ Case &quot;org.openoffice.comp.dbu.OTableDesign&quot;, &quot;org.openoffice.comp.dbu.OQueryDesign&quot; &apos; Table or Query in Edit mode
+ If Not bActive Then
+ If UCase(Right(oComp.Title, Len(psWindow))) = UCase(psWindow) Then &apos; No rigorous mean found to identify Name
+ Set oFrame = oComp.Frame
+ Select Case sImplementation
+ Case &quot;org.openoffice.comp.dbu.OTableDesign&quot; : iType = acTable
+ Case &quot;org.openoffice.comp.dbu.OQueryDesign&quot; : iType = acQuery
+ End Select
+ sName = Right(oComp.Title, Len(psWindow))
+ End If
+ Else
+ Set oFrame = Nothing
+ End If
+ Case &quot;org.openoffice.comp.dbu.ORelationDesign&quot;
+ Set oFrame = oComp.Frame
+ iType = acDiagram
+ sName = &quot;&quot;
+ Case &quot;com.sun.star.comp.sfx2.BackingComp&quot; &apos; Welcome screen
+ Set oFrame = oComp.Frame
+ iType = acWelcome
+ sName = &quot;&quot;
+ Case Else &apos; Other Calc, ..., whatever documents
+ If Utils._hasUNOProperty(oComp, &quot;Location&quot;) Then
+ vLocation = Split(oComp.getLocation(), &quot;/&quot;)
+ If UBound(vLocation) &gt;= 0 Then sName = Join(Split(vLocation(UBound(vLocation)), &quot;%20&quot;), &quot; &quot;) Else sName = &quot;&quot;
+ iType = acDocument
+ If Utils._hasUNOProperty(oComp, &quot;Identifier&quot;) Then
+ Select Case oComp.Identifier
+ Case &quot;com.sun.star.sheet.SpreadsheetDocument&quot; : sDocumentType = docCalc
+ Case &quot;com.sun.star.presentation.PresentationDocument&quot; : sDocumentType = docImpress
+ Case &quot;com.sun.star.drawing.DrawingDocument&quot; : sDocumentType = docDraw
+ Case &quot;com.sun.star.formula.FormulaProperties&quot; : sDocumentType = docMath
+ Case Else : sDocumentType = &quot;&quot;
+ End Select
+ End If
+ Set oFrame = oComp.CurrentController.Frame
+ End If
+ End Select
+ If bActive And Not IsNull(oFrame) Then
+ If oFrame.ContainerWindow.IsActive() Then
+ bFound = True
+ Exit Do
+ End If
+ ElseIf iType = piWindowType And UCase(sName) = UCase(psWindow) Then
+ bFound = True
+ Exit Do
+ End If
+ Loop
+
+ If bFound Then
+ Set oWindow.Frame = oFrame
+ oWindow._Name = sName
+ oWindow.WindowType = iType
+ oWindow.DocumentType = sDocumentType
+ Else
+ Set oWindow.Frame = Nothing
+ End If
+
+Exit_Function:
+ Set _SelectWindow = oWindow
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SelectWindow&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; _SelectWindow V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _SendWithAttachment( _
+ ByVal pvRecipients() As Variant _
+ , ByVal pvCcRecipients() As Variant _
+ , ByVal pvBccRecipients() As Variant _
+ , ByVal psSubject As String _
+ , ByVal pvAttachments() As Variant _
+ , ByVal pvBody As String _
+ , ByVal pbEditMessage As Boolean _
+ ) As Boolean
+
+&apos; Send message with attachments
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _SendWithAttachment = False
+
+Const cstWindows = 1
+Const cstLinux = 4
+Const cstSemiColon = &quot;;&quot;
+Dim oServiceMail as Object, oMail As Object, oMessage As Object, vFlag As Variant
+Dim vCc() As Variant, i As Integer, iOS As Integer, sProduct As String, bMailProvider As Boolean
+
+ &apos;OPENOFFICE &lt;= 3.6 and LIBREOFFICE have XSimple...Mail interface while OPENOFFICE &gt;= 4.0 has XSystemMailProvider interface
+ sProduct = UCase(Utils._GetProductName())
+ bMailProvider = ( Left(sProduct, 4) = &quot;OPEN&quot; And Left(_GetProductName(&quot;VERSION&quot;), 3) &gt;= &quot;4.0&quot; )
+
+ iOS = GetGuiType()
+ Select Case iOS
+ Case cstLinux
+ oServiceMail = createUnoService(&quot;com.sun.star.system.SimpleCommandMail&quot;)
+ Case cstWindows
+ If bMailProvider Then oServiceMail = createUnoService(&quot;com.sun.star.system.SystemMailProvider&quot;) _
+ Else oServiceMail = createUnoService(&quot;com.sun.star.system.SimpleSystemMail&quot;)
+ Case Else
+ Goto Error_Mail
+ End Select
+
+ If bMailProvider Then Set oMail = oServiceMail.queryMailClient() _
+ Else Set oMail = oServiceMail.querySimpleMailClient()
+ If IsNull(oMail) Then Goto Error_Mail
+
+ &apos;Reattribute Recipients &gt;= 2nd to ccRecipients
+ If UBound(pvRecipients) &lt;= 0 Then
+ If UBound(pvCcRecipients) &gt;= 0 Then vCc = pvCcRecipients
+ Else
+ ReDim vCc(0 To UBound(pvRecipients) - 1 + UBound(pvCcRecipients) + 1)
+ For i = 0 To UBound(pvRecipients) - 1
+ vCc(i) = pvRecipients(i + 1)
+ Next i
+ For i = UBound(pvRecipients) To UBound(vCc)
+ vCc(i) = pvCcRecipients(i - UBound(pvRecipients))
+ Next i
+ End If
+
+ If bMailProvider Then
+ Set oMessage = oMail.createMailMessage()
+ If UBound(pvRecipients) &gt;= 0 Then oMessage.Recipient = pvRecipients(0)
+ If psSubject &lt;&gt; &quot;&quot; Then oMessage.Subject = psSubject
+ Select Case iOS &apos; Not published differences between com.sun.star.system.SimpleCommandMail and SimpleSystemMail
+ Case cstLinux
+ If UBound(vCc) &gt;= 0 Then oMessage.CcRecipient = Array(Join(vCc, cstSemiColon))
+ If UBound(pvBccRecipients) &gt;= 0 Then oMessage.BccRecipient = Array(Join(pvBccRecipients, cstSemiColon))
+ Case cstWindows
+ If UBound(vCc) &gt;= 0 Then oMessage.CcRecipient = vCc
+ If UBound(pvBccRecipients) &gt;= 0 Then oMessage.BccRecipient = pvBccRecipients
+ End Select
+ If UBound(pvAttachments) &gt;= 0 Then oMessage.Attachement = pvAttachments
+ If pvBody &lt;&gt; &quot;&quot; Then oMessage.Body = pvBody
+ If pbEditMessage Then
+ vFlag = com.sun.star.system.MailClientFlags.DEFAULTS
+ Else
+ vFlag = com.sun.star.system.MailClientFlags.NO_USER_INTERFACE
+ End If
+ oMail.sendMailMessage(oMessage, vFlag)
+ Else
+ Set oMessage = oMail.createSimpleMailMessage() &apos; Body NOT SUPPORTED !
+ If UBound(pvRecipients) &gt;= 0 Then oMessage.setRecipient(pvRecipients(0))
+ If psSubject &lt;&gt; &quot;&quot; Then oMessage.setSubject(psSubject)
+ Select Case iOS
+ Case cstLinux
+ If UBound(vCc) &gt;= 0 Then oMessage.setCcRecipient(Array(Join(vCc, cstSemiColon)))
+ If UBound(pvBccRecipients) &gt;= 0 Then oMessage.setBccRecipient(Array(Join(pvBccRecipients, cstSemiColon)))
+ Case cstWindows
+ If UBound(vCc) &gt;= 0 Then oMessage.setCcRecipient(vCc)
+ If UBound(pvBccRecipients) &gt;= 0 Then oMessage.setBccRecipient(pvBccRecipients)
+ End Select
+ If UBound(pvAttachments) &gt;= 0 Then oMessage.setAttachement(pvAttachments)
+ If pbEditMessage Then
+ vFlag = com.sun.star.system.SimpleMailClientFlags.DEFAULTS
+ Else
+ vFlag = com.sun.star.system.SimpleMailClientFlags.NO_USER_INTERFACE
+ End If
+ oMail.sendSimpleMailMessage(oMessage, vFlag)
+ End If
+
+ _SendWithAttachment = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;_SendWithAttachment&quot;, Erl)
+ Goto Exit_Function
+Error_Mail:
+ TraceError(TRACEFATAL, ERRSENDMAIL, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; _SendWithAttachment V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _SendWithoutAttachment(ByVal pvTo As Variant _
+ , ByVal pvCc As Variant _
+ , ByVal pvBcc As Variant _
+ , ByVal psSubject As String _
+ , ByVal psBody As String _
+ ) As Boolean
+&apos;Send simple message with mailto: syntax
+Dim sMailTo As String, sTo As String, sCc As String, sBcc As String, oDispatch As Object
+Const cstComma = &quot;,&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If UBound(pvTo) &gt;= 0 Then sTo = Trim(Join(pvTo, cstComma)) Else sTo = &quot;&quot;
+ If UBound(pvCc) &gt;= 0 Then sCc = Trim(Join(pvCc, cstComma)) Else sCc = &quot;&quot;
+ If UBound(pvBcc) &gt;= 0 Then sBcc = Trim(Join(pvBcc, cstComma)) Else sBcc = &quot;&quot;
+
+ sMailTo = &quot;mailto:&quot; _
+ &amp; sTo &amp; &quot;?&quot; _
+ &amp; Iif(sCc = &quot;&quot;, &quot;&quot;, &quot;cc=&quot; &amp; sCc &amp; &quot;&amp;&quot;) _
+ &amp; Iif(sBcc = &quot;&quot;, &quot;&quot;, &quot;bcc=&quot; &amp; sBcc &amp; &quot;&amp;&quot;) _
+ &amp; Iif(psSubject = &quot;&quot;, &quot;&quot;, &quot;subject=&quot; &amp; psSubject &amp; &quot;&amp;&quot;) _
+ &amp; Iif(psBody = &quot;&quot;, &quot;&quot;, &quot;body=&quot; &amp; psBody &amp; &quot;&amp;&quot;)
+ If Right(sMailTo, 1) = &quot;&amp;&quot; Or Right(sMailTo, 1) = &quot;?&quot; Then sMailTo = Left(sMailTo, Len(sMailTo) - 1)
+ sMailTo = ConvertToUrl(sMailTo)
+
+ oDispatch = createUnoService( &quot;com.sun.star.frame.DispatchHelper&quot;)
+ oDispatch.executeDispatch(StarDesktop, sMailTo, &quot;&quot;, 0, Array())
+
+ _SendWithoutAttachment = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;_SendWithoutAttachments&quot;, Erl)
+ _SendWithoutAttachment = False
+ Goto Exit_Function
+End Function &apos; _SendWithoutAttachment V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub _ShellExecute(sCommand As String)
+&apos; Execute shell command
+
+Dim oShell As Object
+ Set oShell = createUnoService(&quot;com.sun.star.system.SystemShellExecute&quot;)
+ oShell.execute(sCommand, &quot;&quot; , com.sun.star.system.SystemShellExecuteFlags.URIS_ONLY)
+
+End Sub &apos; _ShellExecute V0.8.5
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Event.xba b/wizards/source/access2base/Event.xba
new file mode 100644
index 000000000..eb5f23019
--- /dev/null
+++ b/wizards/source/access2base/Event.xba
@@ -0,0 +1,493 @@
+<?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="Event" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be EVENT
+Private _EventSource As Object
+Private _EventType As String
+Private _EventName As String
+Private _SubComponentName As String
+Private _SubComponentType As Long
+Private _ContextShortcut As String
+Private _ButtonLeft As Boolean &apos; com.sun.star.awt.MouseButton.XXX
+Private _ButtonRight As Boolean
+Private _ButtonMiddle As Boolean
+Private _XPos As Variant &apos; Null or Long
+Private _YPos As Variant &apos; Null or Long
+Private _ClickCount As Long
+Private _KeyCode As Integer &apos; com.sun.star.awt.Key.XXX
+Private _KeyChar As String
+Private _KeyFunction As Integer &apos; com.sun.star.awt.KeyFunction.XXX
+Private _KeyAlt As Boolean
+Private _KeyCtrl As Boolean
+Private _KeyShift As Boolean
+Private _FocusChangeTemporary As Boolean &apos; False if user action in same window
+Private _RowChangeAction As Long &apos; com.sun.star.sdb.RowChangeAction.XXX
+Private _Recommendation As String &apos; &quot;IGNORE&quot; or &quot;&quot;
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJEVENT
+ _EventSource = Nothing
+ _EventType = &quot;&quot;
+ _EventName = &quot;&quot;
+ _SubComponentName = &quot;&quot;
+ _SubComponentType = -1
+ _ContextShortcut = &quot;&quot;
+ _ButtonLeft = False &apos; See com.sun.star.awt.MouseButton.XXX
+ _ButtonRight = False
+ _ButtonMiddle = False
+ _XPos = Null
+ _YPos = Null
+ _ClickCount = 0
+ _KeyCode = 0
+ _KeyChar = &quot;&quot;
+ _KeyFunction = com.sun.star.awt.KeyFunction.DONTKNOW
+ _KeyAlt = False
+ _KeyCtrl = False
+ _KeyShift = False
+ _FocusChangeTemporary = False
+ _RowChangeAction = 0
+ _Recommendation = &quot;&quot;
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ButtonLeft() As Variant
+ ButtonLeft = _PropertyGet(&quot;ButtonLeft&quot;)
+End Property &apos; ButtonLeft (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ButtonMiddle() As Variant
+ ButtonMiddle = _PropertyGet(&quot;ButtonMiddle&quot;)
+End Property &apos; ButtonMiddle (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ButtonRight() As Variant
+ ButtonRight = _PropertyGet(&quot;ButtonRight&quot;)
+End Property &apos; ButtonRight (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ClickCount() As Variant
+ ClickCount = _PropertyGet(&quot;ClickCount&quot;)
+End Property &apos; ClickCount (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ContextShortcut() As Variant
+ ContextShortcut = _PropertyGet(&quot;ContextShortcut&quot;)
+End Property &apos; ContextShortcut (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get EventName() As Variant
+ EventName = _PropertyGet(&quot;EventName&quot;)
+End Property &apos; EventName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get EventSource() As Variant
+ EventSource = _PropertyGet(&quot;EventSource&quot;)
+End Property &apos; EventSource (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get EventType() As Variant
+ EventType = _PropertyGet(&quot;EventType&quot;)
+End Property &apos; EventType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FocusChangeTemporary() As Variant
+ FocusChangeTemporary = _PropertyGet(&quot;FocusChangeTemporary&quot;)
+End Property &apos; FocusChangeTemporary (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get KeyAlt() As Variant
+ KeyAlt = _PropertyGet(&quot;KeyAlt&quot;)
+End Property &apos; KeyAlt (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get KeyChar() As Variant
+ KeyChar = _PropertyGet(&quot;KeyChar&quot;)
+End Property &apos; KeyChar (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get KeyCode() As Variant
+ KeyCode = _PropertyGet(&quot;KeyCode&quot;)
+End Property &apos; KeyCode (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get KeyCtrl() As Variant
+ KeyCtrl = _PropertyGet(&quot;KeyCtrl&quot;)
+End Property &apos; KeyCtrl (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get KeyFunction() As Variant
+ KeyFunction = _PropertyGet(&quot;KeyFunction&quot;)
+End Property &apos; KeyFunction (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get KeyShift() As Variant
+ KeyShift = _PropertyGet(&quot;KeyShift&quot;)
+End Property &apos; KeyShift (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Recommendation() As Variant
+ Recommendation = _PropertyGet(&quot;Recommendation&quot;)
+End Property &apos; Recommendation (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get RowChangeAction() As Variant
+ RowChangeAction = _PropertyGet(&quot;RowChangeAction&quot;)
+End Property &apos; RowChangeAction (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Source() As Variant
+&apos; Return the object having fired the event: Form, Control or SubForm
+&apos; Else return the root Database object
+ Source = _PropertyGet(&quot;Source&quot;)
+End Function &apos; Source (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SubComponentName() As String
+ SubComponentName = _PropertyGet(&quot;SubComponentName&quot;)
+End Property &apos; SubComponentName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SubComponentType() As Long
+ SubComponentType = _PropertyGet(&quot;SubComponentType&quot;)
+End Property &apos; SubComponentType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get XPos() As Variant
+ XPos = _PropertyGet(&quot;XPos&quot;)
+End Property &apos; XPos (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get YPos() As Variant
+ YPos = _PropertyGet(&quot;YPos&quot;)
+End Property &apos; YPos (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Form.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;Form.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _Initialize(poEvent As Object)
+
+Dim oObject As Object, i As Integer
+Dim sShortcut As String, sAddShortcut As String, sArray() As String
+Dim sImplementation As String, oSelection As Object
+Dim iCurrentDoc As Integer, oDoc As Object
+Dim vPersistent As Variant
+Const cstDatabaseForm = &quot;com.sun.star.comp.forms.ODatabaseForm&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Set oObject = poEvent.Source
+ _EventSource = oObject
+ sArray = Split(Utils._getUNOTypeName(poEvent), &quot;.&quot;)
+ _EventType = UCase(sArray(UBound(sArray)))
+ If Utils._hasUNOProperty(poEvent, &quot;EventName&quot;) Then _EventName = poEvent.EventName
+
+ Select Case _EventType
+ Case &quot;DOCUMENTEVENT&quot;
+ &apos;SubComponent processing
+ Select Case UCase(_EventName)
+ Case UCase(&quot;OnSubComponentClosed&quot;), UCase(&quot;OnSubComponentOpened&quot;)
+ Set oSelection = poEvent.ViewController.getSelection()(0)
+ _SubComponentName = oSelection.Name
+ With com.sun.star.sdb.application.DatabaseObject
+ Select Case oSelection.Type
+ Case .TABLE : _SubComponentType = acTable
+ Case .QUERY : _SubComponentType = acQuery
+ Case .FORM : _SubComponentType = acForm
+ Case .REPORT : _SubComponentType = acReport
+ Case Else
+ End Select
+ End With
+ Case Else
+ End Select
+ Case &quot;EVENTOBJECT&quot;
+ Case &quot;ACTIONEVENT&quot;
+ Case &quot;FOCUSEVENT&quot;
+ _FocusChangeTemporary = poEvent.Temporary
+ Case &quot;ITEMEVENT&quot;
+ Case &quot;INPUTEVENT&quot;, &quot;KEYEVENT&quot;
+ _KeyCode = poEvent.KeyCode
+ _KeyChar = poEvent.KeyChar
+ _KeyFunction = poEvent.KeyFunc
+ _KeyAlt = Utils._BitShift(poEvent.Modifiers, com.sun.star.awt.KeyModifier.MOD2)
+ _KeyCtrl = Utils._BitShift(poEvent.Modifiers, com.sun.star.awt.KeyModifier.MOD1)
+ _KeyShift = Utils._BitShift(poEvent.Modifiers, com.sun.star.awt.KeyModifier.SHIFT)
+ Case &quot;MOUSEEVENT&quot;
+ _ButtonLeft = Utils._BitShift(poEvent.Buttons, com.sun.star.awt.MouseButton.LEFT)
+ _ButtonRight = Utils._BitShift(poEvent.Buttons, com.sun.star.awt.MouseButton.RIGHT)
+ _ButtonMiddle = Utils._BitShift(poEvent.Buttons, com.sun.star.awt.MouseButton.MIDDLE)
+ _XPos = poEvent.X
+ _YPos = poEvent.Y
+ _ClickCount = poEvent.ClickCount
+ Case &quot;ROWCHANGEEVENT&quot;
+ _RowChangeAction = poEvent.Action
+ Case &quot;TEXTEVENT&quot;
+ Case &quot;ADJUSTMENTEVENT&quot;, &quot;DOCKINGEVENT&quot;, &quot;ENDDOCKINGEVENT&quot;, &quot;ENDPOPUPMODEEVENT&quot;, &quot;ENHANCEDMOUSEEVENT&quot; _
+ , &quot;MENUEVENT&quot;, &quot;PAINTEVENT&quot;, &quot;SPINEVENT&quot;, &quot;VCLCONTAINEREVENT&quot;, &quot;WINDOWEVENT&quot;
+ Goto Exit_Function
+ Case Else
+ Goto Exit_Function
+ End Select
+
+ &apos; Evaluate ContextShortcut
+ sShortcut = &quot;&quot;
+ sImplementation = Utils._ImplementationName(oObject)
+
+ Select Case True
+ Case sImplementation = &quot;stardiv.Toolkit.UnoDialogControl&quot; &apos; Dialog
+ _ContextShortcut = &quot;Dialogs!&quot; &amp; _EventSource.Model.Name
+ Goto Exit_Function
+ Case Left(sImplementation, 16) = &quot;stardiv.Toolkit.&quot; &apos; Control in Dialog
+ _ContextShortcut = &quot;Dialogs!&quot; &amp; _EventSource.Context.Model.Name _
+ &amp; &quot;!&quot; &amp; _EventSource.Model.Name
+ Goto Exit_Function
+ Case Else
+ End Select
+
+ iCurrentDoc = _A2B_.CurrentDocIndex(, False)
+ If iCurrentDoc &lt; 0 Then Goto Exit_Function
+ Set oDoc = _A2B_.CurrentDocument(iCurrentDoc)
+
+ &apos; To manage 2x triggers of &quot;Before record action&quot; form event
+ If _EventType = &quot;ROWCHANGEEVENT&quot; And sImplementation &lt;&gt; &quot;com.sun.star.comp.forms.ODatabaseForm&quot; Then _Recommendation = &quot;IGNORE&quot;
+
+ Do While sImplementation &lt;&gt; &quot;SwXTextDocument&quot;
+ sAddShortcut = &quot;&quot;
+ Select Case sImplementation
+ Case &quot;com.sun.star.comp.forms.OFormsCollection&quot; &apos; Do nothing
+ Case Else
+ If Utils._hasUNOProperty(oObject, &quot;Model&quot;) Then
+ If oObject.Model.Name &lt;&gt; &quot;MainForm&quot; And oObject.Model.Name &lt;&gt; &quot;Form&quot; Then sAddShortcut = Utils._Surround(oObject.Model.Name)
+ ElseIf Utils._hasUNOProperty(oObject, &quot;Name&quot;) Then
+ If oObject.Name &lt;&gt; &quot;MainForm&quot; And oObject.Name &lt;&gt; &quot;Form&quot; Then sAddShortcut = Utils._Surround(oObject.Name)
+ End If
+ If sAddShortcut &lt;&gt; &quot;&quot; Then
+ If sImplementation = cstDatabaseForm And oDoc.DbConnect = DBCONNECTBASE Then sAddShortcut = sAddShortcut &amp; &quot;.Form&quot;
+ sShortcut = sAddShortcut &amp; Iif(Len(sShortcut) &gt; 0, &quot;!&quot; &amp; sShortcut, &quot;&quot;)
+ End If
+ End Select
+ Select Case True
+ Case Utils._hasUNOProperty(oObject, &quot;Model&quot;)
+ Set oObject = oObject.Model.Parent
+ Case Utils._hasUNOProperty(oObject, &quot;Parent&quot;)
+ Set oObject = oObject.Parent
+ Case Else
+ Goto Exit_Function
+ End Select
+ sImplementation = Utils._ImplementationName(oObject)
+ Loop
+ &apos; Add Forms! prefix
+ Select Case oDoc.DbConnect
+ Case DBCONNECTBASE
+ vPersistent = Split(oObject.StringValue, &quot;/&quot;)
+ sAddShortcut = Utils._Surround(_GetHierarchicalName(vPersistent(UBound(vPersistent) - 1)))
+ sShortcut = &quot;Forms!&quot; &amp; sAddShortcut &amp; &quot;!&quot; &amp; sShortcut
+ Case DBCONNECTFORM
+ sShortcut = &quot;Forms!0!&quot; &amp; sShortcut
+ End Select
+
+ sArray = Split(sShortcut, &quot;!&quot;)
+ &apos; If presence of &quot;Forms!myform!myform.Form&quot;, eliminate 2nd element
+ &apos; Eliminate anyway blanco subcomponents (e.g. Forms!!myForm)
+ If UBound(sArray) &gt;= 2 Then
+ If UCase(sArray(1)) &amp; &quot;.FORM&quot; = UCase(sArray(2)) Then sArray(1) = &quot;&quot;
+ sArray = Utils._TrimArray(sArray)
+ End If
+ &apos; If first element ends with .Form, remove suffix
+ If UBound(sArray) &gt;= 1 Then
+ If Len(sArray(1)) &gt; 5 And Right(sArray(1), 5) = &quot;.Form&quot; Then sArray(1) = left(sArray(1), Len(sArray(1)) - 5)
+ sShortcut = Join(sArray, &quot;!&quot;)
+ End If
+ If Len(sShortcut) &gt;= 2 Then
+ If Right(sShortcut, 1) = &quot;!&quot; Then
+ _ContextShortcut = Left(sShortcut, Len(sShortcut) - 1)
+ Else
+ _ContextShortcut = sShortcut
+ End If
+ End If
+
+Exit_Function:
+ Exit Sub
+Error_Function:
+ TraceError(TRACEWARNING, Err, &quot;Event.Initialize&quot;, Erl)
+ GoTo Exit_Function
+End Sub &apos; _Initialize V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+Dim sSubComponentName As String, sSubComponentType As String
+ sSubComponentName = Iif(_SubComponentType &gt; -1, &quot;SubComponentName&quot;, &quot;&quot;)
+ sSubComponentType = Iif(_SubComponentType &gt; -1, &quot;SubComponentType&quot;, &quot;&quot;)
+Dim sXPos As String, sYPos As String
+ sXPos = Iif(IsNull(_XPos), &quot;&quot;, &quot;XPos&quot;)
+ sYPos = Iif(IsNull(_YPos), &quot;&quot;, &quot;YPos&quot;)
+
+ _PropertiesList = Utils._TrimArray(Array( _
+ &quot;ButtonLeft&quot;, &quot;ButtonRight&quot;, &quot;ButtonMiddle&quot;, &quot;ClickCount&quot; _
+ , &quot;ContextShortcut&quot;, &quot;EventName&quot;, &quot;EventType&quot;, &quot;FocusChangeTemporary&quot;, _
+ , &quot;KeyAlt&quot;, &quot;KeyChar&quot;, &quot;KeyCode&quot;, &quot;KeyCtrl&quot;, &quot;KeyFunction&quot;, &quot;KeyShift&quot; _
+ , &quot;ObjectType&quot;, &quot;Recommendation&quot;, &quot;RowChangeAction&quot;, &quot;Source&quot; _
+ , sSubComponentName, sSubComponentType, sXPos, sYPos _
+ ))
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Event.get&quot; &amp; psProperty)
+
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;ButtonLeft&quot;)
+ _PropertyGet = _ButtonLeft
+ Case UCase(&quot;ButtonMiddle&quot;)
+ _PropertyGet = _ButtonMiddle
+ Case UCase(&quot;ButtonRight&quot;)
+ _PropertyGet = _ButtonRight
+ Case UCase(&quot;ClickCount&quot;)
+ _PropertyGet = _ClickCount
+ Case UCase(&quot;ContextShortcut&quot;)
+ _PropertyGet = _ContextShortcut
+ Case UCase(&quot;FocusChangeTemporary&quot;)
+ _PropertyGet = _FocusChangeTemporary
+ Case UCase(&quot;EventName&quot;)
+ _PropertyGet = _EventName
+ Case UCase(&quot;EventSource&quot;)
+ _PropertyGet = _EventSource
+ Case UCase(&quot;EventType&quot;)
+ _PropertyGet = _EventType
+ Case UCase(&quot;KeyAlt&quot;)
+ _PropertyGet = _KeyAlt
+ Case UCase(&quot;KeyChar&quot;)
+ _PropertyGet = _KeyChar
+ Case UCase(&quot;KeyCode&quot;)
+ _PropertyGet = _KeyCode
+ Case UCase(&quot;KeyCtrl&quot;)
+ _PropertyGet = _KeyCtrl
+ Case UCase(&quot;KeyFunction&quot;)
+ _PropertyGet = _KeyFunction
+ Case UCase(&quot;KeyShift&quot;)
+ _PropertyGet = _KeyShift
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Recommendation&quot;)
+ _PropertyGet = _Recommendation
+ Case UCase(&quot;RowChangeAction&quot;)
+ _PropertyGet = _RowChangeAction
+ Case UCase(&quot;Source&quot;)
+ If _ContextShortcut = &quot;&quot; Then
+ _PropertyGet = _EventSource
+ Else
+ _PropertyGet = getObject(_ContextShortcut)
+ End If
+ Case UCase(&quot;SubComponentName&quot;)
+ _PropertyGet = _SubComponentName
+ Case UCase(&quot;SubComponentType&quot;)
+ _PropertyGet = _SubComponentType
+ Case UCase(&quot;XPos&quot;)
+ If IsNull(_XPos) Then Goto Trace_Error
+ _PropertyGet = _XPos
+ Case UCase(&quot;YPos&quot;)
+ If IsNull(_YPos) Then Goto Trace_Error
+ _PropertyGet = _YPos
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Event.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ &apos; Errors are not displayed to avoid display infinite cycling
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, False, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Event._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet V1.1.0
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Field.xba b/wizards/source/access2base/Field.xba
new file mode 100644
index 000000000..1fe2f185e
--- /dev/null
+++ b/wizards/source/access2base/Field.xba
@@ -0,0 +1,923 @@
+<?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="Field" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be FIELD
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _Precision As Long
+Private _ParentName As String
+Private _ParentType As String
+Private _ParentDatabase As Object
+Private _ParentRecordset As Object
+Private _DefaultValue As String
+Private _DefaultValueSet As Boolean
+Private Column As Object &apos; com.sun.star.sdb.OTableColumnWrapper
+ &apos; or org.openoffice.comp.dbaccess.OQueryColumn
+ &apos; or com.sun.star.sdb.ODataColumn
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJFIELD
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ _ParentName = &quot;&quot;
+ _ParentType = &quot;&quot;
+ _DefaultValue = &quot;&quot;
+ _DefaultValueSet = False
+ Set Column = Nothing
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get DataType() As Long &apos; AOO/LibO type
+ DataType = _PropertyGet(&quot;DataType&quot;)
+End Property &apos; DataType (get)
+
+Property Get DataUpdatable() As Boolean
+ DataUpdatable = _PropertyGet(&quot;DataUpdatable&quot;)
+End Property &apos; DataUpdatable (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get DbType() As Long &apos; MSAccess type
+ DbType = _PropertyGet(&quot;DbType&quot;)
+End Property &apos; DbType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get DefaultValue() As Variant
+ DefaultValue = _PropertyGet(&quot;DefaultValue&quot;)
+End Property &apos; DefaultValue (get)
+
+Property Let DefaultValue(ByVal pvDefaultValue As Variant)
+ Call _PropertySet(&quot;DefaultValue&quot;, pvDefaultValue)
+End Property &apos; DefaultValue (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Description() As Variant
+ Description = _PropertyGet(&quot;Description&quot;)
+End Property &apos; Description (get)
+
+Property Let Description(ByVal pvDescription As Variant)
+ Call _PropertySet(&quot;Description&quot;, pvDescription)
+End Property &apos; Description (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FieldSize() As Long
+ FieldSize = _PropertyGet(&quot;FieldSize&quot;)
+End Property &apos; FieldSize (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Size() As Long
+ Size = _PropertyGet(&quot;Size&quot;)
+End Property &apos; Size (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SourceField() As String
+ SourceField = _PropertyGet(&quot;SourceField&quot;)
+End Property &apos; SourceField (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get SourceTable() As String
+ SourceTable = _PropertyGet(&quot;SourceTable&quot;)
+End Property &apos; SourceTable (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get TypeName() As String
+ TypeName = _PropertyGet(&quot;TypeName&quot;)
+End Property &apos; TypeName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Value() As Variant
+ Value = _PropertyGet(&quot;Value&quot;)
+End Property &apos; Value (get)
+
+Property Let Value(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Value&quot;, pvValue)
+End Property &apos; Value (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AppendChunk(ByRef Optional pvValue As Variant) As Boolean
+&apos; Store a chunk of string or binary characters into the current field, presumably a large object (CLOB or BLOB)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Field.AppendChunk&quot;
+ Utils._SetCalledSub(cstThisSub)
+ AppendChunk = False
+
+ If IsMissing(pvValue) Then Call _TraceArguments()
+
+ If _ParentType &lt;&gt; OBJRECORDSET Then Goto Trace_Error &apos; Not on table- or querydefs ... !
+ If Not Column.IsWritable Then Goto Trace_Error_Updatable
+ If Column.IsReadOnly Then Goto Trace_Error_Updatable
+ If _ParentDatabase.Recordsets(_ParentName)._EditMode = dbEditNone Then Goto Trace_Error_Update
+
+Dim iChunkType As Integer
+
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type &apos; DOES NOT WORK FOR CHARACTER TYPES
+&apos; Case .CHAR, .VARCHAR, .LONGVARCHAR, .CLOB
+&apos; iChunkType = vbString
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB, .CHAR &apos; .CHAR added for Sqlite3
+ iChunkType = vbByte
+ Case Else
+ Goto Trace_Error
+ End Select
+ End With
+
+ AppendChunk = _ParentRecordset._AppendChunk(_Name, pvValue, iChunkType)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error_Update:
+ TraceError(TRACEFATAL, ERRUPDATESEQUENCE, Utils._CalledSub(), 0, 1)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Updatable:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0, 1)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, , cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; AppendChunk V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function GetChunk(ByVal Optional pvOffset As Variant, ByVal Optional pvBytes As Variant) As Variant
+&apos; Get a chunk of string or binary characters from the current field, presumably a large object (CLOB or BLOB)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Field.GetChunk&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim oValue As Object, bNullable As Boolean, bNull As Boolean, vValue() As Variant
+Dim lLength As Long, lOffset As Long, lValue As Long
+
+ If IsMissing(pvOffset) Or IsMissing(pvBytes) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvOffset, 1, _AddNumeric()) Then Goto Exit_Function
+ If pvOffset &lt; 0 Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(1, pvOffset))
+ Goto Exit_Function
+ End If
+ If Not Utils._CheckArgument(pvBytes, 2, _AddNumeric()) Then Goto Exit_Function
+ If pvBytes &lt; 0 Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(2, pvBytes))
+ Goto Exit_Function
+ End If
+
+ bNullable = ( Column.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE )
+ bNull = False
+ GetChunk = Null
+ vValue = Array()
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type &apos; DOES NOT WORK FOR CHARACTER TYPES
+&apos; Case .CHAR, .VARCHAR, .LONGVARCHAR
+&apos; Set oValue = Column.getCharacterStream()
+&apos; Case .CLOB
+&apos; Set oValue = Column.getClob.getCharacterStream()
+ Case .BINARY, .VARBINARY, .LONGVARBINARY
+ Set oValue = Column.getBinaryStream()
+ Case .BLOB
+ Set oValue = Column.getBlob.getBinaryStream()
+ Case Else
+ Goto Trace_Error
+ End Select
+ If bNullable Then bNull = Column.wasNull()
+ If Not bNull Then
+ lOffset = CLng(pvOffset)
+ If lOffset &gt; 0 Then oValue.skipBytes(lOffset)
+ lValue = oValue.readBytes(vValue, pvBytes)
+ End If
+ oValue.closeInput()
+ End With
+ GetChunk = vValue
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, , cstThisSub)
+ Goto Exit_Function
+Trace_Argument:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(iArg, pvIndex))
+ Set vForms = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; GetChunk V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+Const cstThisSub = &quot;Field.getProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+Const cstThisSub = &quot;Field.hasProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String, sName As String
+Const cstThisSub = &quot;Field.Properties&quot;
+ Utils._SetCalledSub(cstThisSub)
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ sName = _ParentType &amp; &quot;/&quot; &amp; _ParentName &amp; &quot;/&quot; &amp; _Name
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ Set vProperty._ParentDatabase = _ParentDatabase
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ReadAllBytes(ByVal Optional pvFile As Variant) As Boolean
+&apos; Read the whole content of a file into Long Binary Field object
+
+Const cstThisSub = &quot;Field.ReadAllBytes&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If Not Utils._CheckArgument(pvFile, 1, vbString) Then Goto Exit_Function
+ ReadAllBytes = _ReadAll(pvFile, &quot;ReadAllBytes&quot;)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; ReadAllBytes
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ReadAllText(ByVal Optional pvFile As Variant) As Boolean
+&apos; Read the whole content of a file into a Long Char Field object
+
+Const cstThisSub = &quot;Field.ReadAllText&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If Not Utils._CheckArgument(pvFile, 1, vbString) Then Goto Exit_Function
+ ReadAllText = _ReadAll(pvFile, &quot;ReadAllText&quot;)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; ReadAllText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+Const cstThisSub = &quot;Field.setProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(cstThisSub)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function WriteAllBytes(ByVal Optional pvFile As Variant) As Boolean
+&apos; Write the whole content of a Long Binary Field object to a file
+
+Const cstThisSub = &quot;Field.WriteAllBytes&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If Not Utils._CheckArgument(pvFile, 1, vbString) Then Goto Exit_Function
+ WriteAllBytes = _WriteAll(pvFile, &quot;WriteAllBytes&quot;)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; WriteAllBytes
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function WriteAllText(ByVal Optional pvFile As Variant) As Boolean
+&apos; Write the whole content of a Long Char Field object to a file
+
+Const cstThisSub = &quot;Field.WriteAllText&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If Not Utils._CheckArgument(pvFile, 1, vbString) Then Goto Exit_Function
+ WriteAllText = _WriteAll(pvFile, &quot;WriteAllText&quot;)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; WriteAllText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ Select Case _ParentType
+ Case OBJTABLEDEF
+ _PropertiesList =Array(&quot;DataType&quot;, &quot;dbType&quot;, &quot;DefaultValue&quot; _
+ , &quot;Description&quot;, &quot;Name&quot;, &quot;ObjectType&quot;, &quot;Size&quot;, &quot;SourceField&quot;, &quot;SourceTable&quot; _
+ , &quot;TypeName&quot; _
+ )
+ Case OBJQUERYDEF
+ _PropertiesList = Array(&quot;DataType&quot;, &quot;dbType&quot;, &quot;DefaultValue&quot; _
+ , &quot;Description&quot;, &quot;Name&quot;, &quot;ObjectType&quot;, &quot;Size&quot;, &quot;SourceField&quot;, &quot;SourceTable&quot; _
+ , &quot;TypeName&quot; _
+ )
+ Case OBJRECORDSET
+ _PropertiesList = Array(&quot;DataType&quot;, &quot;DataUpdatable&quot;, &quot;dbType&quot;, &quot;DefaultValue&quot; _
+ , &quot;Description&quot; , &quot;FieldSize&quot;, &quot;Name&quot;, &quot;ObjectType&quot; _
+ , &quot;Size&quot;, &quot;SourceTable&quot;, &quot;TypeName&quot;, &quot;Value&quot; _
+ )
+ End Select
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;Field.get&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+Dim bCond1 As Boolean, bCond2 As Boolean, vValue As Variant, oValue As Object, sValue As String
+Dim oSize As Object, lSize As Long, bNullable As Boolean, bNull As Boolean
+Const cstMaxBinlength = 2 * 65535
+
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;DataType&quot;)
+ _PropertyGet = Column.Type
+ Case UCase(&quot;DbType&quot;)
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type
+ Case .BIT : _PropertyGet = dbBoolean
+ Case .TINYINT : _PropertyGet = dbInteger
+ Case .SMALLINT : _PropertyGet = dbLong
+ Case .INTEGER : _PropertyGet = dbLong
+ Case .BIGINT : _PropertyGet = dbBigInt
+ Case .FLOAT : _PropertyGet = dbFloat
+ Case .REAL : _PropertyGet = dbSingle
+ Case .DOUBLE : _PropertyGet = dbDouble
+ Case .NUMERIC : _PropertyGet = dbNumeric
+ Case .DECIMAL : _PropertyGet = dbDecimal
+ Case .CHAR : _PropertyGet = dbChar
+ Case .VARCHAR : _PropertyGet = dbText
+ Case .LONGVARCHAR : _PropertyGet = dbMemo
+ Case .CLOB : _PropertyGet = dbMemo
+ Case .DATE : _PropertyGet = dbDate
+ Case .TIME : _PropertyGet = dbTime
+ Case .TIMESTAMP : _PropertyGet = dbTimeStamp
+ Case .BINARY : _PropertyGet = dbBinary
+ Case .VARBINARY : _PropertyGet = dbVarBinary
+ Case .LONGVARBINARY : _PropertyGet = dbLongBinary
+ Case .BLOB : _PropertyGet = dbLongBinary
+ Case .BOOLEAN : _PropertyGet = dbBoolean
+ Case Else : _PropertyGet = dbUndefined
+ End Select
+ End With
+ Case UCase(&quot;DataUpdatable&quot;)
+ If Utils._hasUNOProperty(Column, &quot;IsWritable&quot;) Then
+ _PropertyGet = Column.IsWritable
+ ElseIf Utils._hasUNOProperty(Column, &quot;IsReadOnly&quot;) Then
+ _PropertyGet = Not Column.IsReadOnly
+ ElseIf Utils._hasUNOProperty(Column, &quot;IsDefinitelyWritable&quot;) Then
+ _PropertyGet = Column.IsDefinitelyWritable
+ Else
+ _PropertyGet = False
+ End If
+ If Utils._hasUNOProperty(Column, &quot;IsAutoIncrement&quot;) Then
+ If Column.IsAutoIncrement Then _PropertyGet = False &apos; Forces False if auto-increment (MSAccess)
+ End If
+ Case UCase(&quot;DefaultValue&quot;)
+ &apos; default value buffered to avoid multiple calls
+ If Not _DefaultValueSet Then
+ If Utils._hasUNOProperty(Column, &quot;DefaultValue&quot;) Then &apos; Default value in database set via SQL statement
+ _DefaultValue = Column.DefaultValue
+ ElseIf Utils._hasUNOProperty(Column, &quot;ControlDefault&quot;) Then &apos; Default value set in Base via table edition
+ If IsEmpty(Column.ControlDefault) Then _DefaultValue = &quot;&quot; Else _DefaultValue = Column.ControlDefault
+ Else
+ _DefaultValue = &quot;&quot;
+ End If
+ _DefaultValueSet = True
+ End If
+ _PropertyGet = _DefaultValue
+ Case UCase(&quot;Description&quot;)
+ bCond1 = Utils._hasUNOProperty(Column, &quot;Description&quot;)
+ bCond2 = Utils._hasUNOProperty(Column, &quot;HelpText&quot;)
+ Select Case True
+ Case ( bCond1 And bCond2 )
+ If IsEmpty(Column.HelpText) Then _PropertyGet = Column.Description Else _PropertyGet = Column.HelpText
+ Case ( bCond1 And ( Not bCond2 ) )
+ _PropertyGet = Column.Description
+ Case ( ( Not bCond1 ) And bCond2 )
+ _PropertyGet = Column.HelpText
+ Case Else
+ _PropertyGet = &quot;&quot;
+ End Select
+ Case UCase(&quot;FieldSize&quot;)
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type
+ Case .VARCHAR, .LONGVARCHAR, .CLOB
+ Set oSize = Column.getCharacterStream
+ Case .LONGVARBINARY, .VARBINARY, .BINARY, .BLOB
+ Set oSize = Column.getBinaryStream
+ Case Else
+ Set oSize = Nothing
+ End Select
+ End With
+ If Not IsNull(oSize) Then
+ bNullable = ( Column.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE )
+ If bNullable Then
+ If Column.wasNull() Then _PropertyGet = 0 Else _PropertyGet = CLng(oSize.getLength())
+ Else
+ _PropertyGet = CLng(oSize.getLength())
+ End If
+ oSize.closeInput()
+ Else
+ _PropertyGet = EMPTY
+ End If
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Size&quot;)
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type
+ Case .LONGVARCHAR, .LONGVARBINARY, .VARBINARY, .BINARY, .BLOB, .CLOB
+ _PropertyGet = 0 &apos; Always 0 (MSAccess)
+ Case Else
+ If Utils._hasUNOProperty(Column, &quot;Precision&quot;) Then _PropertyGet = Column.Precision Else _PropertyGet = 0
+ End Select
+ End With
+ Case UCase(&quot;SourceField&quot;)
+ Select Case _ParentType
+ Case OBJTABLEDEF
+ _PropertyGet = _Name
+ Case OBJQUERYDEF &apos; RealName = not documented ?!?
+ If Utils._hasUNOProperty(Column, &quot;RealName&quot;) Then _PropertyGet = Column.RealName Else _PropertyGet = _Name
+ End Select
+ Case UCase(&quot;SourceTable&quot;)
+ Select Case _ParentType
+ Case OBJTABLEDEF
+ _PropertyGet = _ParentName
+ Case OBJQUERYDEF, OBJRECORDSET
+ _PropertyGet = Column.TableName
+ End Select
+ Case UCase(&quot;TypeName&quot;)
+ _PropertyGet = Column.TypeName
+ Case UCase(&quot;Value&quot;)
+ bNullable = ( Column.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE )
+ bNull = False
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type
+ Case .BIT, .BOOLEAN : vValue = Column.getBoolean() &apos; vbBoolean
+ Case .TINYINT : vValue = Column.getShort() &apos; vbInteger
+ Case .SMALLINT, .INTEGER: vValue = Column.getInt() &apos; vbLong
+ Case .BIGINT : vValue = Column.getLong() &apos; vbBigint
+ Case .FLOAT : vValue = Column.getFloat() &apos; vbSingle
+ Case .REAL, .DOUBLE : vValue = Column.getDouble() &apos; vbDouble
+ Case .NUMERIC, .DECIMAL
+ If Utils._hasUNOProperty(Column, &quot;Scale&quot;) Then
+ If Column.Scale &gt; 0 Then
+ vValue = Column.getDouble()
+ Else &apos; Try Long otherwise Double (CDec not implemented anymore in LO ?!?)
+ On Local Error Resume Next &apos; Avoid overflow error
+ &apos; CLng checks local decimal point, getString does not !
+ sValue = Join(Split(Column.getString(), &quot;.&quot;), Utils._DecimalPoint())
+ vValue = CLng(sValue)
+ If Err &lt;&gt; 0 Then
+ vValue = CDbl(sValue)
+ Err.Clear
+ On Local Error Goto Error_Function
+ End If
+ End If
+ Else
+ vValue = CDbl(Column.getString())
+ End If
+ Case .CHAR : vValue = Column.getString()
+ Case .VARCHAR : vValue = Column.getString() &apos; vbString
+ Case .LONGVARCHAR, .CLOB
+ Set oValue = Column.getCharacterStream()
+ If bNullable Then bNull = Column.wasNull()
+ If Not bNull Then
+ lSize = CLng(oValue.getLength())
+ oValue.closeInput()
+ vValue = Column.getString() &apos; vbString
+ Else
+ oValue.closeInput()
+ End If
+ Case .DATE : Set oValue = Column.getDate() &apos; vbObject with members VarType Unsigned Short = 18
+ If bNullable Then bNull = Column.wasNull()
+ If Not bNull Then vValue = DateSerial(CInt(oValue.Year), CInt(oValue.Month), CInt(oValue.Day))
+ Case .TIME : Set oValue = Column.getTime() &apos; vbObject with members VarType Unsigned Short = 18
+ If bNullable Then bNull = Column.wasNull()
+ If Not bNull Then vValue = TimeSerial(oValue.Hours, oValue.Minutes, oValue.Seconds)&apos;, oValue.HundredthSeconds)
+ Case .TIMESTAMP : Set oValue = Column.getTimeStamp()
+ If bNullable Then bNull = Column.wasNull()
+ If Not bNull Then vValue = DateSerial(CInt(oValue.Year), CInt(oValue.Month), CInt(oValue.Day)) _
+ + TimeSerial(oValue.Hours, oValue.Minutes, oValue.Seconds)&apos;, oValue.HundredthSeconds)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ Set oValue = Column.getBinaryStream()
+ If bNullable Then bNull = Column.wasNull()
+ If Not bNull Then
+ lSize = CLng(oValue.getLength()) &apos; vbLong =&gt; equivalent to FieldSize
+ If lSize &gt; cstMaxBinlength Then Goto Trace_Length
+ vValue = Array()
+ oValue.readBytes(vValue, lSize)
+ End If
+ oValue.closeInput()
+ Case Else
+ vValue = Column.getString() &apos;GIVE STRING A TRY
+ If IsNumeric(vValue) Then vValue = Val(vValue) &apos;Required when type = &quot;&quot;, sometimes numeric fields are returned as strings (query/MSAccess)
+ End Select
+ If bNullable Then
+ If Column.wasNull() Then vValue = Null &apos;getXXX must precede wasNull()
+ End If
+ End With
+ _PropertyGet = vValue
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Length:
+ TraceError(TRACEFATAL, ERROVERFLOW, Utils._CalledSub(), 0, , Array(lSize, &quot;GetChunk&quot;))
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;Field.set&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+ _PropertySet = True
+Dim iArgNr As Integer, vTemp As Variant
+Dim oParent As Object
+
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;setProperty&quot;) : iArgNr = 3
+ Case UCase(&quot;Field.setProperty&quot;) : iArgNr = 2
+ Case UCase(cstThisSub) : iArgNr = 1
+ End Select
+
+ If Not hasProperty(psProperty) Then Goto Trace_Error
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;DefaultValue&quot;)
+ If _ParentType &lt;&gt; OBJTABLEDEF Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(Column, &quot;ControlDefault&quot;) Then &apos; Default value set in Base via table edition
+ Column.ControlDefault = pvValue
+ _DefaultValue = pvValue
+ _DefaultValueSet = True
+ End If
+ Case UCase(&quot;Description&quot;)
+ If _ParentType &lt;&gt; OBJTABLEDEF Then Goto Trace_Error
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ Column.HelpText = pvValue
+ Case UCase(&quot;Value&quot;)
+ If _ParentType &lt;&gt; OBJRECORDSET Then Goto Trace_Error &apos; Not on table- or querydefs ... !
+ If Not Column.IsWritable Then Goto Trace_Error_Updatable
+ If Column.IsReadOnly Then Goto Trace_Error_Updatable
+ If _ParentDatabase.Recordsets(_ParentName)._EditMode = dbEditNone Then Goto Trace_Error_Update
+ With com.sun.star.sdbc.DataType
+ If IsNull(pvValue) Then
+ If Column.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE Then Column.updateNull() Else Goto Trace_Null
+ Else
+ Select Case Column.Type
+ Case .BIT, .BOOLEAN
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ Column.updateBoolean(pvValue)
+ Case .TINYINT
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; -128 Or pvValue &gt; +127 Then Goto Trace_Error_Value
+ Column.updateShort(CInt(pvValue))
+ Case .SMALLINT
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; -32768 Or pvValue &gt; 32767 Then Goto trace_Error_Value
+ Column.updateInt(CLng(pvValue))
+ Case .INTEGER
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; -2147483648 Or pvValue &gt; 2147483647 Then Goto trace_Error_Value
+ Column.updateInt(CLng(pvValue))
+ Case .BIGINT
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ Column.updateLong(pvValue) &apos; No proper type conversion for HYPER data type
+ Case .FLOAT
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Abs(pvValue) &lt; 3.402823E38 And Abs(pvValue) &gt; 1.401298E-45 Then Column.updateFloat(CSng(pvValue)) Else Goto trace_Error_Value
+ Case .REAL, .DOUBLE
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ &apos;If Abs(pvValue) &lt; 1.79769313486232E308 And Abs(pvValue) &gt; 4.94065645841247E-307 Then Column.updateDouble(CDbl(pvValue)) Else Goto trace_Error_Value
+ Column.updateDouble(CDbl(pvValue))
+ Case .NUMERIC, .DECIMAL
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(Column, &quot;Scale&quot;) Then
+ If Column.Scale &gt; 0 Then
+ &apos;If Abs(pvValue) &lt; 1.79769313486232E308 And Abs(pvValue) &gt; 4.94065645841247E-307 Then Column.updateDouble(CDbl(pvValue)) Else Goto trace_Error_Value
+ Column.updateDouble(CDbl(pvValue))
+ Else
+ Column.updateString(CStr(pvValue))
+ End If
+ Else
+ Column.updateString(CStr(pvValue))
+ End If
+ Case .CHAR, .VARCHAR, .LONGVARCHAR, .CLOB
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If _Precision &gt; 0 And Len(pvValue) &gt; _Precision Then Goto Trace_Error_Length
+ Column.updateString(pvValue) &apos; vbString
+ Case .DATE
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbDate, , False) Then Goto Trace_Error_Value
+ vTemp = New com.sun.star.util.Date
+ With vTemp
+ .Day = Day(pvValue)
+ .Month = Month(pvValue)
+ .Year = Year(pvValue)
+ End With
+ Column.updateDate(vTemp)
+ Case .TIME
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbDate, , False) Then Goto Trace_Error_Value
+ vTemp = New com.sun.star.util.Time
+ With vTemp
+ .Hours = Hour(pvValue)
+ .Minutes = Minute(pvValue)
+ .Seconds = Second(pvValue)
+ &apos;.HundredthSeconds = 0 &apos; replaced with Long nanoSeconds in LO 4.1 ??
+ End With
+ Column.updateTime(vTemp)
+ Case .TIMESTAMP
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbDate, , False) Then Goto Trace_Error_Value
+ vTemp = New com.sun.star.util.DateTime
+ With vTemp
+ .Day = Day(pvValue)
+ .Month = Month(pvValue)
+ .Year = Year(pvValue)
+ .Hours = Hour(pvValue)
+ .Minutes = Minute(pvValue)
+ .Seconds = Second(pvValue)
+ &apos;.HundredthSeconds = 0
+ End With
+ Column.updateTimestamp(vTemp)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ If Not IsArray(pvValue) Then Goto Trace_Error_Value
+ If UBound(pvValue) &lt; LBound(pvValue) Then Goto Trace_Error_Value
+ If Not Utils._CheckArgument(pvValue(LBound(pvValue)), iArgNr, vbInteger, , False) Then Goto Trace_Error_Value
+ Column.updateBytes(pvValue)
+ Case Else
+ Goto trace_Error
+ End Select
+ End If
+ End With
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Null:
+ TraceError(TRACEFATAL, ERRNOTNULLABLE, Utils._CalledSub(), 0, 1, _Name)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Update:
+ TraceError(TRACEFATAL, ERRUPDATESEQUENCE, Utils._CalledSub(), 0, 1)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Updatable:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0, 1)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Length:
+ TraceError(TRACEFATAL, ERROVERFLOW, Utils._CalledSub(), 0, , Array(Len(pvValue), &quot;AppendChunk&quot;))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _ReadAll(ByVal psFile As String, ByVal psMethod As String) As Boolean
+&apos; Write the whole content of a file into a stream object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _ReadAll = False
+
+ If _ParentType &lt;&gt; OBJRECORDSET Then Goto Trace_Error &apos; Not on table- or querydefs ... !
+ If Not Column.IsWritable Then Goto Trace_Error_Updatable
+ If Column.IsReadOnly Then Goto Trace_Error_Updatable
+ If _ParentDatabase.Recordsets(_ParentName)._EditMode = dbEditNone Then Goto Trace_Error_Update
+
+Dim sFile As String, oSimpleFileAccess As Object, sMethod As String, oStream As Object
+Dim lFileLength As Long, sBuffer As String, sMemo As String, iFile As Integer
+Const cstMaxLength = 64000
+ sFile = ConvertToURL(psFile)
+
+ oSimpleFileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ If Not oSimpleFileAccess.exists(sFile) Then Goto Trace_File
+
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ If psMethod &lt;&gt; &quot;ReadAllBytes&quot; Then Goto Trace_Error
+ Set oStream = oSimpleFileAccess.openFileRead(sFile)
+ lFileLength = oStream.getLength()
+ If lFileLength = 0 Then Goto Trace_File
+ Column.updateBinaryStream(oStream, lFileLength)
+ oStream.closeInput()
+ Case .VARCHAR, .LONGVARCHAR, .CLOB
+ If psMethod &lt;&gt; &quot;ReadAllText&quot; Then Goto Trace_Error
+ sMemo = &quot;&quot;
+ lFileLength = 0
+ iFile = FreeFile()
+ Open sFile For Input Access Read Shared As iFile
+ Do While Not Eof(iFile)
+ Line Input #iFile, sBuffer
+ lFileLength = lFileLength + Len(sBuffer) + 1
+ If lFileLength &gt; cstMaxLength Then Exit Do
+ sMemo = sMemo &amp; sBuffer &amp; vbNewLine
+ Loop
+ If lFileLength = 0 Or lFileLength &gt; cstMaxLength Then
+ Close #iFile
+ Goto Trace_File
+ End If
+ sMemo = Left(sMemo, lFileLength - 1)
+ Column.updateString(sMemo)
+ &apos;Column.updateCharacterStream(oStream, lFileLength) &apos; DOES NOT WORK ?!?
+ Case Else
+ Goto Trace_Error
+ End Select
+ End With
+
+ _ReadAll = True
+
+Exit_Function:
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, , psMethod)
+ Goto Exit_Function
+Trace_File:
+ TraceError(TRACEFATAL, ERRFILEACCESS, Utils._CalledSub(), 0, , sFile)
+ If Not IsNull(oStream) Then oStream.closeInput()
+ Goto Exit_Function
+Trace_Error_Update:
+ TraceError(TRACEFATAL, ERRUPDATESEQUENCE, Utils._CalledSub(), 0, 1)
+ If Not IsNull(oStream) Then oStream.closeInput()
+ Goto Exit_Function
+Trace_Error_Updatable:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0, 1)
+ If Not IsNull(oStream) Then oStream.closeInput()
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, _CalledSub, Erl)
+ GoTo Exit_Function
+End Function &apos; ReadAll
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _WriteAll(ByVal psFile As String, ByVal psMethod As String) As Boolean
+&apos; Write the whole content of a stream object to a file
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _WriteAll = False
+
+Dim sFile As String, oSimpleFileAccess As Object, sMethod As String, oStream As Object
+ sFile = ConvertToURL(psFile)
+
+ oSimpleFileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ With com.sun.star.sdbc.DataType
+ Select Case Column.Type
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ If psMethod &lt;&gt; &quot;WriteAllBytes&quot; Then Goto Trace_Error
+ Set oStream = Column.getBinaryStream()
+ Case .VARCHAR, .LONGVARCHAR, .CLOB
+ If psMethod &lt;&gt; &quot;WriteAllText&quot; Then Goto Trace_Error
+ Set oStream = Column.getCharacterStream()
+ Case Else
+ Goto Trace_Error
+ End Select
+ End With
+
+ If Column.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE Then
+ If Column.wasNull() Then Goto Trace_Null
+ End If
+ If oStream.getLength() = 0 Then Goto Trace_Null
+ On Local Error Goto Trace_File
+ If oSimpleFileAccess.exists(sFile) Then oSimpleFileAccess.kill(sFile)
+ oSimpleFileAccess.writeFile(sFile, oStream)
+ On Local Error Goto Error_Function
+ oStream.closeInput()
+
+ _WriteAll = True
+
+Exit_Function:
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, , psMethod)
+ Goto Exit_Function
+Trace_File:
+ TraceError(TRACEFATAL, ERRFILEACCESS, Utils._CalledSub(), 0, , sFile)
+ If Not IsNull(oStream) Then oStream.closeInput()
+ Goto Exit_Function
+Trace_Null:
+ TraceError(TRACEFATAL, ERRFIELDNULL, _CalledSub, 0)
+ If Not IsNull(oStream) Then oStream.closeInput()
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, _CalledSub, Erl)
+ GoTo Exit_Function
+End Function &apos; WriteAll
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Form.xba b/wizards/source/access2base/Form.xba
new file mode 100644
index 000000000..df18feb34
--- /dev/null
+++ b/wizards/source/access2base/Form.xba
@@ -0,0 +1,1129 @@
+<?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="Form" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be FORM
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Shortcut As String
+Private _Name As String
+Private _DocEntry As Integer &apos; Doc- and DbContainer entries in Root structure
+Private _DbEntry As Integer
+Private _MainForms As Variant
+Private _PersistentName As String
+Private _IsLoaded As Boolean
+Private _OpenArgs As Variant
+Private _OrderBy As String
+Public Component As Object &apos; com.sun.star.text.TextDocument
+Public ContainerWindow As Object &apos; (No name)
+Public FormsCollection As Object &apos; com.sun.star.form.OFormsCollection
+Public DatabaseForm As Object &apos; com.sun.star.form.component.DataForm and com.sun.star.sdb.ResultSet (a.o.)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJFORM
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Shortcut = &quot;&quot;
+ _Name = &quot;&quot;
+ _DocEntry = -1
+ _DbEntry = -1
+ _MainForms = Array()
+ _PersistentName = &quot;&quot;
+ _IsLoaded = False
+ _OpenArgs = &quot;&quot;
+ _OrderBy = &quot;&quot;
+ Set Component = Nothing
+ Set ContainerWindow = Nothing
+ Set FormsCollection = Nothing
+ Set DatabaseForm = Nothing
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+Dim ofForm As Object
+ If Not IsLoaded(True) Then
+ If Not IsNull(DatabaseForm) Then DatabaseForm.Dispose()
+ End If
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AllowAdditions() As Variant
+ AllowAdditions = _PropertyGet(&quot;AllowAdditions&quot;)
+End Property &apos; AllowAdditions (get)
+
+Property Let AllowAdditions(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AllowAdditions&quot;, pvValue)
+End Property &apos; AllowAdditions (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AllowDeletions() As Variant
+ AllowDeletions = _PropertyGet(&quot;AllowDeletions&quot;)
+End Property &apos; AllowDeletions (get)
+
+Property Let AllowDeletions(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AllowDeletions&quot;, pvValue)
+End Property &apos; AllowDeletions (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AllowEdits() As Variant
+ AllowEdits = _PropertyGet(&quot;AllowEdits&quot;)
+End Property &apos; AllowEdits (get)
+
+Property Let AllowEdits(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AllowEdits&quot;, pvValue)
+End Property &apos; AllowEdits (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Bookmark() As Variant
+ Bookmark = _PropertyGet(&quot;Bookmark&quot;)
+End Property &apos; Bookmark (get)
+
+Property Let Bookmark(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Bookmark&quot;, pvValue)
+End Property &apos; Bookmark (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Caption() As Variant
+ Caption = _PropertyGet(&quot;Caption&quot;)
+End Property &apos; Caption (get)
+
+Property Let Caption(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Caption&quot;, pvValue)
+End Property &apos; Caption (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get CurrentRecord() As Variant
+ CurrentRecord = _PropertyGet(&quot;CurrentRecord&quot;)
+End Property &apos; CurrentRecord (get)
+
+Property Let CurrentRecord(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;CurrentRecord&quot;, pvValue)
+End Property &apos; CurrentRecord (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Filter() As Variant
+ Filter = _PropertyGet(&quot;Filter&quot;)
+End Property &apos; Filter (get)
+
+Property Let Filter(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Filter&quot;, pvValue)
+End Property &apos; Filter (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FilterOn() As Variant
+ FilterOn = _PropertyGet(&quot;FilterOn&quot;)
+End Property &apos; FilterOn (get)
+
+Property Let FilterOn(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FilterOn&quot;, pvValue)
+End Property &apos; FilterOn (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Height() As Variant
+ Height = _PropertyGet(&quot;Height&quot;)
+End Property &apos; Height (get)
+
+Property Let Height(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Height&quot;, pvValue)
+End Property &apos; Height (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Function IsLoaded(ByVal Optional pbForce As Boolean) As Boolean
+&apos;Return True if form open
+&apos;pbForce = True forbids bypass on value of _IsLoaded
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Form.getIsLoaded&quot;)
+ If IsMissing(pbForce) Then pbForce = False
+ If ( Not pbForce ) And _IsLoaded Then &apos; For performance reasons, a form object, once detected as loaded, is presumed remaining loaded. Except if pbForce = True
+ IsLoaded = True
+ Goto Exit_Function
+ End If
+ IsLoaded = False
+
+Dim oDoc As Object, oDatabase As Object, oEnum As Object, oDesk As Object, oComp As Object, vPersistent As Variant
+Dim i As Integer
+ Set oDoc = _A2B_.CurrentDocument()
+ Select Case oDoc.DbConnect
+ Case DBCONNECTBASE
+ Set oDesk = CreateUnoService(&quot;com.sun.star.frame.Desktop&quot;)
+ Set oEnum = oDesk.Components().createEnumeration
+ Do While oEnum.hasMoreElements &apos; Search in all open components if one corresponds with current form
+ oComp = oEnum.nextElement
+ If _hasUNOProperty(oComp, &quot;Identifier&quot;) Then
+ If oComp.Identifier = &quot;com.sun.star.sdb.FormDesign&quot; Then
+ vPersistent = Split(oComp.StringValue, &quot;/&quot;)
+ If vPersistent(UBound(vPersistent) - 1) = _PersistentName Then
+ _IsLoaded = True
+ Set Component = oComp
+ Exit Do
+ End If
+ End If
+ End If
+ Loop
+ Case DBCONNECTFORM
+ Set Component = oDoc.Document &apos; Form
+ _IsLoaded = True &apos; Interactive form always loaded by design
+ End Select
+ Set oComp = Nothing
+ IsLoaded = _IsLoaded
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.getIsLoaded&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form.getIsLoaded&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; IsLoaded V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveCursorMove() As Variant
+ OnApproveCursorMove = _PropertyGet(&quot;OnApproveCursorMove&quot;)
+End Property &apos; OnApproveCursorMove (get)
+
+Property Let OnApproveCursorMove(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveCursorMove&quot;, pvValue)
+End Property &apos; OnApproveCursorMove (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveParameter() As Variant
+ OnApproveParameter = _PropertyGet(&quot;OnApproveParameter&quot;)
+End Property &apos; OnApproveParameter (get)
+
+Property Let OnApproveParameter(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveParameter&quot;, pvValue)
+
+End Property &apos; OnApproveParameter (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveReset() As Variant
+ OnApproveReset = _PropertyGet(&quot;OnApproveReset&quot;)
+End Property &apos; OnApproveReset (get)
+
+Property Let OnApproveReset(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveReset&quot;, pvValue)
+End Property &apos; OnApproveReset (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveRowChange() As Variant
+ OnApproveRowChange = _PropertyGet(&quot;OnApproveRowChange&quot;)
+End Property &apos; OnApproveRowChange (get)
+
+Property Let OnApproveRowChange(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveRowChange&quot;, pvValue)
+End Property &apos; OnApproveRowChange (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveSubmit() As Variant
+ OnApproveSubmit = _PropertyGet(&quot;OnApproveSubmit&quot;)
+End Property &apos; OnApproveSubmit (get)
+
+Property Let OnApproveSubmit(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveSubmit&quot;, pvValue)
+End Property &apos; OnApproveSubmit (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnConfirmDelete() As Variant
+ OnConfirmDelete = _PropertyGet(&quot;OnConfirmDelete&quot;)
+End Property &apos; OnConfirmDelete (get)
+
+Property Let OnConfirmDelete(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnConfirmDelete&quot;, pvValue)
+End Property &apos; OnConfirmDelete (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnCursorMoved() As Variant
+ OnCursorMoved = _PropertyGet(&quot;OnCursorMoved&quot;)
+End Property &apos; OnCursorMoved (get)
+
+Property Let OnCursorMoved(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnCursorMoved&quot;, pvValue)
+End Property &apos; OnCursorMoved (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnErrorOccurred() As Variant
+ OnErrorOccurred = _PropertyGet(&quot;OnErrorOccurred&quot;)
+End Property &apos; OnErrorOccurred (get)
+
+Property Let OnErrorOccurred(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnErrorOccurred&quot;, pvValue)
+End Property &apos; OnErrorOccurred (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnLoaded() As Variant
+ OnLoaded = _PropertyGet(&quot;OnLoaded&quot;)
+End Property &apos; OnLoaded (get)
+
+Property Let OnLoaded(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnLoaded&quot;, pvValue)
+End Property &apos; OnLoaded (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnReloaded() As Variant
+ OnReloaded = _PropertyGet(&quot;OnReloaded&quot;)
+End Property &apos; OnReloaded (get)
+
+Property Let OnReloaded(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnReloaded&quot;, pvValue)
+End Property &apos; OnReloaded (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnReloading() As Variant
+ OnReloading = _PropertyGet(&quot;OnReloading&quot;)
+End Property &apos; OnReloading (get)
+
+Property Let OnReloading(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnReloading&quot;, pvValue)
+End Property &apos; OnReloading (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnResetted() As Variant
+ OnResetted = _PropertyGet(&quot;OnResetted&quot;)
+End Property &apos; OnResetted (get)
+
+Property Let OnResetted(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnResetted&quot;, pvValue)
+End Property &apos; OnResetted (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnRowChanged() As Variant
+ OnRowChanged = _PropertyGet(&quot;OnRowChanged&quot;)
+End Property &apos; OnRowChanged (get)
+
+Property Let OnRowChanged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnRowChanged&quot;, pvValue)
+End Property &apos; OnRowChanged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUnloaded() As Variant
+ OnUnloaded = _PropertyGet(&quot;OnUnloaded&quot;)
+End Property &apos; OnUnloaded (get)
+
+Property Let OnUnloaded(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnUnloaded&quot;, pvValue)
+End Property &apos; OnUnloaded (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUnloading() As Variant
+ OnUnloading = _PropertyGet(&quot;OnUnloading&quot;)
+End Property &apos; OnUnloading (get)
+
+Property Let OnUnloading(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnUnloading&quot;, pvValue)
+End Property &apos; OnUnloading (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OpenArgs() As Variant
+ OpenArgs = _PropertyGet(&quot;OpenArgs&quot;)
+End Property &apos; OpenArgs (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OrderBy() As Variant
+ OrderBy = _PropertyGet(&quot;OrderBy&quot;)
+End Property &apos; OrderBy (get) V1.2.0
+
+Property Let OrderBy(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OrderBy&quot;, pvValue)
+End Property &apos; OrderBy (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OrderByOn() As Variant
+ OrderByOn = _PropertyGet(&quot;OrderByOn&quot;)
+End Property &apos; OrderByOn (get) V1.2.0
+
+Property Let OrderByOn(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OrderByOn&quot;, pvValue)
+End Property &apos; OrderByOn (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OptionGroup(ByVal Optional pvGroupName As Variant) As Variant
+&apos; Return either an error or an object of type OPTIONGROUP based on its name
+
+Const cstThisSub = &quot;Form.OptionGroup&quot;
+Dim ogGroup As Object
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvGroupName) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Set ogGroup = _OptionGroup(pvGroupName, CTLPARENTISFORM, Component, FormsCollection)
+ If Not IsNull(ogGroup) Then
+ ogGroup._DocEntry = _DocEntry
+ ogGroup._DbEntry = _DbEntry
+ End If
+ Set OptionGroup = ogGroup
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Form.OptionGroup, Erl)
+ GoTo Exit_Function
+End Function &apos; OptionGroup V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Parent() As Object
+ Parent = _Parent
+End Function &apos; Parent (get) V6.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Recordset() As Object
+ Recordset = _PropertyGet(&quot;Recordset&quot;)
+End Property &apos; Recordset (get) V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get RecordSource() As Variant
+ RecordSource = _PropertyGet(&quot;RecordSource&quot;)
+End Property &apos; RecordSource (get)
+
+Property Let RecordSource(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;RecordSource&quot;, pvValue)
+End Property &apos; RecordSource (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Visible() As Variant
+ Visible = _PropertyGet(&quot;Visible&quot;)
+End Property &apos; Visible (get)
+
+Property Let Visible(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Visible&quot;, pvValue)
+End Property &apos; Visible (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Width() As Variant
+ Width = _PropertyGet(&quot;Width&quot;)
+End Property &apos; Width (get)
+
+Property Let Width(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Width&quot;, pvValue)
+End Property &apos; Width (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function mClose() As Variant
+&apos; Close the form
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Form.Close&quot;)
+ mClose = False
+Dim oDatabase As Object, oController As Object
+ Set oDatabase = Application._CurrentDb()
+ If oDatabase._DbConnect &lt;&gt; DBCONNECTBASE Then Goto Error_NotApplicable
+
+ Set oController = oDatabase.Document.getFormDocuments.getByHierarchicalName(_Name)
+ oController.close()
+ Dispose()
+ mClose = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.Close&quot;)
+ Exit Function
+Error_NotApplicable:
+ TraceError(TRACEFATAL, ERRMETHOD, Utils._CalledSub(), 0, 1, cstThisSub)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form.Close&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Close
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Controls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Return a Control object with name or index = pvIndex
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Form.Controls&quot;)
+
+Dim ocControl As Variant, iControlCount As Integer
+Dim oCounter As Variant, sControls() As Variant, i As Integer, bFound As Boolean, sIndex As String
+Dim j As Integer, iCount As Integer, sName As String, iAddCount As Integer
+Dim oDatabaseForm As Object, iCtlCount As Integer
+
+ Set ocControl = Nothing
+ If Not IsLoaded Then Goto Trace_Error_NotOpen
+ &apos;Count number of controls thru the forms collection
+ iControlCount = 0
+
+ iCount = FormsCollection.Count
+ For i = 0 To iCount - 1
+ If i = 0 Then Set oDatabaseForm = DatabaseForm Else Set oDatabaseForm = FormsCollection.getByIndex(i)
+ If Not IsNull(oDatabaseForm) Then iControlCount = iControlCount + oDatabaseForm.getCount()
+ Next i
+
+ If IsMissing(pvIndex) Then &apos; No argument, return Collection pseudo-object
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLCONTROLS
+ Set oCounter._Parent = _This
+ oCounter._Count = iControlCount
+ Set Controls = oCounter
+ Goto Exit_Function
+ End If
+
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+
+ &apos; Start building the ocControl object
+ &apos; Determine exact name
+
+ sName = &quot;&quot;
+ Select Case VarType(pvIndex)
+ Case vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal
+ If pvIndex &lt; 0 Or pvIndex &gt; iControlCount - 1 Then Goto Trace_Error_Index
+ iAddCount = 0
+ For i = 0 To iCount - 1
+ If i = 0 Then Set oDatabaseForm = DatabaseForm Else Set oDatabaseForm = FormsCollection.getByIndex(i)
+ If Not IsNull(oDatabaseForm) Then
+ iCtlCount = oDatabaseForm.getCount()
+ If pvIndex &gt;= iAddCount And pvIndex &lt;= iAddcount + iCtlCount - 1 Then
+ sName = oDatabaseForm.ElementNames(pvIndex - iAddCount)
+ Exit For
+ End If
+ iAddCount = iAddcount +iCtlCount
+ End If
+ Next i
+ Case vbString &apos; Check control name validity (non case sensitive)
+ sIndex = UCase(Utils._Trim(pvIndex))
+ bFound = False
+ For i = 0 To iCount - 1
+ If i = 0 Then Set oDatabaseForm = DatabaseForm Else Set oDatabaseForm = FormsCollection.getByIndex(i)
+ If Not IsNull(oDatabaseForm) Then
+ sControls() = oDatabaseForm.getElementNames()
+ For j = 0 To UBound(sControls)
+ If UCase(sControls(j)) = sIndex Then
+ sName = sControls(j)
+ bFound = True
+ Exit For
+ End If
+ Next j
+ If bFound Then Exit For
+ End If
+ Next i
+ If Not bFound Then Goto Trace_NotFound
+ End Select
+
+ &apos;Initialize a new Control object
+ Set ocControl = New Control
+ With ocControl
+ Set ._This = ocControl
+ Set ._Parent = _This
+ ._ParentType = CTLPARENTISFORM
+ ._Name = sName
+ ._Shortcut = _Shortcut &amp; &quot;!&quot; &amp; Utils._Surround(sName)
+ If IsNull(oDatabaseForm) Then ._MainForm = &quot;&quot; Else ._MainForm = oDatabaseForm.Name
+ Set .ControlModel = oDatabaseForm.getByName(sName)
+ ._ImplementationName = .ControlModel.getImplementationName()
+ ._FormComponent = Component
+ If Utils._hasUNOProperty(.ControlModel, &quot;ClassId&quot;) Then ._ClassId = .ControlModel.ClassId
+ If ._ClassId &gt; 0 And ._ClassId &lt;&gt; acHiddenControl Then
+ Set .ControlView = Component.CurrentController.getControl(.ControlModel)
+ End If
+
+ ._Initialize()
+ ._DocEntry = _DocEntry
+ ._DbEntry = _DbEntry
+ End With
+ Set Controls = ocControl
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.Controls&quot;)
+ Exit Function
+Trace_Error_NotOpen:
+ TraceError(TRACEFATAL, ERRFORMNOTOPEN, Utils._CalledSub(), 0, , _Name)
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERRCONTROLNOTFOUND, Utils._CalledSub(), 0, , Array(pvIndex, pvIndex))
+ Set Controls = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form.Controls&quot;, Erl)
+ Set Controls = Nothing
+ GoTo Exit_Function
+End Function &apos; Controls
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CurrentDb() As Object
+&apos; Returns Database object related to current form
+
+Const cstThisSub = &quot;Form.CurrentDb&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ Set CurrentDb = Application._CurrentDb(_DocEntry, _DbEntry)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; CurrentDb V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Form.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;Form.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Move( ByVal Optional pvLeft As Variant _
+ , ByVal Optional pvTop As Variant _
+ , ByVal Optional pvWidth As Variant _
+ , ByVal Optional pvHeight As Variant _
+ ) As Variant
+&apos; Execute Move method
+ Utils._SetCalledSub(&quot;Form.Move&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Move = False
+Dim iArgNr As Integer
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;Move&quot;) : iArgNr = 1
+ Case UCase(&quot;Form.Move&quot;) : iArgNr = 0
+ End Select
+ If IsMissing(pvLeft) Then pvLeft = -1
+ If IsMissing(pvTop) Then pvTop = -1
+ If IsMissing(pvWidth) Then pvWidth = -1
+ If IsMissing(pvHeight) Then pvHeight = -1
+ If Not Utils._CheckArgument(pvLeft, iArgNr + 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvTop, iArgNr + 2, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWidth, iArgNr + 3, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvHeight, iArgNr + 4, Utils._AddNumeric()) Then Goto Exit_Function
+
+Dim iArg As Integer, iWrong As Integer &apos; Check arguments values
+ iArg = 0
+ If pvHeight &lt; -1 Then
+ iArg = 4 : iWrong = pvHeight
+ ElseIf pvWidth &lt; -1 Then
+ iArg = 3 : iWrong = pvWidth
+ ElseIf pvTop &lt; -1 Then
+ iArg = 2 : iWrong = pvTop
+ ElseIf pvLeft &lt; -1 Then
+ iArg = 1 : iWrong = pvLeft
+ End If
+ If iArg &gt; 0 Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(iArgNr + iArg, iWrong))
+ Goto Exit_Function
+ End If
+
+Dim iPosSize As Integer
+ iPosSize = 0
+ If pvLeft &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.X
+ If pvTop &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.Y
+ If pvWidth &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.WIDTH
+ If pvHeight &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.HEIGHT
+ If iPosSize &gt; 0 Then
+ If Utils._hasUNOProperty(ContainerWindow, &quot;IsMaximized&quot;) Then &apos; Ignored when &lt;= OO3.2
+ ContainerWindow.IsMaximized = False
+ ContainerWindow.IsMinimized = False
+ End If
+ ContainerWindow.setPosSize(pvLeft, pvTop, pvWidth, pvHeight, iPosSize)
+ End If
+ Move = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.Move&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form.Move&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Move
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Refresh() As Boolean
+&apos; Refresh data with its most recent value in the database in a form or subform
+ Utils._SetCalledSub(&quot;Form.Refresh&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Refresh = False
+
+Dim oSet As Object
+ Set oSet = DatabaseForm.createResultSet()
+ If Not IsNull(oSet) Then
+ oSet.refreshRow()
+ Refresh = True
+ End If
+
+Exit_Function:
+ Set oSet = Nothing
+ Utils._ResetCalledSub(&quot;Form.Refresh&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm.Refresh&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Refresh
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Requery() As Boolean
+&apos; Refresh data displayed in a form, subform, combobox or listbox
+ Utils._SetCalledSub(&quot;Form.Requery&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Requery = False
+
+ DatabaseForm.reload()
+ Requery = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.Requery&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form.Requery&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Requery
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFocus() As Boolean
+&apos; Execute setFocus method
+Const cstThisSub = &quot;Form.setFocus&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ setFocus = False
+
+ With ContainerWindow
+ If .isVisible() = False Then .setVisible(True)
+ .IsMinimized = False
+ .setFocus()
+ .setEnable(True) &apos; Added to try to bypass desynchro issue in Linux
+ .toFront() &apos; Added to force window change in Linux
+ End With
+ setFocus = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ Goto Exit_Function
+End Function &apos; setFocus V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;Form.setProperty&quot;)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(&quot;Form.setProperty&quot;)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetListener(ByVal psProperty As String) As String
+&apos; Return the X...Listener corresponding with the property in argument
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;OnApproveCursorMove&quot;)
+ _GetListener = &quot;XRowSetApproveListener&quot;
+ Case UCase(&quot;OnApproveParameter&quot;)
+ _GetListener = &quot;XDatabaseParameterListener&quot;
+ Case UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnResetted&quot;)
+ _GetListener = &quot;XResetListener&quot;
+ Case UCase(&quot;OnApproveRowChange&quot;)
+ _GetListener = &quot;XRowSetApproveListener&quot;
+ Case UCase(&quot;OnApproveSubmit&quot;)
+ _GetListener = &quot;XSubmitListener&quot;
+ Case UCase(&quot;OnConfirmDelete&quot;)
+ _GetListener = &quot;XConfirmDeleteListener&quot;
+ Case UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnRowChanged&quot;)
+ _GetListener = &quot;XRowSetListener&quot;
+ Case UCase(&quot;OnErrorOccurred&quot;)
+ _GetListener = &quot;XSQLErrorListener&quot;
+ Case UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ _GetListener = &quot;XLoadListener&quot;
+ End Select
+
+End Function &apos; _GetListener V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _Initialize(psName As String)
+&apos; Set pointers to UNO objects
+
+Dim oDoc As Object, oDatabase As Object
+ If _ErrorHandler() Then On Local Error Goto Trace_Error
+ _Name = psName
+ _Shortcut = &quot;Forms!&quot; &amp; Utils._Surround(psName)
+ Set oDoc = _A2B_.CurrentDocument()
+ If oDoc.DbConnect = DBCONNECTBASE Then _PersistentName = oDoc.Document.getFormDocuments().getByHierarchicalName(psName).PersistentName
+ If IsLoaded Then
+ Select Case oDoc.DbConnect
+ Case DBCONNECTBASE
+ If Not IsNull(Component.CurrentController) Then &apos; A form opened then closed afterwards keeps a Component attribute
+ Set ContainerWindow = Component.CurrentController.Frame.ContainerWindow
+ Set FormsCollection = Component.getDrawPage.Forms
+ If FormsCollection.Count = 0 Then
+ Set DatabaseForm = Nothing
+ Else
+ &apos;Only first member of the collection can be reached with A2B
+ &apos;Compliant with MSAccess which has 1 datasource by form, while LO might have many
+ _MainForms = FormsCollection.ElementNames()
+ Set DatabaseForm = FormsCollection.getByIndex(0)
+ End If
+ End If
+ Case DBCONNECTFORM
+ Set ContainerWindow = oDoc.Document.CurrentController.Frame.ContainerWindow
+ Set FormsCollection = oDoc.Document.getDrawPage.Forms
+ Set oDatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ With oDatabase
+ Set DatabaseForm = .Form
+ If IsNull(.Connection) Then
+ Set .Connection = DatabaseForm.ActiveConnection
+ If Not IsNull(.Connection) Then
+ Set .MetaData = .Connection.MetaData
+ oDatabase._ReadOnly = .Connection.isReadOnly()
+ End If
+ End If
+ End With
+ End Select
+ If IsNull(DatabaseForm) Then _OrderBy = &quot;&quot; Else _OrderBy = DatabaseForm.Order
+ Else
+ Set Component = Nothing
+ Set ContainerWindow = Nothing
+ Set DatabaseForm = Nothing
+ End If
+
+Exit_Sub:
+ Exit Sub
+Trace_Error:
+ TraceError(TRACEABORT, Err, &quot;Form.Initialize&quot;, Erl)
+ Goto Exit_Sub
+Trace_Internal_Error:
+ TraceError(TRACEABORT, ERRFORMNOTIDENTIFIED, Utils._CalledSub(), 0, , _Name)
+ Goto Exit_Sub
+End Sub &apos; _Initialize V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ If _IsLoaded Then
+ _PropertiesList = Array(&quot;AllowAdditions&quot;, &quot;AllowDeletions&quot;, &quot;AllowEdits&quot;, &quot;Bookmark&quot; _
+ , &quot;Caption&quot;, &quot;CurrentRecord&quot;, &quot;Filter&quot;, &quot;FilterOn&quot;, &quot;Height&quot;, &quot;IsLoaded&quot; _
+ , &quot;Name&quot;, &quot;ObjectType&quot;, &quot;OnApproveCursorMove&quot;, &quot;OnApproveParameter&quot; _
+ , &quot;OnApproveReset&quot;, &quot;OnApproveRowChange&quot;, &quot;OnApproveSubmit&quot;, &quot;OnConfirmDelete&quot; _
+ , &quot;OnCursorMoved&quot;, &quot;OnErrorOccurred&quot;, &quot;OnLoaded&quot;, &quot;OnReloaded&quot;, &quot;OnReloading&quot; _
+ , &quot;OnResetted&quot;, &quot;OnRowChanged&quot;, &quot;OnUnloaded&quot;, &quot;OnUnloading&quot;, &quot;OpenArgs&quot; _
+ , &quot;OrderBy&quot;, &quot;OrderByOn&quot;, &quot;RecordSource&quot;, &quot;Visible&quot;, &quot;Width&quot; _
+ ) &apos; Recordset removed
+ Else
+ _PropertiesList = Array(&quot;IsLoaded&quot;, &quot;Name&quot; _
+ )
+ End If
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Form.get&quot; &amp; psProperty)
+
+&apos;Execute
+Dim oDatabase As Object, vBookmark As Variant
+Dim i As Integer, oObject As Object
+
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Name&quot;), UCase(&quot;IsLoaded&quot;)
+ Case Else : If Not IsLoaded Then Goto Trace_Error_Form
+ End Select
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AllowAdditions&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = False Else _PropertyGet = DatabaseForm.AllowInserts
+ Case UCase(&quot;AllowDeletions&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = False Else _PropertyGet = DatabaseForm.AllowDeletes
+ Case UCase(&quot;AllowEdits&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = False Else _PropertyGet = DatabaseForm.AllowUpdates
+ Case UCase(&quot;Bookmark&quot;)
+ If IsNull(DatabaseForm) Then
+ _PropertyGet = 0
+ Else
+ On Local Error Resume Next &apos; Disable error handler because bookmarking does not always react well in events ...
+ If DatabaseForm.IsBookmarkable Then vBookmark = DatabaseForm.getBookmark() Else vBookmark = Nothing
+ If _ErrorHandler() Then On Local Error Goto Error_Function Else On Local Error Goto 0
+ If IsNull(vBookmark) Then Goto Trace_Error
+ _PropertyGet = vBookmark
+ End If
+ Case UCase(&quot;Caption&quot;)
+ Set odatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ Select Case oDatabase._DbConnect
+ Case DBCONNECTFORM : _PropertyGet = oDatabase.Document.CurrentController.Frame.Title
+ Case DBCONNECTBASE : _PropertyGet = Component.CurrentController.Frame.Title
+ End Select
+ Case UCase(&quot;CurrentRecord&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = 0 Else _PropertyGet = DatabaseForm.Row
+ Case UCase(&quot;Filter&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = &quot;&quot; Else _PropertyGet = DatabaseForm.Filter
+ Case UCase(&quot;FilterOn&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = False Else _PropertyGet = DatabaseForm.ApplyFilter
+ Case UCase(&quot;Height&quot;)
+ _PropertyGet = ContainerWindow.getPosSize().Height
+ Case UCase(&quot;IsLoaded&quot;) &apos; Only for indirect access from property object
+ _PropertyGet = IsLoaded
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;OnApproveCursorMove&quot;), UCase(&quot;OnApproveParameter&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveRowChange&quot;) _
+ , UCase(&quot;OnApproveSubmit&quot;), UCase(&quot;OnConfirmDelete&quot;), UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnErrorOccurred&quot;) _
+ , UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnRowChanged&quot;) _
+ , UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = &quot;&quot; Else _PropertyGet = Utils._GetEventScriptCode(DatabaseForm, psProperty, _Name, True)
+ Case UCase(&quot;OpenArgs&quot;)
+ _PropertyGet = _OpenArgs
+ Case UCase(&quot;OrderBy&quot;)
+ _PropertyGet = _OrderBy
+ Case UCase(&quot;OrderByOn&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = False Else _PropertyGet = ( DatabaseForm.Order &lt;&gt; &quot;&quot; )
+ Case UCase(&quot;Recordset&quot;)
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ If DatabaseForm.Command = &quot;&quot; Then Goto Trace_Error &apos; No underlying data ??
+ Set oObject = New Recordset
+ With DatabaseForm
+ oObject._This = oObject
+ oObject._CommandType = .CommandType
+ oObject._Command = .Command
+ oObject._ParentName = _Name
+ oObject._ParentType = _Type
+ Set oDatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ Set oObject._ParentDatabase = oDatabase
+ Set oObject._ParentDatabase.Connection = .ActiveConnection
+ oObject._ForwardOnly = ( .ResultSetType = com.sun.star.sdbc.ResultSetType.FORWARD_ONLY )
+ oObject._PassThrough = ( .EscapeProcessing = False )
+ oObject._ReadOnly = ( .ResultSetConcurrency = com.sun.star.sdbc.ResultSetConcurrency.READ_ONLY )
+ Call oObject._Initialize()
+ End With
+ With oDatabase
+ .RecordsetMax = .RecordsetMax + 1
+ oObject._Name = Format(.RecordsetMax, &quot;0000000&quot;)
+ .RecordsetsColl.Add(oObject, UCase(oObject._Name))
+ End With
+ If Not ( oObject._BOF And oObject._EOF ) Then oObject.MoveFirst() &apos; Do nothing if resultset empty
+ Set _PropertyGet = oObject
+ Case UCase(&quot;RecordSource&quot;)
+ If IsNull(DatabaseForm) Then _PropertyGet = &quot;&quot; Else _PropertyGet = DatabaseForm.Command
+ Case UCase(&quot;Visible&quot;)
+ _PropertyGet = ContainerWindow.IsVisible()
+ Case UCase(&quot;Width&quot;)
+ _PropertyGet = ContainerWindow.getPosSize().Width
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Error_Form:
+ TraceError(TRACEFATAL, ERRFORMNOTOPEN, Utils._CalledSub(), 0, 1, _Name)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+
+ Utils._SetCalledSub(&quot;Form.set&quot; &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _PropertySet = True
+
+&apos;Execute
+Dim iArgNr As Integer, i As Integer
+Dim oDatabase As Object
+
+ If _Isleft(_A2B_.CalledSub, &quot;Form.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ If Not IsLoaded Then Goto Trace_Error_Form
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AllowAdditions&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.AllowInserts = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;AllowDeletions&quot;)
+ If Not Utils._CheckArgument(pvValue,iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.AllowDeletes = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;AllowEdits&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.AllowUpdates = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;Bookmark&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(vbObject), , False) Then Goto Trace_Error_Value
+ If IsNull(pvValue) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.MoveToBookmark(pvValue)
+ Case UCase(&quot;Caption&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ Set oDatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ Select Case oDatabase._DbConnect
+ Case DBCONNECTFORM : oDatabase.Document.CurrentController.Frame.Title = pvValue
+ Case DBCONNECTBASE : Component.CurrentController.Frame.Title = pvValue
+ End Select
+ Case UCase(&quot;CurrentRecord&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 1 Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.absolute(pvValue)
+ Case UCase(&quot;Filter&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.Filter = Application._CurrentDb(_DocEntry, _DbEntry)._ReplaceSquareBrackets(pvValue)
+ Case UCase(&quot;FilterOn&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.ApplyFilter = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;Height&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(ContainerWindow, &quot;IsMaximized&quot;) Then &apos; Ignored when &lt;= OO3.2
+ ContainerWindow.IsMaximized = False
+ ContainerWindow.IsMinimized = False
+ End If
+ ContainerWindow.setPosSize(0, 0, 0, pvValue, com.sun.star.awt.PosSize.HEIGHT)
+ Case UCase(&quot;OnApproveCursorMove&quot;), UCase(&quot;OnApproveParameter&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveRowChange&quot;) _
+ , UCase(&quot;OnApproveSubmit&quot;), UCase(&quot;OnConfirmDelete&quot;), UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnErrorOccurred&quot;) _
+ , UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnRowChanged&quot;) _
+ , UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ If Not Utils._RegisterEventScript(DatabaseForm _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue, _Name, True _
+ ) Then GoTo Trace_Error
+ Case UCase(&quot;OrderBy&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ _OrderBy = Application._CurrentDb(_DocEntry, _DbEntry)._ReplaceSquareBrackets(pvValue)
+ Case UCase(&quot;OrderByOn&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ If pvValue Then DatabaseForm.Order = _OrderBy Else DatabaseForm.Order = &quot;&quot;
+ DatabaseForm.reload()
+ Case UCase(&quot;RecordSource&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If IsNull(DatabaseForm) Then Goto Trace_Error
+ DatabaseForm.Command = Application._CurrentDb(_DocEntry, _DbEntry)._ReplaceSquareBrackets(pvValue)
+ DatabaseForm.CommandType = com.sun.star.sdb.CommandType.COMMAND
+ DatabaseForm.Filter = &quot;&quot;
+ DatabaseForm.reload()
+ Case UCase(&quot;Visible&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ ContainerWindow.setVisible(pvValue)
+ Case UCase(&quot;Width&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric()) Then Goto Trace_Error_Value
+ If Utils._hasUNOProperty(ContainerWindow, &quot;IsMaximized&quot;) Then &apos; Ignored when &lt;= OO3.2
+ ContainerWindow.IsMaximized = False
+ ContainerWindow.IsMinimized = False
+ End If
+ ContainerWindow.setPosSize(0, 0, pvValue, 0, com.sun.star.awt.PosSize.WIDTH)
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Form.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error_Form:
+ TraceError(TRACEFATAL, ERRFORMNOTOPEN, Utils._CalledSub(), 0, 1, _Name)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Form._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/L10N.xba b/wizards/source/access2base/L10N.xba
new file mode 100644
index 000000000..ef11f6f3e
--- /dev/null
+++ b/wizards/source/access2base/L10N.xba
@@ -0,0 +1,540 @@
+<?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="L10N" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function _GetLabel(ByVal psShortlabel As String, Optional ByVal psLocale As String) As String
+&apos; Return the localized label corresponding with ShortLabel
+
+ If IsMissing(psLocale) Then psLocale = UCase(Left(_A2B_.Locale, 2)) Else psLocale = UCase(psLocale)
+ On Local Error Goto Error_Function
+ If Not Utils._InList(psLocale, Array( _
+ &quot;EN&quot;, &quot;FR&quot;, &quot;ES&quot;, &quot;DE&quot; _
+ )) Then psLocale = &quot;DEFAULT&quot; &apos; If list incomplete a recursive call will be provided anyway
+
+Dim sLocal As String
+ sLocal = psShortLabel
+ Select Case psLocale
+ Case &quot;EN&quot;, &quot;DEFAULT&quot;
+ Select Case UCase(psShortlabel)
+ Case &quot;ERR&quot; &amp; ERRDBNOTCONNECTED : sLocal = &quot;No active connection to a database found&quot;
+ Case &quot;ERR&quot; &amp; ERRMISSINGARGUMENTS : sLocal = &quot;Arguments are missing or are not initialized&quot;
+ Case &quot;ERR&quot; &amp; ERRWRONGARGUMENT : sLocal = &quot;Argument nr. %0 [Value = &apos;%1&apos;] is invalid&quot;
+ Case &quot;ERR&quot; &amp; ERRMAINFORM : sLocal = &quot;Document &apos;%0&apos; does not contain any form&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTIDENTIFIED : sLocal = &quot;Form &apos;%0&apos; not identified in database Forms set&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTFOUND : sLocal = &quot;Form &apos;%0&apos; not found&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTOPEN : sLocal = &quot;Form &apos;%0&apos; is currently not open&quot;
+ Case &quot;ERR&quot; &amp; ERRDFUNCTION : sLocal = &quot;DFunction execution failed, SQL=%0&quot;
+ Case &quot;ERR&quot; &amp; ERROPENFORM : sLocal = &quot;Form &apos;%0&apos; could not be opened&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTY : sLocal = &quot;Property &apos;%0&apos; not applicable in this context&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYVALUE : sLocal = &quot;Value &apos;%0&apos; is invalid for property &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRINDEXVALUE : sLocal = &quot;Out of array range or incorrect array size for property &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRCOLLECTION : sLocal = &quot;Out of array range&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYNOTARRAY : sLocal = &quot;Argument nr.%0 should be an array&quot;
+ Case &quot;ERR&quot; &amp; ERRCONTROLNOTFOUND : sLocal = &quot;Control &apos;%0&apos; not found in parent (form, grid or dialog) &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOACTIVEFORM : sLocal = &quot;No active form or control found&quot;
+ Case &quot;ERR&quot; &amp; ERRDATABASEFORM : sLocal = &quot;Form &apos;%0&apos; has no underlying dataset&quot;
+ Case &quot;ERR&quot; &amp; ERRFOCUSINGRID : sLocal = &quot;Control &apos;%0&apos; not found in gridcontrol &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOGRIDINFORM : sLocal = &quot;No gridcontrol found in form &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRFINDRECORD : sLocal = &quot;FindNext() must be preceded by a successful FindRecord(...) call&quot;
+ Case &quot;ERR&quot; &amp; ERRSQLSTATEMENT : sLocal = &quot;SQL Error, SQL statement = &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROBJECTNOTFOUND : sLocal = &quot;%0 &apos;%1&apos; not found&quot;
+ Case &quot;ERR&quot; &amp; ERROPENOBJECT : sLocal = &quot;%0 &apos;%1&apos; could not be opened&quot;
+ Case &quot;ERR&quot; &amp; ERRCLOSEOBJECT : sLocal = &quot;%0 &apos;%1&apos; could not be closed&quot;
+ Case &quot;ERR&quot; &amp; ERRACTION : sLocal = &quot;Action not applicable in this context&quot;
+ Case &quot;ERR&quot; &amp; ERRSENDMAIL : sLocal = &quot;Mail service could not be activated&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMYETOPEN : sLocal = &quot;Form %0 is already open&quot;
+ Case &quot;ERR&quot; &amp; ERRMETHOD : sLocal = &quot;Method &apos;%0&apos; not applicable in this context&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYINIT : sLocal = &quot;Property &apos;%0&apos; applicable but not initialized&quot;
+ Case &quot;ERR&quot; &amp; ERRFILENOTCREATED : sLocal = &quot;File &apos;%0&apos; could not be created&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTFOUND : sLocal = &quot;Dialog &apos;%0&apos; not found in the currently loaded libraries&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGUNDEFINED : sLocal = &quot;Dialog unknown&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGSTARTED : sLocal = &quot;Dialog already started&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTSTARTED : sLocal = &quot;Dialog &apos;%0&apos; not active&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETNODATA : sLocal = &quot;Recordset delivered no data. Action on current record rejected&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLOSED : sLocal = &quot;Recordset has been closed. Recordset action rejected&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETRANGE : sLocal = &quot;Current record out of range&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETFORWARD : sLocal = &quot;Action rejected in a forward-only or not bookmarkable recordset&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDNULL : sLocal = &quot;Field is null or empty. Action rejected&quot;
+ Case &quot;ERR&quot; &amp; ERRFILEACCESS : sLocal = &quot;File access error on file &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROVERFLOW : sLocal = &quot;Field length (%0) exceeds maximum length. Use the &apos;%1&apos; method instead&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTACTIONQUERY : sLocal = &quot;Query &apos;%0&apos; is not an action query&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTUPDATABLE : sLocal = &quot;Database, recordset or field is read only&quot;
+ Case &quot;ERR&quot; &amp; ERRUPDATESEQUENCE : sLocal = &quot;Recordset update sequence error&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTNULLABLE : sLocal = &quot;Field &apos;%0&apos; must not contain a NULL value&quot;
+ Case &quot;ERR&quot; &amp; ERRROWDELETED : sLocal = &quot;Current row has been deleted by another process or user&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLONE : sLocal = &quot;Cloning a cloned Recordset is forbidden&quot;
+ Case &quot;ERR&quot; &amp; ERRQUERYDEFDELETED : sLocal = &quot;Pre-existing query &apos;%0&apos; has been deleted&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLEDEFDELETED : sLocal = &quot;Pre-existing table &apos;%0&apos; has been deleted&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLECREATION : sLocal = &quot;Table &apos;%0&apos; could not be created&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDCREATION : sLocal = &quot;Field &apos;%0&apos; could not be created&quot;
+ Case &quot;ERR&quot; &amp; ERRSUBFORMNOTFOUND : sLocal = &quot;Subform &apos;%0&apos; not found in parent form &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRWINDOW : sLocal = &quot;Current window is not a document&quot;
+ Case &quot;ERR&quot; &amp; ERRCOMPATIBILITY : sLocal = &quot;Field &apos;%0&apos; could not be converted due to incompatibility of field types between the respective database systems&quot;
+ Case &quot;ERR&quot; &amp; ERRPRECISION : sLocal = &quot;Field &apos;%0&apos; could not be loaded in record #%1 due to capacity shortage&quot;
+ Case &quot;ERR&quot; &amp; ERRMODULENOTFOUND : sLocal = &quot;Module &apos;%0&apos; not found in the currently loaded libraries&quot;
+ Case &quot;ERR&quot; &amp; ERRPROCEDURENOTFOUND : sLocal = &quot;Procedure &apos;%0&apos; not found in module &apos;%1&apos;&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;OBJECT&quot; : sLocal = &quot;Object&quot;
+ Case &quot;TABLE&quot; : sLocal = &quot;Table&quot;
+ Case &quot;QUERY&quot; : slocal = &quot;Query&quot;
+ Case &quot;FORM&quot; : sLocal = &quot;Form&quot;
+ Case &quot;REPORT&quot; : sLocal = &quot;Report&quot;
+ Case &quot;RECORDSET&quot; : sLocal = &quot;Recordset&quot;
+ Case &quot;FIELD&quot; : sLocal = &quot;Field&quot;
+ Case &quot;TEMPVAR&quot; : sLocal = &quot;Temporary variable&quot;
+ Case &quot;COMMANDBAR&quot; : sLocal = &quot;Command bar&quot;
+ Case &quot;COMMANDBARCONTROL&quot; : sLocal = &quot;Command bar control&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;ERR#&quot; : sLocal = &quot;Error #&quot;
+ Case &quot;ERROCCUR&quot; : sLocal = &quot;occurred&quot;
+ Case &quot;ERRLINE&quot; : sLocal = &quot;at line&quot;
+ Case &quot;ERRIN&quot; : sLocal = &quot;in&quot;
+ Case &quot;CALLTO&quot; : sLocal = &quot;a call to function&quot;
+ Case &quot;SAVECONSOLE&quot; : sLocal = &quot;Save console&quot;
+ Case &quot;SAVECONSOLEENTRIES&quot; : sLocal = &quot;The console entries have been saved successfully.&quot;
+ Case &quot;QUITSHORT&quot; : sLocal = &quot;Quit&quot;
+ Case &quot;QUIT&quot; : sLocal = &quot;Do you really want to quit the application ? Changed data will be saved.&quot;
+ Case &quot;ENTERING&quot; : sLocal = &quot;Entering&quot;
+ Case &quot;EXITING&quot; : sLocal = &quot;Exiting&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGTRACE_HELP&quot; : sLocal = &quot;Manage the console buffer and its entries&quot;
+ Case &quot;DLGTRACE_TITLE&quot; : sLocal = &quot;Console&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_HELP&quot; : sLocal = &quot;Clear the list and resize the circular buffer&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_LABEL&quot; : sLocal = &quot;Set max number of entries&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_HELP&quot; : sLocal = &quot;Text can be selected, copied, ...&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_TEXT&quot; : sLocal = &quot;--- Log file is empty ---&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_HELP&quot; : sLocal = &quot;Cancel and close the dialog&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_LABEL&quot; : sLocal = &quot;Cancel&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_HELP&quot; : sLocal = &quot;Clear the list&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_LABEL&quot; : sLocal = &quot;Clear the list&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_HELP&quot; : sLocal = &quot;Register only logging requests above given level&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_LABEL&quot; : sLocal = &quot;Set minimal trace level&quot;
+ Case &quot;DLGTRACE_CMDOK_HELP&quot; : sLocal = &quot;Validate&quot;
+ Case &quot;DLGTRACE_CMDOK_LABEL&quot; : sLocal = &quot;OK&quot;
+ Case &quot;DLGTRACE_CMDDUMP_HELP&quot; : sLocal = &quot;Choose a file and dump the actual list content in it&quot;
+ Case &quot;DLGTRACE_CMDDUMP_LABEL&quot; : sLocal = &quot;Dump to file&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_HELP&quot; : sLocal = &quot;Actual size of list&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_LABEL&quot; : sLocal = &quot;Actual number of entries:&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGFORMAT_HELP&quot; : sLocal = &quot;Export the form&quot;
+ Case &quot;DLGFORMAT_TITLE&quot; : sLocal = &quot;OutputTo&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_HELP&quot; : sLocal = &quot;Format in which the form should be exported&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_LABEL&quot; : sLocal = &quot;Select the output format&quot;
+ Case &quot;DLGFORMAT_CMDOK_HELP&quot; : sLocal = &quot;Validate your choice&quot;
+ Case &quot;DLGFORMAT_CMDOK_LABEL&quot; : sLocal = &quot;OK&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_HELP&quot; : sLocal = &quot;Cancel and close the dialog&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_LABEL&quot; : sLocal = &quot;Cancel&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case Else : sLocal = &quot;&quot;
+ End Select
+ Case &quot;FR&quot;
+ Select Case UCase(psShortlabel)
+ Case &quot;ERR&quot; &amp; ERRDBNOTCONNECTED : sLocal = &quot;Pas de connexion active trouvée à une banque de données&quot;
+ Case &quot;ERR&quot; &amp; ERRMISSINGARGUMENTS : sLocal = &quot;Des arguments sont manquants ou non initialisés&quot;
+ Case &quot;ERR&quot; &amp; ERRWRONGARGUMENT : sLocal = &quot;L&apos;argument n° %0 [Valeur = &apos;%1&apos;] n&apos;est pas valable&quot;
+ Case &quot;ERR&quot; &amp; ERRMAINFORM : sLocal = &quot;Le document &apos;%0&apos; ne contient aucun formulaire&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTIDENTIFIED : sLocal = &quot;Le formulaire &apos;%0&apos; n&apos;a pas pu être identifié parmi l&apos;ensemble des formulaires de la Database&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTFOUND : sLocal = &quot;Formulaire &apos;%0&apos; non trouvé&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTOPEN : sLocal = &quot;Le formulaire &apos;%0&apos; n&apos;est actuellement pas ouvert&quot;
+ Case &quot;ERR&quot; &amp; ERRDFUNCTION : sLocal = &quot;L&apos;exécution de la &quot;&quot;fonction database&quot;&quot; a échoué, SQL=%0&quot;
+ Case &quot;ERR&quot; &amp; ERROPENFORM : sLocal = &quot;Le formulaire &apos;%0&apos; n&apos;a pas pu être ouvert&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTY : sLocal = &quot;La propriété &apos;%0&apos; n&apos;est pas applicable dans ce contexte&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYVALUE : sLocal = &quot;La valeur &apos;%0&apos; est invalide pour la propriété &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRINDEXVALUE : sLocal = &quot;Indice invalide ou dimension erronée du tableau pour la propriété &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRCOLLECTION : sLocal = &quot;Indice de tableau invalide&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYNOTARRAY : sLocal = &quot;L&apos;argument n°%0 doit être un tableau&quot;
+ Case &quot;ERR&quot; &amp; ERRCONTROLNOTFOUND : sLocal = &quot;Contrôle &apos;%0&apos; non trouvé dans le parent (formulaire, contrôle de table ou dialogue) &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOACTIVEFORM : sLocal = &quot;Pas de formulaire ou de contrôle actif&quot;
+ Case &quot;ERR&quot; &amp; ERRDATABASEFORM : sLocal = &quot;Le formulaire &apos;%0&apos; n&apos;a pas de données sous-jacentes&quot;
+ Case &quot;ERR&quot; &amp; ERRFOCUSINGRID : sLocal = &quot;Contrôle &apos;%0&apos; non trouvé dans le contrôle de table &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOGRIDINFORM : sLocal = &quot;Aucun contrôle de table trouvé dans le formulaire &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRFINDRECORD : sLocal = &quot;FindNext() doit être précédé par un appel réussi à FindRecord(...)&quot;
+ Case &quot;ERR&quot; &amp; ERRSQLSTATEMENT : sLocal = &quot;Erreur SQL, instruction SQL = &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROBJECTNOTFOUND : sLocal = &quot;%0 &apos;%1&apos; non trouvé(e)&quot;
+ Case &quot;ERR&quot; &amp; ERROPENOBJECT : sLocal = &quot;%0 &apos;%1&apos;: ouverture en échec&quot;
+ Case &quot;ERR&quot; &amp; ERRCLOSEOBJECT : sLocal = &quot;%0 &apos;%1&apos;: fermeture en échec&quot;
+ Case &quot;ERR&quot; &amp; ERRACTION : sLocal = &quot;Action non applicable dans ce contexte&quot;
+ Case &quot;ERR&quot; &amp; ERRSENDMAIL : sLocal = &quot;Le service de messagerie n&apos;a pas pu être activé&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMYETOPEN : sLocal = &quot;Le formulaire %0 est déjà ouvert&quot;
+ Case &quot;ERR&quot; &amp; ERRMETHOD : sLocal = &quot;La méthode &apos;%0&apos; n&apos;est pas applicable dans ce contexte&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYINIT : sLocal = &quot;Propriété &apos;%0&apos; applicable mais non initialisée&quot;
+ Case &quot;ERR&quot; &amp; ERRFILENOTCREATED : sLocal = &quot;Erreur de création du fichier &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTFOUND : sLocal = &quot;Dialogue &apos;%0&apos; introuvable dans les librairies chargées actuellement&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGUNDEFINED : sLocal = &quot;Boîte de dialogue inconnue&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGSTARTED : sLocal = &quot;Dialogue déjà initialisé précédemment&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTSTARTED : sLocal = &quot;Dialogue &apos;%0&apos; non initialisé&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETNODATA : sLocal = &quot;Recordset n&apos;a pas fourni de données. Toute action sur les enregistrements est rejetée&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLOSED : sLocal = &quot;Recordset a été clôturé. Action sur l&apos;enregistrement courant est rejetée&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETRANGE : sLocal = &quot;L&apos;enregistrement courant est hors cadre&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETFORWARD : sLocal = &quot;Action rejetée car recordset lisible seulement vers l&apos;avant ou n&apos;acceptant pas de signets&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDNULL : sLocal = &quot;Champ nul ou vide. Action rejetée&quot;
+ Case &quot;ERR&quot; &amp; ERRFILEACCESS : sLocal = &quot;Erreur d&apos;accès au fichier &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROVERFLOW : sLocal = &quot;La longueur du champ (%0) dépasse la taille maximale autorisée. Utiliser de préférence la méthode &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTACTIONQUERY : sLocal = &quot;La requête &apos;%0&apos; n&apos;est pas une requête d&apos;action&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTUPDATABLE : sLocal = &quot;La banque de données, le recordset ou le champ sont en lecture seulement&quot;
+ Case &quot;ERR&quot; &amp; ERRUPDATESEQUENCE : sLocal = &quot;Erreur de séquence lors de la mise à jour d&apos;un Recordset&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTNULLABLE : sLocal = &quot;Le champ &apos;%0&apos; ne peut pas recevoir une valeur NULLe&quot;
+ Case &quot;ERR&quot; &amp; ERRROWDELETED : sLocal = &quot;L&apos;enregistrement courant a été effacé par un autre processus ou un autre utilisateur&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLONE : sLocal = &quot;Le clonage d&apos;un Recordset cloné est interdit&quot;
+ Case &quot;ERR&quot; &amp; ERRQUERYDEFDELETED : sLocal = &quot;La requête existante &apos;%0&apos; a été supprimée&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLEDEFDELETED : sLocal = &quot;La table existante &apos;%0&apos; a été supprimée&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLECREATION : sLocal = &quot;La table &apos;%0&apos; n&apos;a pas pu être créée&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDCREATION : sLocal = &quot;Le champ &apos;%0&apos; n&apos;a pas pu être créé&quot;
+ Case &quot;ERR&quot; &amp; ERRSUBFORMNOTFOUND : sLocal = &quot;Sous-formulaire &apos;%0&apos; non trouvé dans le formulaire parent &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRWINDOW : sLocal = &quot;La fenêtre courante n&apos;est pas un document&quot;
+ Case &quot;ERR&quot; &amp; ERRCOMPATIBILITY : sLocal = &quot;Le champ &apos;%0&apos; n&apos;a pas pu être converti à cause d&apos;une incompatibilité entre les types de champs supportés par les systèmes de bases de données respectifs&quot;
+ Case &quot;ERR&quot; &amp; ERRPRECISION : sLocal = &quot;Le champ &apos;%0&apos; n&apos;a pas pu être chargé dans l&apos;enregistrement #%1 par manque de capacité&quot;
+ Case &quot;ERR&quot; &amp; ERRMODULENOTFOUND : sLocal = &quot;Le module &apos;%0&apos; est introuvable dans les librairies chargées actuellement&quot;
+ Case &quot;ERR&quot; &amp; ERRPROCEDURENOTFOUND : sLocal = &quot;La procédure &apos;%0&apos; est introuvable dans le module &apos;%1&apos;&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;OBJECT&quot; : sLocal = &quot;Objet&quot;
+ Case &quot;TABLE&quot; : sLocal = &quot;Table&quot;
+ Case &quot;QUERY&quot; : slocal = &quot;Requête&quot;
+ Case &quot;FORM&quot; : sLocal = &quot;Formulaire&quot;
+ Case &quot;REPORT&quot; : sLocal = &quot;Rapport&quot;
+ Case &quot;RECORDSET&quot; : sLocal = &quot;Recordset&quot;
+ Case &quot;FIELD&quot; : sLocal = &quot;Champ&quot;
+ Case &quot;TEMPVAR&quot; : sLocal = &quot;Variable temporaire&quot;
+ Case &quot;COMMANDBAR&quot; : sLocal = &quot;Barre de commande&quot;
+ Case &quot;COMMANDBARCONTROL&quot; : sLocal = &quot;Elément de barre de commande&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;ERR#&quot; : sLocal = &quot;L&apos;erreur #&quot;
+ Case &quot;ERROCCUR&quot; : sLocal = &quot;s&apos;est produite&quot;
+ Case &quot;ERRLINE&quot; : sLocal = &quot;à la ligne&quot;
+ Case &quot;ERRIN&quot; : sLocal = &quot;dans&quot;
+ Case &quot;CALLTO&quot; : sLocal = &quot;un appel à la fonction&quot;
+ Case &quot;SAVECONSOLE&quot; : sLocal = &quot;Sauver console&quot;
+ Case &quot;SAVECONSOLEENTRIES&quot; : sLocal = &quot;Les entrées de la console ont été sauvées avec succès.&quot;
+ Case &quot;QUITSHORT&quot; : sLocal = &quot;Quitter&quot;
+ Case &quot;QUIT&quot; : sLocal = &quot;Voulez-vous réellement quitter l&apos;application ? Les données modifiées seront sauvées.&quot;
+ Case &quot;ENTERING&quot; : sLocal = &quot;Entrée dans&quot;
+ Case &quot;EXITING&quot; : sLocal = &quot;Sortie de&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGTRACE_HELP&quot; : sLocal = &quot;Gestion du tampon de la console et toutes ses entrées&quot;
+ Case &quot;DLGTRACE_TITLE&quot; : sLocal = &quot;Console&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_HELP&quot; : sLocal = &quot;Effacer la liste et redimensionner le tampon circulaire&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_LABEL&quot; : sLocal = &quot;Définir le nombre maximum d&apos;entrées&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_HELP&quot; : sLocal = &quot;Le texte peut être sélectionné, copié, ...&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_TEXT&quot; : sLocal = &quot;--- Le fichier journal est vide ---&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_HELP&quot; : sLocal = &quot;Annuler et fermer la boîte de dialogue&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_LABEL&quot; : sLocal = &quot;Annuler&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_HELP&quot; : sLocal = &quot;Effacer la liste&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_LABEL&quot; : sLocal = &quot;Effacer la liste&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_HELP&quot; : sLocal = &quot;N&apos;enregistrer que les demandes de journalisation à partir du niveau indiqué&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_LABEL&quot; : sLocal = &quot;Définir le niveau minimal d&apos;enregistrement&quot;
+ Case &quot;DLGTRACE_CMDOK_HELP&quot; : sLocal = &quot;Valider&quot;
+ Case &quot;DLGTRACE_CMDOK_LABEL&quot; : sLocal = &quot;OK&quot;
+ Case &quot;DLGTRACE_CMDDUMP_HELP&quot; : sLocal = &quot;Sélectionner un fichier et y vider le contenu actuel des traces enregistrées&quot;
+ Case &quot;DLGTRACE_CMDDUMP_LABEL&quot; : sLocal = &quot;Vider dans fichier&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_HELP&quot; : sLocal = &quot;Taille actuelle de la liste&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_LABEL&quot; : sLocal = &quot;Nombre actuel d&apos;entrées:&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGFORMAT_HELP&quot; : sLocal = &quot;Exporter le formulaire&quot;
+ Case &quot;DLGFORMAT_TITLE&quot; : sLocal = &quot;OutputTo&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_HELP&quot; : sLocal = &quot;Format dans lequel le formulaire sera exporté&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_LABEL&quot; : sLocal = &quot;Selectionner le format de sortie&quot;
+ Case &quot;DLGFORMAT_CMDOK_HELP&quot; : sLocal = &quot;Valider votre choix&quot;
+ Case &quot;DLGFORMAT_CMDOK_LABEL&quot; : sLocal = &quot;OK&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_HELP&quot; : sLocal = &quot;Annuler et fermer la boîte de dialogue&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_LABEL&quot; : sLocal = &quot;Annuler&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case Else : sLocal = _Getlabel(psShortLabel, &quot;DEFAULT&quot;)
+ End Select
+&apos;********************************************************
+&apos;Translated by Iñigo Zuluaga
+&apos;********************************************************
+ Case &quot;ES&quot; &apos;(España)
+ Select Case UCase(psShortlabel)
+ Case &quot;ERR&quot; &amp; ERRDBNOTCONNECTED : sLocal = &quot;No se ha encontrado una conexión activa a una base de datos&quot;
+ Case &quot;ERR&quot; &amp; ERRMISSINGARGUMENTS : sLocal = &quot;Faltan argumentos o no están inicializados&quot;
+ Case &quot;ERR&quot; &amp; ERRWRONGARGUMENT : sLocal = &quot;El argumento nr. %0 [Value = &apos;%1&apos;] no es válido&quot;
+ Case &quot;ERR&quot; &amp; ERRMAINFORM : sLocal = &quot;El documento &apos;%0&apos; no contiene ningún formulario&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTIDENTIFIED : sLocal = &quot;No se ha identificado el formulario &apos;%0&apos; en el conjunto de formularios de la base de datos&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTFOUND : sLocal = &quot;No se ha encontrado el formulario &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTOPEN : sLocal = &quot;El formulario &apos;%0&apos; no está abierto&quot;
+ Case &quot;ERR&quot; &amp; ERRDFUNCTION : sLocal = &quot;La ejecución de DFunction falló, SQL=%0&quot;
+ Case &quot;ERR&quot; &amp; ERROPENFORM : sLocal = &quot;El formulario &apos;%0&apos; no se puede abrir&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTY : sLocal = &quot;La propiedad &apos;%0&apos; no es aplicable en este contexto&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYVALUE : sLocal = &quot;El valor &apos;%0&apos; es inválido para la propiedad &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRINDEXVALUE : sLocal = &quot;Fuera del rango de la matriz o tamaño incorrecto de la matriz para la propiedad &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRCOLLECTION : sLocal = &quot;Fuera del rango de la matriz&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYNOTARRAY : sLocal = &quot;El argumento nr.%0 debería ser una matriz&quot;
+ Case &quot;ERR&quot; &amp; ERRCONTROLNOTFOUND : sLocal = &quot;El control &apos;%0&apos; not found in parent (formulario, control de tabla or diálogo) &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOACTIVEFORM : sLocal = &quot;No se ha encontrado un formulario o control activo&quot;
+ Case &quot;ERR&quot; &amp; ERRDATABASEFORM : sLocal = &quot;El formulario &apos;%0&apos; no tiene datos subyacentes&quot;
+ Case &quot;ERR&quot; &amp; ERRFOCUSINGRID : sLocal = &quot;No se ha encontrado el control &apos;%0&apos; en el control de tabla &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOGRIDINFORM : sLocal = &quot;No se ha encontrado un control de tabla en el formulario &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRFINDRECORD : sLocal = &quot;FindNext() tiene que ser precedido por una llamada exitosa de FindRecord(...)&quot;
+ Case &quot;ERR&quot; &amp; ERRSQLSTATEMENT : sLocal = &quot;Error SQL, instrución SQL = &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROBJECTNOTFOUND : sLocal = &quot;%0 &apos;%1&apos; no encontrado&quot;
+ Case &quot;ERR&quot; &amp; ERROPENOBJECT : sLocal = &quot;%0 &apos;%1&apos; no se puede abrir&quot;
+ Case &quot;ERR&quot; &amp; ERRCLOSEOBJECT : sLocal = &quot;%0 &apos;%1&apos; no se puede abrir&quot;
+ Case &quot;ERR&quot; &amp; ERRACTION : sLocal = &quot;Acción no aplicable en este contexto&quot;
+ Case &quot;ERR&quot; &amp; ERRSENDMAIL : sLocal = &quot;No se puede activar el servicio de correo&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMYETOPEN : sLocal = &quot;El formulario %0 ya está abierto&quot;
+ Case &quot;ERR&quot; &amp; ERRMETHOD : sLocal = &quot;El método &apos;%0&apos; no es aplicable en este contexto&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYINIT : sLocal = &quot;Propiedad &apos;%0&apos; aplicable pero no inicializada&quot;
+ Case &quot;ERR&quot; &amp; ERRFILENOTCREATED : sLocal = &quot;No se ha podido crear el archivo &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTFOUND : sLocal = &quot;No se ha encontrado el diálogo &apos;%0&apos; en las bibliotecas cargadas actualmente&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGUNDEFINED : sLocal = &quot;Diálogo desconocido&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGSTARTED : sLocal = &quot;El diálogo ya está iniciado&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTSTARTED : sLocal = &quot;El diálogo &apos;%0&apos; no está activo&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETNODATA : sLocal = &quot;El Recordset no suministra datos. La acción en el registro actual rechazada&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLOSED : sLocal = &quot;El recorset se ha cerrado. Acción con el Recordset rechazada&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETRANGE : sLocal = &quot;Registro actual fuera de rango&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETFORWARD : sLocal = &quot;Acción rechazada en un recorset legible sólo hacia adelante o que no admita marcadores&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDNULL : sLocal = &quot;El campo es nulo o vacío. Acción rechazada&quot;
+ Case &quot;ERR&quot; &amp; ERRFILEACCESS : sLocal = &quot;Error durante el acceso al archivo &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROVERFLOW : sLocal = &quot;La longitud del campo (%0) excede la longitud máxima. Reemplazar por el método &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTACTIONQUERY : sLocal = &quot;La consulta &apos;%0&apos; no es una consulta de acción&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTUPDATABLE : sLocal = &quot;La base de datos, el Recordset o el Campo es de sólo lectura&quot;
+ Case &quot;ERR&quot; &amp; ERRUPDATESEQUENCE : sLocal = &quot;Error durante la secuencia de actualización del Recordset&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTNULLABLE : sLocal = &quot;El campo &apos;%0&apos; no puede contener un valor NULL&quot;
+ Case &quot;ERR&quot; &amp; ERRROWDELETED : sLocal = &quot;La fila actual ha sido borrada por otro proceso o usuario&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLONE : sLocal = &quot;No se puede clonar un Recordset clonado&quot;
+ Case &quot;ERR&quot; &amp; ERRQUERYDEFDELETED : sLocal = &quot;Se ha borrado la consulta pre-existente &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLEDEFDELETED : sLocal = &quot;Se ha borrado la tabla pre-existente &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLECREATION : sLocal = &quot;No se ha podido crear la Tabla &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDCREATION : sLocal = &quot;No se ha podido crear el campo &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRSUBFORMNOTFOUND : sLocal = &quot;No se ha encontrado el Subformulario &apos;%0&apos; en el subformulario padre &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRWINDOW : sLocal = &quot;La ventana actual no es un documento&quot;
+ Case &quot;ERR&quot; &amp; ERRCOMPATIBILITY : sLocal = &quot;El campo &apos;%0&apos; no se ha convertido debido a una incompatibilidad de los tipos de campo soportados entre las dos bases de datos&quot;
+ Case &quot;ERR&quot; &amp; ERRPRECISION : sLocal = &quot;El campo &apos;%0&apos; no se ha cargado en el registro #%1 por falta de capacidad&quot;
+ Case &quot;ERR&quot; &amp; ERRMODULENOTFOUND : sLocal = &quot;Module &apos;%0&apos; not found in the currently loaded libraries&quot;
+ Case &quot;ERR&quot; &amp; ERRPROCEDURENOTFOUND : sLocal = &quot;Procedure &apos;%0&apos; not found in module &apos;%1&apos;&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;OBJECT&quot; : sLocal = &quot;Objeto&quot;
+ Case &quot;TABLE&quot; : sLocal = &quot;Tabla&quot;
+ Case &quot;QUERY&quot; : slocal = &quot;Consulta&quot;
+ Case &quot;FORM&quot; : sLocal = &quot;Formulario&quot;
+ Case &quot;REPORT&quot; : sLocal = &quot;Informe&quot;
+ Case &quot;RECORDSET&quot; : sLocal = &quot;Recordset&quot;
+ Case &quot;FIELD&quot; : sLocal = &quot;Campo&quot;
+ Case &quot;TEMPVAR&quot; : sLocal = &quot;Variable temporal&quot;
+ Case &quot;COMMANDBAR&quot; : sLocal = &quot;Barra de comandos&quot;
+ Case &quot;COMMANDBARCONTROL&quot; : sLocal = &quot;Control de barra de comandos&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;ERR#&quot; : sLocal = &quot;Error #&quot;
+ Case &quot;ERROCCUR&quot; : sLocal = &quot;ocurrido&quot;
+ Case &quot;ERRLINE&quot; : sLocal = &quot;en línea&quot;
+ Case &quot;ERRIN&quot; : sLocal = &quot;en&quot;
+ Case &quot;CALLTO&quot; : sLocal = &quot;una llamada a la función&quot;
+ Case &quot;SAVECONSOLE&quot; : sLocal = &quot;Guardar consola&quot;
+ Case &quot;SAVECONSOLEENTRIES&quot; : sLocal = &quot;Las entradas de la consola han sido guardadas correctamente.&quot;
+ Case &quot;QUITSHORT&quot; : sLocal = &quot;Cerrar&quot;
+ Case &quot;QUIT&quot; : sLocal = &quot;Quieres realmente cerrar la aplicación? los datos cambiados se guardarán.&quot;
+ Case &quot;ENTERING&quot; : sLocal = &quot;Entrando&quot;
+ Case &quot;EXITING&quot; : sLocal = &quot;Saliendo&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGTRACE_HELP&quot; : sLocal = &quot;Gestión del buffer de la consola y sus entradas&quot;
+ Case &quot;DLGTRACE_TITLE&quot; : sLocal = &quot;Consola&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_HELP&quot; : sLocal = &quot;Limpiar la lista y redimensionar el buffer circular&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_LABEL&quot; : sLocal = &quot;Definir el número máximo de entradas&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_HELP&quot; : sLocal = &quot;El texto puede ser seleccionado, copiado, ...&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_TEXT&quot; : sLocal = &quot;--- El archivo Histórico está vacío ---&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_HELP&quot; : sLocal = &quot;Cancelar y cerrar el diálogo&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_LABEL&quot; : sLocal = &quot;Cancelar&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_HELP&quot; : sLocal = &quot;Limpiar la lista&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_LABEL&quot; : sLocal = &quot;Limpiar la lista&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_HELP&quot; : sLocal = &quot;No registrar más que las peticiones de registro a partir de un nivel indicado&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_LABEL&quot; : sLocal = &quot;Definir el nivel mínimo de registro&quot;
+ Case &quot;DLGTRACE_CMDOK_HELP&quot; : sLocal = &quot;Validar&quot;
+ Case &quot;DLGTRACE_CMDOK_LABEL&quot; : sLocal = &quot;Aceptar&quot;
+ Case &quot;DLGTRACE_CMDDUMP_HELP&quot; : sLocal = &quot;Elegir un archivo y guardar en él el contenido de la lista actual&quot;
+ Case &quot;DLGTRACE_CMDDUMP_LABEL&quot; : sLocal = &quot;Guardar en a archivo&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_HELP&quot; : sLocal = &quot;Tamaño actual de la lista&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_LABEL&quot; : sLocal = &quot;Numero actual de entradas:&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGFORMAT_HELP&quot; : sLocal = &quot;Exportar el formulario&quot;
+ Case &quot;DLGFORMAT_TITLE&quot; : sLocal = &quot;Exportar como&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_HELP&quot; : sLocal = &quot;Formato en el que será ser exportado el formulario&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_LABEL&quot; : sLocal = &quot;Seleccionar el formato de salida&quot;
+ Case &quot;DLGFORMAT_CMDOK_HELP&quot; : sLocal = &quot;Validar su elección&quot;
+ Case &quot;DLGFORMAT_CMDOK_LABEL&quot; : sLocal = &quot;Aceptar&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_HELP&quot; : sLocal = &quot;Cancelar y cerrar el diálogo&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_LABEL&quot; : sLocal = &quot;Cancelar&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case Else : sLocal = _Getlabel(psShortLabel, &quot;DEFAULT&quot;)
+ End Select
+&apos;********************************************************
+&apos;Translated by Gisbert Friege
+&apos;********************************************************
+ Case &quot;DE&quot;
+ Select Case UCase(psShortlabel)
+ Case &quot;ERR&quot; &amp; ERRDBNOTCONNECTED : sLocal = &quot;Keine aktive Verbindung zu einer Datenbank gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRMISSINGARGUMENTS : sLocal = &quot;Argumente fehlen oder sind nicht initialisiert&quot;
+ Case &quot;ERR&quot; &amp; ERRWRONGARGUMENT : sLocal = &quot;Argument Nr. %0 [Wert = &apos;%1&apos;] ist ungültig&quot;
+ Case &quot;ERR&quot; &amp; ERRMAINFORM : sLocal = &quot;Dokument &apos;%0&apos; enthält kein Formular&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTIDENTIFIED : sLocal = &quot;Formular &apos;%0&apos; nicht bei den Datenbank-Formularen erkannt&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTFOUND : sLocal = &quot;Formular &apos;%0&apos; nicht gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMNOTOPEN : sLocal = &quot;Formular &apos;%0&apos; ist zur Zeit nicht offen&quot;
+ Case &quot;ERR&quot; &amp; ERRDFUNCTION : sLocal = &quot;DFunction Ausführung misslungen, SQL=%0&quot;
+ Case &quot;ERR&quot; &amp; ERROPENFORM : sLocal = &quot;Formular &apos;%0&apos; konnte nicht geöffnet werden&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTY : sLocal = &quot;Eigenschaft &apos;%0&apos; in diesem Kontext nicht anwendbar&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYVALUE : sLocal = &quot;Wert &apos;%0&apos; ist ungültig für die Eigenschaft &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRINDEXVALUE : sLocal = &quot;Außerhalb des Array-Bereichs oder falsche Array-Größe für Eigenschaft &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRCOLLECTION : sLocal = &quot;Außerhalb des Array-Bereichs&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYNOTARRAY : sLocal = &quot;Argument Nr.%0 sollte ein Array sein&quot;
+ Case &quot;ERR&quot; &amp; ERRCONTROLNOTFOUND : sLocal = &quot;Steuerelement &apos;%0&apos; nicht gefunden in parent (Formular, Tabelle oder Dialog) &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOACTIVEFORM : sLocal = &quot;Kein aktives Formular oder Steuerelement gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRDATABASEFORM : sLocal = &quot;Formular &apos;%0&apos; basiert nicht auf einem Datensatz&quot;
+ Case &quot;ERR&quot; &amp; ERRFOCUSINGRID : sLocal = &quot;Steuerelement &apos;%0&apos; im Tabellen-Steuerelement &apos;%1&apos; nicht gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRNOGRIDINFORM : sLocal = &quot;Kein Tabellen-Steuerelement im Formular &apos;%0&apos; gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRFINDRECORD : sLocal = &quot;Bei FindNext() muss ein erfolgreicher FindRecord(...)-Aufruf vorhergehen&quot;
+ Case &quot;ERR&quot; &amp; ERRSQLSTATEMENT : sLocal = &quot;SQL Error, SQL statement = &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROBJECTNOTFOUND : sLocal = &quot;%0 &apos;%1&apos; nicht gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERROPENOBJECT : sLocal = &quot;%0 &apos;%1&apos; konnte nicht geöffnet werden&quot;
+ Case &quot;ERR&quot; &amp; ERRCLOSEOBJECT : sLocal = &quot;%0 &apos;%1&apos; konnte nicht geschlossen werden&quot;
+ Case &quot;ERR&quot; &amp; ERRACTION : sLocal = &quot;Aktion in diesem Kontext nicht anwendbar&quot;
+ Case &quot;ERR&quot; &amp; ERRSENDMAIL : sLocal = &quot;Email-Dienst konnte nicht aktiviert werden&quot;
+ Case &quot;ERR&quot; &amp; ERRFORMYETOPEN : sLocal = &quot;Formular %0 ist schon offen&quot;
+ Case &quot;ERR&quot; &amp; ERRMETHOD : sLocal = &quot;Methode &apos;%0&apos; in diesem Kontext nicht anwendbar&quot;
+ Case &quot;ERR&quot; &amp; ERRPROPERTYINIT : sLocal = &quot;Eigenschaft &apos;%0&apos; anwendbar aber nicht initialisiert&quot;
+ Case &quot;ERR&quot; &amp; ERRFILENOTCREATED : sLocal = &quot;Datei &apos;%0&apos; konnte nicht erzeugt werden&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTFOUND : sLocal = &quot;Dialog &apos;%0&apos; nicht in den aktuell geladenen Bibliotheken gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGUNDEFINED : sLocal = &quot;Dialog unbekannt&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGSTARTED : sLocal = &quot;Dialog schon gestartet&quot;
+ Case &quot;ERR&quot; &amp; ERRDIALOGNOTSTARTED : sLocal = &quot;Dialog &apos;%0&apos; nicht aktiv&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETNODATA : sLocal = &quot;Datensatz ergab keine Daten. Aktion auf aktuellem Datensatz verweigert&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLOSED : sLocal = &quot;Datensatz wurde geschlossen. Datensatz-Aktion verweigert&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETRANGE : sLocal = &quot;Aktueller Datensatz außerhalb des Bereichs&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETFORWARD : sLocal = &quot;Aktion verweigert auf einem nur vorwärts lesbaren oder keine Textmarken unterstützenden Datensatz&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDNULL : sLocal = &quot;Feld ist null oder leer. Aktion verweigert&quot;
+ Case &quot;ERR&quot; &amp; ERRFILEACCESS : sLocal = &quot;Dateizugriffs-Fehler bei Datei &apos;%0&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERROVERFLOW : sLocal = &quot;Feldlänge (%0) überschreitet die maximale Länge. Verwende stattdessen die Methode &apos;%1&apos;&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTACTIONQUERY : sLocal = &quot;Abfrage &apos;%0&apos; ist keine Aktionsabfrage&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTUPDATABLE : sLocal = &quot;Datenbank, Datensatz oder Feld kann nur gelesen werden&quot;
+ Case &quot;ERR&quot; &amp; ERRUPDATESEQUENCE : sLocal = &quot;Datensatz-Update Folgefehler&quot;
+ Case &quot;ERR&quot; &amp; ERRNOTNULLABLE : sLocal = &quot;Feld &apos;%0&apos; darf keinen NULL-Wert haben&quot;
+ Case &quot;ERR&quot; &amp; ERRROWDELETED : sLocal = &quot;Aktuelle Zeile wurde durch einen anderen Prozess oder Benutzer gelösch&quot;
+ Case &quot;ERR&quot; &amp; ERRRECORDSETCLONE : sLocal = &quot;Ein geklonter Datensatz kann nicht geklont werden&quot;
+ Case &quot;ERR&quot; &amp; ERRQUERYDEFDELETED : sLocal = &quot;Bereits vorhandene Abfrage &apos;%0&apos; wurde gelöscht&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLEDEFDELETED : sLocal = &quot;Bereits vorhandene Tabelle &apos;%0&apos; wurde gelöscht&quot;
+ Case &quot;ERR&quot; &amp; ERRTABLECREATION : sLocal = &quot;Tabelle &apos;%0&apos; konnte nicht erzeugt werden&quot;
+ Case &quot;ERR&quot; &amp; ERRFIELDCREATION : sLocal = &quot;Feld &apos;%0&apos; konnte nicht erzeugt werden&quot;
+ Case &quot;ERR&quot; &amp; ERRSUBFORMNOTFOUND : sLocal = &quot;Unterformular &apos;%0&apos; nicht im Eltern-Formular &apos;%1‘ gefunden&quot;
+ Case &quot;ERR&quot; &amp; ERRWINDOW : sLocal = &quot;Aktuelles Fenster ist kein Dokument&quot;
+ Case &quot;ERR&quot; &amp; ERRCOMPATIBILITY : sLocal = &quot;Feld &apos;%0&apos; konnte wegen inkompatibler Feldtypen der Datenbanksysteme nicht konvertiert werden&quot;
+ Case &quot;ERR&quot; &amp; ERRPRECISION : sLocal = &quot;Feld &apos;%0&apos; konnte wegen fehlender Speicherkapazität nicht in den Datensatz #%1 geladen werden&quot;
+ Case &quot;ERR&quot; &amp; ERRMODULENOTFOUND : sLocal = &quot;Modul &apos;%0&apos; nicht gefunden in den aktuell geladen Bibliotheken&quot;
+ Case &quot;ERR&quot; &amp; ERRPROCEDURENOTFOUND : sLocal = &quot;Prozedur &apos;%0&apos; im Modul &apos;%1&apos; nicht gefunden&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;OBJECT&quot; : sLocal = &quot;Objekt&quot;
+ Case &quot;TABLE&quot; : sLocal = &quot;Tabelle&quot;
+ Case &quot;QUERY&quot; : slocal = &quot;Abfrage&quot;
+ Case &quot;FORM&quot; : sLocal = &quot;Formular&quot;
+ Case &quot;REPORT&quot; : sLocal = &quot;Report&quot;
+ Case &quot;RECORDSET&quot; : sLocal = &quot;Datensatz&quot;
+ Case &quot;FIELD&quot; : sLocal = &quot;Feld&quot;
+ Case &quot;TEMPVAR&quot; : sLocal = &quot;Temporäre Variable&quot;
+ Case &quot;COMMANDBAR&quot; : sLocal = &quot;Befehlsleiste&quot;
+ Case &quot;COMMANDBARCONTROL&quot; : sLocal = &quot;Befehlsleisten-Steuerelement&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;ERR#&quot; : sLocal = &quot;Error #&quot;
+ Case &quot;ERROCCUR&quot; : sLocal = &quot;aufgetreten&quot;
+ Case &quot;ERRLINE&quot; : sLocal = &quot;in Zeile&quot;
+ Case &quot;ERRIN&quot; : sLocal = &quot;in&quot;
+ Case &quot;CALLTO&quot; : sLocal = &quot;ein Funktionsaufruf&quot;
+ Case &quot;SAVECONSOLE&quot; : sLocal = &quot;Konsoleneingaben sichern&quot;
+ Case &quot;SAVECONSOLEENTRIES&quot; : sLocal = &quot;Die Konsoleneingaben wurden erfolgreich gesichert.&quot;
+ Case &quot;QUITSHORT&quot; : sLocal = &quot;Beenden&quot;
+ Case &quot;QUIT&quot; : sLocal = &quot;Wollen Sie wirklich die Anwendung beenden? Geänderte Daten werden gesichert.&quot;
+ Case &quot;ENTERING&quot; : sLocal = &quot;Beginne mit&quot;
+ Case &quot;EXITING&quot; : sLocal = &quot;Verlasse&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGTRACE_HELP&quot; : sLocal = &quot;Verwalte den Konsolenpuffer und seine Eingaben&quot;
+ Case &quot;DLGTRACE_TITLE&quot; : sLocal = &quot;Konsole&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_HELP&quot; : sLocal = &quot;Leere die Liste und ändere die Größe des Umlaufpuffers&quot;
+ Case &quot;DLGTRACE_LBLENTRIES_LABEL&quot; : sLocal = &quot;Setze maximale Anzahl von Eingaben&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_HELP&quot; : sLocal = &quot;Text kann ausgewählt, kopiert, ... werden&quot;
+ Case &quot;DLGTRACE_TXTTRACELOG_TEXT&quot; : sLocal = &quot;--- Log Datei ist leer ---&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_HELP&quot; : sLocal = &quot;Abbrechen und den Dialog schließen&quot;
+ Case &quot;DLGTRACE_CMDCANCEL_LABEL&quot; : sLocal = &quot;Abbrechen&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_HELP&quot; : sLocal = &quot;Leere die Liste&quot;
+ Case &quot;DLGTRACE_LBLCLEAR_LABEL&quot; : sLocal = &quot;Leere die Liste&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_HELP&quot; : sLocal = &quot;Registriere nur Logging-Anfragen oberhalb des gegebenen Levels&quot;
+ Case &quot;DLGTRACE_LBLMINLEVEL_LABEL&quot; : sLocal = &quot;Setze minimalen Fehlerbehandlungs-Level&quot;
+ Case &quot;DLGTRACE_CMDOK_HELP&quot; : sLocal = &quot;Übernehmen&quot;
+ Case &quot;DLGTRACE_CMDOK_LABEL&quot; : sLocal = &quot;OK&quot;
+ Case &quot;DLGTRACE_CMDDUMP_HELP&quot; : sLocal = &quot;Wähle eine Datei und speichere darin den aktuellen Listeninhalt&quot;
+ Case &quot;DLGTRACE_CMDDUMP_LABEL&quot; : sLocal = &quot;Ausgabe in Datei&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_HELP&quot; : sLocal = &quot;Aktuelle Länge der Liste&quot;
+ Case &quot;DLGTRACE_LBLNBENTRIES_LABEL&quot; : sLocal = &quot;Aktuelle Anzahl von Einträgen:&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case &quot;DLGFORMAT_HELP&quot; : sLocal = &quot;Exportiere das Formular&quot;
+ Case &quot;DLGFORMAT_TITLE&quot; : sLocal = &quot;Export&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_HELP&quot; : sLocal = &quot;Format, in dem das Formular exportiert werden soll&quot;
+ Case &quot;DLGFORMAT_LBLFORMAT_LABEL&quot; : sLocal = &quot;Wähle das Ausgabe-Format&quot;
+ Case &quot;DLGFORMAT_CMDOK_HELP&quot; : sLocal = &quot;Auswahl übernehmen&quot;
+ Case &quot;DLGFORMAT_CMDOK_LABEL&quot; : sLocal = &quot;OK&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_HELP&quot; : sLocal = &quot;Abbrechen und den Dialog schließen&quot;
+ Case &quot;DLGFORMAT_CMDCANCEL_LABEL&quot; : sLocal = &quot;Abbrechen&quot;
+ &apos;----------------------------------------------------------------------------------------------------------------------
+ Case Else : sLocal = _Getlabel(psShortLabel, &quot;DEFAULT&quot;)
+ End Select
+REM *******************************************************************************************************************************************
+REM *** ***
+REM *** ANY OTHER LANGUAGE TO BE INSERTED HERE ***
+REM *** ***
+REM *******************************************************************************************************************************************
+ Case Else
+ sLocal = _Getlabel(psShortLabel, &quot;DEFAULT&quot;)
+ End Select
+
+Exit_Function:
+ _Getlabel = sLocal
+ Exit Function
+Error_Function:
+ sLocal = psShortLabel
+ GoTo Exit_Function
+End Function &apos; GetLabel V0.8.9
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetLabelArray(ByVal pvShortlabel As Variant, Optional ByVal psLocale As String) As Variant
+&apos; Return the localized label corresponding with the ShortLabel array of strings
+
+ If IsMissing(psLocale) Then psLocale = UCase(Left(_GetLocale(), 2)) Else psLocale = UCase(psLocale)
+ On Local Error Goto Error_Function
+
+Dim vLocal() As Variant, i As integer
+ vLocal = Array()
+
+ If Not IsArray(pvShortLabel) Then
+ vLocal = _GetLabel(pvShortLabel, psLocale)
+ Goto Exit_Function
+ End If
+
+ ReDim vLocal(LBound(pvShortLabel) To UBound(pvShortlabel))
+ For i = LBound(pvShortLabel) To UBound(pvShortlabel)
+ vLocal(i) = _GetLabel(pvShortLabel(i), psLocale)
+ Next i
+
+Exit_Function:
+ _GetlabelArray = vLocal()
+ Exit Function
+Error_Function:
+ vLocal = Array()
+ GoTo Exit_Function
+End Function &apos; GetLabelArray V0.8.9
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetLocale() as String
+&apos;Return OO localization
+&apos;Derived from Tools library
+
+Dim oLocale as Object
+ oLocale = _GetRegistryKeyContent(&quot;org.openoffice.Setup/L10N&quot;)
+ _GetLocale = oLocale.getByName(&quot;ooLocale&quot;)
+End Function &apos; GetLocale V0.8.9
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Methods.xba b/wizards/source/access2base/Methods.xba
new file mode 100644
index 000000000..7f809c6c1
--- /dev/null
+++ b/wizards/source/access2base/Methods.xba
@@ -0,0 +1,300 @@
+<?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="Methods" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AddItem(Optional pvBox As Variant, ByVal Optional pvItem As Variant, ByVal Optional pvIndex) As Boolean
+&apos; Add an item in a Listbox
+
+ Utils._SetCalledSub(&quot;AddItem&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If IsMissing(pvBox) Or IsMissing(pvItem) Then Call _TraceArguments()
+ If IsMissing(pvIndex) Then pvIndex = -1
+ If Not Utils._CheckArgument(pvBox, 1, Array(CTLLISTBOX, CTLCOMBOBOX)) Then Goto Exit_Function
+
+ AddItem = pvBox.AddItem(pvItem, pvIndex)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;AddItem&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;AddItem&quot;, Erl)
+ AddItem = False
+ GoTo Exit_Function
+End Function &apos; AddItem V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(Optional pvObject As Variant, ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if pvObject has a valid property called pvProperty (case-insensitive comparison !)
+
+Dim vPropertiesList As Variant
+
+ Utils._SetCalledSub(&quot;hasProperty&quot;)
+ If IsMissing(pvObject) Or IsMissing(pvProperty) Then Call _TraceArguments()
+
+ hasProperty = False
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJCOLLECTION, OBJFORM, OBJSUBFORM, OBJCONTROL, OBJOPTIONGROUP, OBJEVENT _
+ , OBJPROPERTY, OBJDATABASE, OBJQUERYDEF, OBJTABLEDEF, OBJRECORDSET _
+ )) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvProperty, 2, vbString) Then Goto Exit_Function
+
+ hasProperty = pvObject.hasProperty(pvProperty)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;hasProperty&quot;)
+ Exit Function
+End Function &apos; hasProperty V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Move(Optional pvObject As Object _
+ , ByVal Optional pvLeft As Variant _
+ , ByVal Optional pvTop As Variant _
+ , ByVal Optional pvWidth As Variant _
+ , ByVal Optional pvHeight As Variant _
+ ) As Variant
+&apos; Execute Move method
+ Utils._SetCalledSub(&quot;Move&quot;)
+ If IsMissing(pvObject) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Move = False
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJFORM, OBJDIALOG)) Then Goto Exit_Function
+ If IsMissing(pvLeft) Then Call _TraceArguments()
+ If IsMissing(pvTop) Then pvTop = -1
+ If IsMissing(pvWidth) Then pvWidth = -1
+ If IsMissing(pvHeight) Then pvHeight = -1
+
+ Move = pvObject.Move(pvLeft, pvTop, pvWidth, pvHeight)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Move&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Move&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Move V.0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenHelpFile()
+&apos; Open the help file from the Help menu (IDE only)
+Const cstHelpFile = &quot;http://www.access2base.com/access2base.html&quot;
+
+ On Local Error Resume Next
+ Call _ShellExecute(cstHelpFile)
+
+End Function &apos; OpenHelpFile V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(Optional pvObject As Variant, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperties As Variant, oCounter As Variant, opProperty As Variant
+Dim vPropertiesList() As Variant
+
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments()
+ Utils._SetCalledSub(&quot;Properties&quot;)
+
+ Set vProperties = Nothing
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJCOLLECTION, OBJFORM, OBJSUBFORM, OBJCONTROL, OBJOPTIONGROUP, OBJEVENT _
+ , OBJPROPERTY, OBJDATABASE, OBJQUERYDEF, OBJTABLEDEF, OBJRECORDSET _
+ )) Then Goto Exit_Function
+
+ If IsMissing(pvIndex) Then vProperties = pvObject.Properties Else vProperties = pvObject.Properties(pvIndex)
+
+Exit_Function:
+ Set Properties = vProperties
+ Utils._ResetCalledSub(&quot;Properties&quot;)
+ Exit Function
+End Function &apos; Properties V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Refresh(Optional pvObject As Variant) As Boolean
+&apos; Refresh data with its most recent value in the database in a form or subform
+ Utils._SetCalledSub(&quot;Refresh&quot;)
+ If IsMissing(pvObject) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Refresh = False
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+
+ Refresh = pvObject.Refresh()
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Refresh&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Refresh&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Refresh V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function RemoveItem(Optional pvBox As Variant,ByVal Optional pvIndex) As Boolean
+&apos; Remove an item from a Listbox
+&apos; Index may be a string value or an index-position
+
+ Utils._SetCalledSub(&quot;RemoveItem&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If IsMissing(pvBox) Or IsMissing(pvIndex) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvBox, 1, Array(CTLLISTBOX, CTLCOMBOBOX)) Then Goto Exit_Function
+
+ RemoveItem = pvBox.RemoveItem(pvIndex)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;RemoveItem&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;RemoveItem&quot;, Erl)
+ RemoveItem = False
+ GoTo Exit_Function
+End Function &apos; RemoveItem V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Requery(Optional pvObject As Variant) As Boolean
+&apos; Refresh data displayed in a form, subform, combobox or listbox
+ Utils._SetCalledSub(&quot;Requery&quot;)
+ If IsMissing(pvObject) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJFORM, OBJCONTROL, OBJSUBFORM)) Then Goto Exit_Function
+
+ Requery = pvObject.Requery()
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Requery&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Requery&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Requery V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function SetFocus(Optional pvObject As Variant) As Boolean
+&apos; Execute SetFocus method
+ Utils._SetCalledSub(&quot;setFocus&quot;)
+ If IsMissing(pvObject) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJFORM, OBJCONTROL)) Then Goto Exit_Function
+
+ SetFocus = pvObject.setFocus()
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SetFocus&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SetFocus&quot;, Erl)
+ Goto Exit_Function
+Error_Grid:
+ TraceError(TRACEFATAL, ERRFOCUSINGRID, Utils._CalledSub(), 0, 1, Array(pvObject._Name, ocGrid._Name))
+ Goto Exit_Function
+End Function &apos; SetFocus V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _OptionGroup(ByVal pvGroupName As Variant _
+ , ByVal psParentType As String _
+ , poComponent As Object _
+ , poParent As Object _
+ ) As Variant
+&apos; Return either an error or an object of type OPTIONGROUP based on its name
+
+ If IsMissing(pvGroupName) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Set _OptionGroup = Nothing
+
+ If Not Utils._CheckArgument(pvGroupName, 1, vbString) Then Goto Exit_Function
+
+Dim ogGroup As Variant, i As Integer, j As Integer, bFound As Boolean
+Dim vOptionButtons() As Variant, sGroupName As String
+Dim lXY() As Long, iIndex() As Integer &apos; Two indexes X-Y coordinates
+Dim oView As Object, oDatabaseForm As Object, vControls As Variant
+
+Const cstPixels = 10 &apos; Tolerance on coordinates when drawn approximately
+
+ bFound = False
+ Select Case psParentType
+ Case CTLPARENTISFORM
+ &apos;poParent is a forms collection, find the appropriate database form
+ For i = 0 To poParent.Count - 1
+ Set oDatabaseForm = poParent.getByIndex(i)
+ If Not IsNull(oDatabaseForm) Then
+ For j = 0 To oDatabaseForm.GroupCount - 1 &apos; Does a group with the right name exist ?
+ oDatabaseForm.getGroup(j, vOptionButtons, sGroupName)
+ If UCase(sGroupName) = UCase(Utils._Trim(pvGroupName)) Then
+ bFound = True
+ Exit For
+ End If
+ Next j
+ If bFound Then Exit For
+ End If
+ If bFound Then Exit For
+ Next i
+ Case CTLPARENTISSUBFORM
+ &apos;poParent is already a database form
+ Set oDatabaseForm = poParent
+ For j = 0 To oDatabaseForm.GroupCount - 1 &apos; Does a group with the right name exist ?
+ oDatabaseForm.getGroup(j, vOptionButtons, sGroupName)
+ If UCase(sGroupName) = UCase(Utils._Trim(pvGroupName)) Then
+ bFound = True
+ Exit For
+ End If
+ Next j
+ End Select
+
+ If bFound Then
+
+ ogGroup = New Optiongroup
+ ogGroup._This = ogGroup
+ ogGroup._Name = sGroupName
+ ogGroup._ButtonsGroup = vOptionButtons
+ ogGroup._Count = UBound(vOptionButtons) + 1
+ ogGroup._ParentType = psParentType
+ ogGroup._MainForm = oDatabaseForm.Name
+ Set ogGroup._ParentComponent = poComponent
+
+ ReDim lXY(1, ogGroup._Count - 1)
+ ReDim iIndex(ogGroup._Count - 1)
+ For i = 0 To ogGroup._Count - 1 &apos; Find the position of each radiobutton
+ Set oView = poComponent.CurrentController.getControl(ogGroup._ButtonsGroup(i))
+ lXY(0, i) = oView.PosSize.X
+ lXY(1, i) = oView.PosSize.Y
+ Next i
+ For i = 0 To ogGroup._Count - 1 &apos; Sort them on XY coordinates
+ If i = 0 Then
+ iIndex(0) = 0
+ Else
+ iIndex(i) = i
+ For j = i - 1 To 0 Step -1
+ If lXY(1, i) - lXY(1, j) &lt; - cstPixels Or ( Abs(lXY(1, i) - lXY(1, j)) &lt;= cstPixels And lXY(0, i) - lXY(0, j) &lt; - cstPixels ) Then
+ iIndex(i) = iIndex(j)
+ iIndex(j) = iIndex(j) + 1
+ End If
+ Next j
+ End If
+ Next i
+ ogGroup._ButtonsIndex = iIndex()
+
+ Set _OptionGroup = ogGroup
+
+ Else
+
+ Set _OptionGroup = Nothing
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(1, pvGroupName))
+
+ End If
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err,&quot;_OptionGroup&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; _OptionGroup V1.1.0
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Module.xba b/wizards/source/access2base/Module.xba
new file mode 100644
index 000000000..d3095d645
--- /dev/null
+++ b/wizards/source/access2base/Module.xba
@@ -0,0 +1,722 @@
+<?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="Module" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be MODULE
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _Library As Object &apos; com.sun.star.container.XNameAccess
+Private _LibraryName As String
+Private _Storage As String &apos; GLOBAL or DOCUMENT
+Private _Script As String &apos; Full script (string with vbLf&apos;s)
+Private _Lines As Variant &apos; Array of script lines
+Private _CountOfLines As Long
+Private _ProcsParsed As Boolean &apos; To test before use of proc arrays
+Private _ProcNames() As Variant &apos; All procedure names
+Private _ProcDecPositions() As Variant &apos; All procedure declarations
+Private _ProcEndPositions() As Variant &apos; All end procedure statements
+Private _ProcTypes() As Variant &apos; One of the vbext_pk_* constants
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJMODULE
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ Set _Library = Nothing
+ _LibraryName = &quot;&quot;
+ _Storage = &quot;&quot;
+ _Script = &quot;&quot;
+ _Lines = Array()
+ _CountOfLines = 0
+ _ProcsParsed = False
+ _ProcNames = Array()
+ _ProcDecPositions = Array()
+ _ProcEndPositions = Array()
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get CountOfDeclarationLines() As Long
+ CountOfDeclarationLines = _PropertyGet(&quot;CountOfDeclarationLines&quot;)
+End Property &apos; CountOfDeclarationLines (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get CountOfLines() As Long
+ CountOfLines = _PropertyGet(&quot;CountOfLines&quot;)
+End Property &apos; CountOfLines (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Lines(Optional ByVal pvLine As Variant, Optional ByVal pvNumLines As Variant) As String
+&apos; Returns a string containing the contents of a specified line or lines in a standard module or a class module
+
+Const cstThisSub = &quot;Module.Lines&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim sLines As String, lLine As Long
+ sLines = &quot;&quot;
+
+ If IsMissing(pvLine) Or IsMissing(pvNumLines) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvLine, 1, _AddNumeric()) Then GoTo Exit_Function
+ If Not Utils._CheckArgument(pvNumLines, 1, _AddNumeric()) Then GoTo Exit_Function
+
+ lLine = pvLine
+ Do While lLine &lt; _CountOfLines And lLine &lt; pvLine + pvNumLines
+ sLines = sLines &amp; _Lines(lLine - 1) &amp; vbLf
+ lLine = lLine + 1
+ Loop
+ If Len(sLines) &gt; 0 Then sLines = Left(sLines, Len(sLines) - 1)
+
+Exit_Function:
+ Lines = sLines
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Lines
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ProcBodyLine(Optional ByVal pvProc As Variant, Optional ByVal pvProcType As Variant) As Long
+&apos; Return the number of the line at which the body of a specified procedure begins
+
+Const cstThisSub = &quot;Module.ProcBodyLine&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iIndex As Integer
+
+ If IsMissing(pvProc) Or IsMissing(pvProcType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvProc, 1, vbString) Then GoTo Exit_Function
+ If Not Utils._CheckArgument(pvProcType, 2, _AddNumeric()) Then GoTo Exit_Function
+
+ iIndex = _FindProcIndex(pvProc, pvProcType)
+ If iIndex &gt;= 0 Then ProcBodyLine = _LineOfPosition(_ProcDecPositions(iIndex)) Else ProcBodyLine = iIndex
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; ProcBodyline
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ProcCountLines(Optional ByVal pvProc As Variant, Optional ByVal pvProcType As Variant) As Long
+&apos; Return the number of lines in the specified procedure
+
+Const cstThisSub = &quot;Module.ProcCountLines&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim iIndex As Integer, lStart As Long, lEnd As Long
+
+ If IsMissing(pvProc) Or IsMissing(pvProcType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvProc, 1, vbString) Then GoTo Exit_Function
+ If Not Utils._CheckArgument(pvProcType, 2, _AddNumeric()) Then GoTo Exit_Function
+
+ iIndex = _FindProcIndex(pvProc, pvProcType)
+ lStart = ProcStartLine(pvProc, pvProcType)
+ lEnd = _LineOfPosition(_ProcEndPositions(iIndex))
+ ProcCountLines = lEnd - lStart + 1
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; ProcCountLines
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ProcOfLine(Optional ByVal pvLine As Variant, Optional ByRef pvProcType As Variant) As String
+&apos; Return the name and type of the procedure containing line pvLine
+
+Const cstThisSub = &quot;Module.ProcOfLine&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim sProcedure As String, iProc As Integer, lLineDec As Long, lLineEnd As Long
+
+ If IsMissing(pvLine) Or IsMissing(pvProcType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvLine, 1, _AddNumeric()) Then GoTo Exit_Function
+ If Not Utils._CheckArgument(pvProcType, 2, _AddNumeric()) Then GoTo Exit_Function
+
+ If Not _ProcsParsed Then _ParseProcs()
+
+ sProcedure = &quot;&quot;
+ For iProc = 0 To UBound(_ProcNames)
+ lLineEnd = _LineOfPosition(_ProcEndPositions(iProc))
+ If pvLine &lt;= lLineEnd Then
+ lLineDec = _LineOfPosition(_ProcDecPositions(iProc))
+ If pvLine &lt; lLineDec Then &apos; Line between 2 procedures
+ sProcedure = &quot;&quot;
+ Else
+ sProcedure = _ProcNames(iProc)
+ pvProcType = _ProcTypes(iProc)
+ End If
+ Exit For
+ End If
+ Next iProc
+
+Exit_Function:
+ ProcOfLine = sProcedure
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; ProcOfline
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function ProcStartLine(Optional ByVal pvProc As Variant, Optional ByVal pvProcType As Variant) As Long
+&apos; Return the number of the line at which the specified procedure begins
+
+Const cstThisSub = &quot;Module.ProcStartLine&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim lLine As Long, lIndex As Long, sLine As String
+
+ If IsMissing(pvProc) Or IsMissing(pvProcType) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvProc, 1, vbString) Then GoTo Exit_Function
+ If Not Utils._CheckArgument(pvProcType, 2, _AddNumeric()) Then GoTo Exit_Function
+
+ lLine = ProcBodyLine(pvProc, pvProcType)
+ &apos; Search baclIndexward for comment lines
+ lIndex = lLine - 1
+ Do While lIndex &gt; 0
+ sLine = _Trim(_Lines(lIndex - 1))
+ If UCase(Left(sLine, 4)) = &quot;REM &quot; Or Left(sLine, 1) = &quot;&apos;&quot; Then
+ lLine = lIndex
+ Else
+ Exit Do
+ End If
+ lIndex = lIndex - 1
+ Loop
+
+ ProcStartLine = lLine
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; ProcStartLine
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Const cstThisSub = &quot;Module.Properties&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get pType() As String
+ pType = _PropertyGet(&quot;Type&quot;)
+End Property &apos; Type (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Find(Optional ByVal pvTarget As Variant _
+ , Optional ByRef pvStartLine As Variant _
+ , Optional ByRef pvStartColumn As Variant _
+ , Optional ByRef pvEndLine As Variant _
+ , Optional ByRef pvEndColumn As Variant _
+ , Optional ByVal pvWholeWord As Boolean _
+ , Optional ByVal pvMatchCase As Boolean _
+ , Optional ByVal pvPatternSearch As Boolean _
+ ) As Boolean
+&apos; Finds specified text in the module
+&apos; xxLine and xxColumn arguments are mainly to return the position of the found string
+&apos; If they are initialized but nonsense, the function returns False
+
+Const cstThisSub = &quot;Module.Find&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+Dim bFound As Boolean, lPosition As Long, lStartLine As Long, lStartColumn As Long, lStartPosition As Long
+Dim lEndLine As Long, lEndColumn As Long, lEndPosition As Long
+Dim sMatch As String, vOptions As Variant, sPattern As String
+Dim i As Integer, sSpecChar As String
+
+Const cstSpecialCharacters = &quot;\[^$.|?*+()&quot;
+
+ bFound = False
+
+ If IsMissing(pvTarget) Or IsMissing(pvStartLine) Or IsMissing(pvStartColumn) Or IsMissing(pvEndLine) Or IsMissing(pvEndColumn) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvTarget, 1, vbString) Then GoTo Exit_Function
+ If Len(pvTarget) = 0 Then GoTo Exit_Function
+ If Not IsEmpty(pvStartLine) Then
+ If Not Utils._CheckArgument(pvStartLine, 2, _AddNumeric()) Then GoTo Exit_Function
+ End If
+ If Not IsEmpty(pvStartColumn) Then
+ If Not Utils._CheckArgument(pvStartColumn, 3, _AddNumeric()) Then GoTo Exit_Function
+ End If
+ If Not IsEmpty(pvEndLine) Then
+ If Not Utils._CheckArgument(pvEndLine, 4, _AddNumeric()) Then GoTo Exit_Function
+ End If
+ If Not IsEmpty(pvEndColumn) Then
+ If Not Utils._CheckArgument(pvEndColumn, 5, _AddNumeric()) Then GoTo Exit_Function
+ End If
+ If IsMissing(pvWholeWord) Then pvWholeWord = False
+ If Not Utils._CheckArgument(pvWholeWord, 6, vbBoolean) Then GoTo Exit_Function
+ If IsMissing(pvMatchCase) Then pvMatchCase = False
+ If Not Utils._CheckArgument(pvMatchCase, 7, vbBoolean) Then GoTo Exit_Function
+ If IsMissing(pvPatternSearch) Then pvPatternSearch = False
+ If Not Utils._CheckArgument(pvPatternSearch, 8, vbBoolean) Then GoTo Exit_Function
+
+ &apos; Initialize starting values
+ If IsEmpty(pvStartLine) Then lStartLine = 1 Else lStartLine = pvStartLine
+ If lStartLine &lt;= 0 Or lStartLine &gt; UBound(_Lines) + 1 Then GoTo Exit_Function
+ If IsEmpty(pvStartColumn) Then lStartColumn = 1 Else lStartColumn = pvStartColumn
+ If lStartColumn &lt;= 0 Then GoTo Exit_Function
+ If lStartColumn &gt; 1 And lStartColumn &gt; Len(_Lines(lStartLine + 1)) Then GoTo Exit_Function
+ lStartPosition = _PositionOfLine(lStartline) + lStartColumn - 1
+ If IsEmpty(pvEndLine) Then lEndLine = UBound(_Lines) + 1 Else lEndLine = pvEndLine
+ If lEndLine &lt; lStartLine Or lEndLine &gt; UBound(_Lines) + 1 Then GoTo Exit_Function
+ If IsEmpty(pvEndColumn) Then lEndColumn = Len(_Lines(lEndLine - 1)) Else lEndColumn = pvEndColumn
+ If lEndColumn &lt; 0 Then GoTo Exit_Function
+ If lEndColumn = 0 Then lEndColumn = 1
+ If lEndColumn &gt; Len(_Lines(lEndLine - 1)) + 1 Then GoTo Exit_Function
+ lEndPosition = _PositionOfLine(lEndline) + lEndColumn - 1
+
+ If pvMatchCase Then
+ Set vOptions = _A2B_.SearchOptions
+ vOptions.transliterateFlags = 0
+ End If
+
+ &apos; Define pattern to search for
+ sPattern = pvTarget
+ &apos; Protect special characters in regular expressions
+ For i = 1 To Len(cstSpecialCharacters)
+ sSpecChar = Mid(cstSpecialCharacters, i, 1)
+ sPattern = Replace(sPattern, sSpecChar, &quot;\&quot; &amp; sSpecChar)
+ Next i
+ If pvPatternSearch Then sPattern = Replace(Replace(sPattern, &quot;\*&quot;, &quot;.*&quot;), &quot;\?&quot;, &quot;.&quot;)
+ If pvWholeWord Then sPattern = &quot;\b&quot; &amp; sPattern &amp; &quot;\b&quot;
+
+ lPosition = lStartPosition
+ sMatch = Utils._RegexSearch(_Script, sPattern, lPosition)
+ &apos; Re-establish default options for later searches
+ If pvMatchCase Then vOptions.transliterateFlags = com.sun.star.i18n.TransliterationModules.IGNORE_CASE
+
+ &apos; Found within requested bounds ?
+ If sMatch &lt;&gt; &quot;&quot; And lPosition &gt;= lStartPosition And lPosition &lt;= lEndPosition Then
+ pvStartLine = _LineOfPosition(lPosition)
+ pvStartColumn = lPosition - _PositionOfLine(pvStartLine) + 1
+ pvEndLine = _LineOfPosition(lPosition + Len(sMatch) - 1)
+ If pvEndLine &gt; pvStartLine Then
+ pvEndColumn = lPosition + Len(sMatch) - 1 - _PositionOfLine(pvEndLine)
+ Else
+ pvEndColumn = pvStartColumn + Len(sMatch) - 1
+ End If
+ bFound = True
+ End If
+
+Exit_Function:
+ Find = bFound
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Module.Find&quot;, Erl)
+ bFound = False
+ GoTo Exit_Function
+End Function &apos; Find
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+Const cstThisSub = &quot;Module.Properties&quot;
+
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+
+End Function &apos; getProperty
+
+REM --------------------------------Mid(a._Script, iCtl, 25)---------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+Const cstThisSub = &quot;Module.hasProperty&quot;
+
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _BeginStatement(ByVal plStart As Long) As Long
+&apos; Return the position in _Script of the beginning of the current statement as defined by plStart
+
+Dim sProc As String, iProc As Integer, iType As Integer
+Dim lPosition As Long, lPrevious As Long, sFind As String
+
+ sProc = ProcOfLine(_LineOfPosition(plStart), iType)
+ iProc = _FindProcIndex(sProc, iType)
+ If iProc &lt; 0 Then lPosition = 1 Else lPosition = _ProcDecPositions(iProc)
+
+ sFind = &quot;Any&quot;
+ Do While lPosition &lt; plStart And sFind &lt;&gt; &quot;&quot;
+ lPrevious = lPosition
+ sFind = _FindPattern(&quot;%^\w&quot;, lPosition)
+ If sFind = &quot;&quot; Then Exit Do
+ Loop
+
+ _BeginStatement = lPrevious
+
+End Function &apos; _EndStatement
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _EndStatement(ByVal plStart As Long) As Long
+&apos; Return the position in _Script of the end of the current statement as defined by plStart
+&apos; plStart is assumed not to be in the middle of a comment or a string
+
+Dim sMatch As String, lPosition As Long
+ lPosition = plStart
+ sMatch = _FindPattern(&quot;%$&quot;, lPosition)
+ _EndStatement = lPosition
+
+End Function &apos; _EndStatement
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _FindPattern(ByVal psPattern As Variant, Optional ByRef plStart As Long) As String
+&apos; Find first occurrence of any of the patterns in |-delimited string psPattern
+&apos; Special escapes
+&apos; - for word breaks: &quot;%B&quot; (f.i. for searching &quot;END%BFUNCTION&quot;)
+&apos; - for statement start: &quot;%^&quot; (f.i. for searching &quot;%^END%BFUNCTION&quot;). Necessarily first 2 characters of pattern
+&apos; - for statement end: &quot;%$&quot;. Pattern should not contain anything else
+&apos; If quoted string searched, pattern should start and end with a double quote
+&apos; Return &quot;&quot; if none found, otherwise returns the matching string
+&apos; plStart = start position of _Script to search (starts at 1)
+&apos; In output plStart contains the first position of the matching string or is left unchanged
+&apos; To search again the same or another pattern =&gt; plStart = plStart + Len(matching string)
+&apos; Comments and strings are skipped
+
+&apos; Common patterns
+Const cstComment = &quot;(&apos;|\bREM\b)[^\n]*$&quot;
+Const cstString = &quot;&quot;&quot;[^&quot;&quot;\n]*&quot;&quot;&quot;
+Const cstBeginStatement = &quot;(^|:|\bthen\b|\belse\b|\n)[ \t]*&quot;
+Const cstEndStatement = &quot;[ \t]*($|:|\bthen\b|\belse\b|\n)&quot;
+Const cstContinuation = &quot;[ \t]_\n&quot;
+Const cstWordBreak = &quot;\b[ \t]+(_\n[ \t]*)?\b&quot;
+Const cstAlt = &quot;|&quot;
+
+Dim sRegex As String, lStart As Long, bContinue As Boolean, sMatch As String
+Dim bEndStatement As Boolean, bQuote As Boolean
+
+ If psPattern = &quot;%$&quot; Then
+ sRegex = cstEndStatement
+ Else
+ sRegex = psPattern
+ If Left(psPattern, 2) = &quot;%^&quot; Then sRegex = cstBeginStatement &amp; Right(sRegex, Len(sregex) - 2)
+ sregex = Replace(sregex, &quot;%B&quot;, cstWordBreak)
+ End If
+ &apos; Add all to ignore patterns to regex. If pattern = quoted string do not add cstString
+ If Len(psPattern) &gt; 2 And Left(psPattern, 1) = &quot;&quot;&quot;&quot; And Right(psPattern, 1) = &quot;&quot;&quot;&quot; Then
+ bQuote = True
+ sRegex = sRegex &amp; cstAlt &amp; cstComment &amp; cstAlt &amp; cstContinuation
+ Else
+ bQuote = False
+ sRegex = sRegex &amp; cstAlt &amp; cstComment &amp; cstAlt &amp; cstString &amp; cstAlt &amp; cstContinuation
+ End If
+
+ If IsMissing(plStart) Then plStart = 1
+ lStart = plStart
+
+ bContinue = True
+ Do While bContinue
+ bEndStatement = False
+ sMatch = Utils._RegexSearch(_Script, sRegex, lStart)
+ Select Case True
+ Case sMatch = &quot;&quot;
+ bContinue = False
+ Case Left(sMatch, 1) = &quot;&apos;&quot;
+ bEndStatement = True
+ Case Left(sMatch, 1) = &quot;&quot;&quot;&quot;
+ If bQuote Then
+ plStart = lStart
+ bContinue = False
+ End If
+ Case Left(smatch, 1) = &quot;:&quot; Or Left(sMatch, 1) = vbLf
+ If psPattern = &quot;%$&quot; Then
+ bEndStatement = True
+ Else
+ bContinue = False
+ plStart = lStart + 1
+ sMatch = Right(sMatch, Len(sMatch) - 1)
+ End If
+ Case UCase(Left(sMatch, 4)) = &quot;REM &quot; Or UCase(Left(sMatch, 4)) = &quot;REM&quot; &amp; vbTab Or UCase(Left(sMatch, 4)) = &quot;REM&quot; &amp; vbNewLine
+ bEndStatement = True
+ Case UCase(Left(sMatch, 4)) = &quot;THEN&quot; Or UCase(Left(sMatch, 4)) = &quot;ELSE&quot;
+ If psPattern = &quot;%$&quot; Then
+ bEndStatement = True
+ Else
+ bContinue = False
+ plStart = lStart + 4
+ sMatch = Right(sMatch, Len(sMatch) - 4)
+ End If
+ Case sMatch = &quot; _&quot; &amp; vbLf
+ Case Else &apos; Found
+ plStart = lStart
+ bContinue = False
+ End Select
+ If bEndStatement And psPattern = &quot;%$&quot; Then
+ bContinue = False
+ plStart = lStart - 1
+ sMatch = &quot;&quot;
+ End If
+ lStart = lStart + Len(sMatch)
+ Loop
+
+ _FindPattern = sMatch
+
+End Function &apos; _FindPattern
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _FindProcIndex(ByVal psProc As String, ByVal piType As Integer) As Integer
+&apos; Return index of entry in _Procnames corresponding with pvProc
+
+Dim i As Integer, iIndex As Integer
+
+ If Not _ProcsParsed Then _ParseProcs
+
+ iIndex = -1
+ For i = 0 To UBound(_ProcNames)
+ If UCase(psProc) = UCase(_ProcNames(i)) And piType = _ProcTypes(i) Then
+ iIndex = i
+ Exit For
+ End If
+ Next i
+ If iIndex &lt; 0 Then TraceError(TRACEFATAL, ERRPROCEDURENOTFOUND, Utils._CalledSub(), 0, , Array(psProc, _Name))
+
+Exit_Function:
+ _FindProcIndex = iIndex
+ Exit Function
+End Function &apos; _FindProcIndex
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _Initialize()
+
+ _Script = Replace(_Script, vbCr, &quot;&quot;)
+ _Lines = Split(_Script, vbLf)
+ _CountOfLines = UBound(_Lines) + 1
+
+End Sub &apos; _Initialize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _LineOfPosition(ByVal plPosition) As Long
+&apos; Return the line number of a position in _Script
+
+Dim lLine As Long, lLength As Long
+ &apos; Start counting from start or end depending on how close position is
+ If plPosition &lt;= Len(_Script) / 2 Then
+ lLength = 0
+ For lLine = 0 To UBound(_Lines)
+ lLength = lLength + Len(_Lines(lLine)) + 1 &apos; + 1 for line feed
+ If lLength &gt;= plPosition Then
+ _LineOfPosition = lLine + 1
+ Exit Function
+ End If
+ Next lLine
+ Else
+ If Right(_Script, 1) = vbLf Then lLength = Len(_Script) + 1 Else lLength = Len(_Script)
+ For lLine = UBound(_Lines) To 0 Step -1
+ lLength = lLength - Len(_Lines(lLine)) - 1 &apos; - 1 for line feed
+ If lLength &lt;= plPosition Then
+ _LineOfPosition = lLine + 1
+ Exit Function
+ End If
+ Next lLine
+ End If
+
+End Function &apos; _LineOfPosition
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub _ParseProcs()
+&apos; Fills the Proc arrays: name, start and end position
+&apos; Executed at first request needing this processing
+
+Dim lPosition As Long, iProc As Integer, sDecProc As String, sEndProc As String, sNameProc As String, sType As String
+Const cstDeclaration = &quot;%^(private%B|public%B)?\b(property%Bget|property%Blet|property%Bset|function|sub)\b&quot;
+Const cstEnd = &quot;%^end%B(property|function|sub)\b&quot;
+Const cstName = &quot;\w*&quot; &apos;&quot;[A-Za-z_][A-Za-z_0-9]*&quot;
+
+ If _ProcsParsed Then Exit Sub &apos; Do not redo if already done
+ _ProcNames = Array()
+ _ProcDecPositions = Array()
+ _ProcEndPositions = Array()
+ _ProcTypes = Array()
+
+ lPosition = 1
+ iProc = -1
+ sDecProc = &quot;???&quot;
+ Do While sDecProc &lt;&gt; &quot;&quot;
+ &apos; Identify Function/Sub declaration string
+ sDecProc = _FindPattern(cstDeclaration, lPosition)
+ If sDecProc &lt;&gt; &quot;&quot; Then
+ iProc = iProc + 1
+ ReDim Preserve _ProcNames(0 To iProc)
+ ReDim Preserve _ProcDecPositions(0 To iProc)
+ ReDim Preserve _ProcEndPositions(0 To iProc)
+ ReDim Preserve _ProcTypes(0 To iProc)
+ _ProcDecPositions(iProc) = lPosition
+ lPosition = lPosition + Len(sDecProc)
+ &apos; Identify procedure type
+ Select Case True
+ Case InStr(UCase(sDecProc), &quot;FUNCTION&quot;) &gt; 0 : _ProcTypes(iProc) = vbext_pk_Proc
+ Case InStr(UCase(sDecProc), &quot;SUB&quot;) &gt; 0 : _ProcTypes(iProc) = vbext_pk_Proc
+ Case InStr(UCase(sDecProc), &quot;GET&quot;) &gt; 0 : _ProcTypes(iProc) = vbext_pk_Get
+ Case InStr(UCase(sDecProc), &quot;LET&quot;) &gt; 0 : _ProcTypes(iProc) = vbext_pk_Let
+ Case InStr(UCase(sDecProc), &quot;SET&quot;) &gt; 0 : _ProcTypes(iProc) = vbext_pk_Set
+ End Select
+ &apos; Identify name of Function/Sub
+ sNameProc = _FindPattern(cstName, lPosition)
+ If sNameProc = &quot;&quot; Then Exit Do &apos; Should never happen
+ _ProcNames(iProc) = sNameProc
+ lPosition = lPosition + Len(sNameProc)
+ &apos; Identify End statement
+ sEndProc = _FindPattern(cstEnd, lPosition)
+ If sEndProc = &quot;&quot; Then Exit Do &apos; Should never happen
+ _ProcEndPositions(iProc) = lPosition
+ lPosition = lPosition + Len(sEndProc)
+ End If
+ Loop
+
+ _ProcsParsed = True
+
+End Sub
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PositionOfLine(ByVal plLine) As Long
+&apos; Return the position of the first character of the given line in _Script
+
+Dim lLine As Long, lPosition As Long
+ &apos; Start counting from start or end depending on how close line is
+ If plLine &lt;= (UBound(_Lines) + 1) / 2 Then
+ lPosition = 0
+ For lLine = 0 To plLine - 1
+ lPosition = lPosition + 1 &apos; + 1 for line feed
+ If lLine &lt; plLine - 1 Then lPosition = lPosition + Len(_Lines(lLine))
+ Next lLine
+ Else
+ lPosition = Len(_Script) + 2 &apos; Anticipate an ending null-string and a line feed
+ For lLine = UBound(_Lines) To plLine - 1 Step -1
+ lPosition = lPosition - Len(_Lines(lLine)) - 1 &apos; - 1 for line feed
+ Next lLine
+ End If
+
+ _PositionOfLine = lPosition
+
+End Function &apos; _LineOfPosition
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ _PropertiesList = Array(&quot;CountOfDeclarationLines&quot;, &quot;CountOfLines&quot;, &quot;Name&quot;, &quot;ObjectType&quot;, &quot;Type&quot;)
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+Dim cstThisSub As String
+Const cstDot = &quot;.&quot;
+
+Dim sText As String
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ cstThisSub = &quot;Module.get&quot; &amp; psProperty
+ Utils._SetCalledSub(cstThisSub)
+ _PropertyGet = Null
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;CountOfDeclarationLines&quot;)
+ If Not _ProcsParsed Then _ParseProcs()
+ If UBound(_ProcNames) &gt;= 0 Then
+ _PropertyGet = ProcStartLine(_ProcNames(0), _ProcTypes(0)) - 1
+ Else
+ _PropertyGet = _CountOfLines
+ End If
+ Case UCase(&quot;CountOfLines&quot;)
+ _PropertyGet = _CountOfLines
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Storage &amp; cstDot &amp; _LibraryName &amp; cstDot &amp; _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Type&quot;)
+ &apos; Find option statement before any procedure declaration
+ sText = _FindPattern(&quot;%^option%Bclassmodule\b|\bfunction\b|\bsub\b|\bproperty\b&quot;)
+ If UCase(Left(sText, 6)) = &quot;OPTION&quot; Then _PropertyGet = acClassModule Else _PropertyGet = acStandardModule
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Module._PropertyGet&quot;, Erl)
+ _PropertyGet = Null
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/OptionGroup.xba b/wizards/source/access2base/OptionGroup.xba
new file mode 100644
index 000000000..f4b749ef6
--- /dev/null
+++ b/wizards/source/access2base/OptionGroup.xba
@@ -0,0 +1,315 @@
+<?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="OptionGroup" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be FORM
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _ParentType As String
+Private _ParentComponent As Object
+Private _MainForm As String
+Private _DocEntry As Integer
+Private _DbEntry As Integer
+Private _ButtonsGroup() As Variant
+Private _ButtonsIndex() As Variant
+Private _Count As Long
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJOPTIONGROUP
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ _ParentType = &quot;&quot;
+ _ParentComponent = Nothing
+ _DocEntry = -1
+ _DbEntry = -1
+ _ButtonsGroup = Array()
+ _ButtonsIndex = Array()
+ _Count = 0
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Count() As Variant
+ Count = _PropertyGet(&quot;Count&quot;)
+End Property &apos; Count (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Value() As Variant
+ Value = _PropertyGet(&quot;Value&quot;)
+End Property &apos; Value (get)
+
+Property Let Value(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Value&quot;, pvValue)
+End Property &apos; Value (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Controls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Return a Control object with name or index = pvIndex
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;OptionGroup.Controls&quot;)
+
+Dim ocControl As Variant, iArgNr As Integer, i As Integer
+Dim oCounter As Object
+
+ Set ocControl = Nothing
+
+ If IsMissing(pvIndex) Then &apos; No argument, return Collection object
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLCONTROLS
+ Set oCounter._Parent = _This
+ oCounter._Count = _Count
+ Set Controls = oCounter
+ Goto Exit_Function
+ End If
+
+ If _IsLeft(_A2B_.CalledSub, &quot;OptionGroup.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ If Not Utils._CheckArgument(pvIndex, iArgNr, Utils._AddNumeric()) Then Goto Exit_Function
+ If pvIndex &lt; 0 Or pvIndex &gt; _Count - 1 Then Goto Trace_Error_Index
+
+ &apos; Start building the ocControl object
+ &apos; Determine exact name
+ Set ocControl = New Control
+ Set ocControl._This = ocControl
+ Set ocControl._Parent = _This
+ ocControl._ParentType = CTLPARENTISGROUP
+
+ ocControl._Shortcut = &quot;&quot;
+ For i = 0 To _Count - 1
+ If _ButtonsIndex(i) = pvIndex Then
+ Set ocControl.ControlModel = _ButtonsGroup(i)
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG : ocControl._Name = _ButtonsGroup(i).Name
+ Case Else : ocControl._Name = _Name &apos; OptionGroup and individual radio buttons share the same name
+ End Select
+ ocControl._ImplementationName = ocControl.ControlModel.getImplementationName()
+ Exit For
+ End If
+ Next i
+ ocControl._FormComponent = _ParentComponent
+ ocControl._ClassId = acRadioButton
+ Select Case _ParentType
+ Case CTLPARENTISDIALOG : Set ocControl.ControlView = _ParentComponent.getControl(ocControl._Name)
+ Case Else : Set ocControl.ControlView = _ParentComponent.CurrentController.getControl(ocControl.ControlModel)
+ End Select
+
+ ocControl._Initialize()
+ ocControl._DocEntry = _DocEntry
+ ocControl._DbEntry = _DbEntry
+ Set Controls = ocControl
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OptionGroup.Controls&quot;)
+ Exit Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set Controls = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OptionGroup.Controls&quot;, Erl)
+ Set Controls = Nothing
+ GoTo Exit_Function
+End Function &apos; Controls
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;OptionGroup.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;OptionGroup.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;OptionGroup.setProperty&quot;)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(&quot;OptionGroup.setProperty&quot;)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ _PropertiesList = Array(&quot;Count&quot;, &quot;Name&quot;, &quot;ObjectType&quot;, &quot;Value&quot;)
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;OptionGroup.get&quot; &amp; psProperty)
+
+&apos;Execute
+Dim oDatabase As Object, vBookmark As Variant
+Dim iValue As Integer, i As Integer
+ _PropertyGet = EMPTY
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Count&quot;)
+ _PropertyGet = _Count
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Value&quot;)
+ iValue = -1
+ For i = 0 To _Count - 1 &apos; Find the selected RadioButton
+ If _ButtonsGroup(i).State = 1 Then
+ iValue = _ButtonsIndex(i)
+ Exit For
+ End If
+ Next i
+ _PropertyGet = iValue
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OptionGroup.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRINDEXVALUE, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OptionGroup._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+
+ Utils._SetCalledSub(&quot;OptionGroup.set&quot; &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _PropertySet = True
+
+&apos;Execute
+Dim i As Integer, iRadioIndex As Integer, oModel As Object, iArgNr As Integer
+
+ If _IsLeft(_A2B_.CalledSub, &quot;OptionGroup.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Value&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 0 Or pvValue &gt; _Count - 1 Then Goto Trace_Error_Value
+ For i = 0 To _Count - 1
+ _ButtonsGroup(i).State = 0
+ If _ButtonsIndex(i) = pvValue Then iRadioIndex = i
+ Next i
+ _ButtonsGroup(iRadioIndex).State = 1
+ Set oModel = _ButtonsGroup(iRadioIndex)
+ If Utils._hasUNOProperty(oModel, &quot;DataField&quot;) Then
+ If Not IsNull(oModel.Datafield) And Not IsEmpty(oModel.Datafield) Then
+ If oModel.Datafield &lt;&gt; &quot;&quot; And Utils._hasUNOMethod(oModel, &quot;commit&quot;) Then oModel.commit() &apos; f.i. checkboxes have no commit method ?? [PASTIM]
+ End If
+ End If
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;OptionGroup.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;OptionGroup._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/PropertiesGet.xba b/wizards/source/access2base/PropertiesGet.xba
new file mode 100644
index 000000000..59fc8db31
--- /dev/null
+++ b/wizards/source/access2base/PropertiesGet.xba
@@ -0,0 +1,1120 @@
+<?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="PropertiesGet" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getAbsolutePosition(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getAbsolutePosition&quot;)
+ getAbsolutePosition = PropertiesGet._getProperty(pvObject, &quot;AbsolutePosition&quot;)
+End Function &apos; getAbsolutePosition
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getAllowAdditions(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getAllowAdditions&quot;)
+ getAllowAdditions = PropertiesGet._getProperty(pvObject, &quot;AllowAdditions&quot;)
+End Function &apos; getAllowAdditions
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getAllowDeletions(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getAllowDeletions&quot;)
+ getAllowDeletions = PropertiesGet._getProperty(pvObject, &quot;AllowDeletions&quot;)
+End Function &apos; getAllowDeletions
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getAllowEdits(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getAllowEdits&quot;)
+ getAllowEdits = PropertiesGet._getProperty(pvObject, &quot;AllowEdits&quot;)
+End Function &apos; getAllowEdits
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBackColor(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBackColor&quot;)
+ getBackColor = PropertiesGet._getProperty(pvObject, &quot;BackColor&quot;)
+End Function &apos; getBackColor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBeginGroup(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBeginGroup&quot;)
+ getBeginGroup = PropertiesGet._getProperty(pvObject, &quot;BeginGroup&quot;)
+End Function &apos; getBeginGroup
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBOF(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBOF&quot;)
+ getBOF = PropertiesGet._getProperty(pvObject, &quot;BOF&quot;)
+End Function &apos; getBOF
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBookmark(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBookmark&quot;)
+ getBookmark = PropertiesGet._getProperty(pvObject, &quot;Bookmark&quot;)
+End Function &apos; getBookmark
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBookmarkable(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBookmarkable&quot;)
+ getBookmarkable = PropertiesGet._getProperty(pvObject, &quot;Bookmarkable&quot;)
+End Function &apos; getBookmarkable
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBorderColor(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBorderColor&quot;)
+ getBorderColor = PropertiesGet._getProperty(pvObject, &quot;BorderColor&quot;)
+End Function &apos; getBorderColor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBorderStyle(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBorderStyle&quot;)
+ getBorderStyle = PropertiesGet._getProperty(pvObject, &quot;BorderStyle&quot;)
+End Function &apos; getBorderStyle
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getBuiltIn(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getBuiltIn&quot;)
+ getBuiltIn = PropertiesGet._getProperty(pvObject, &quot;BuiltIn&quot;)
+End Function &apos; getBuiltIn
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getButtonLeft(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getButtonLeft&quot;)
+ getButtonLeft = PropertiesGet._getProperty(pvObject, &quot;ButtonLeft&quot;)
+End Function &apos; getButtonLeft
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getButtonMiddle(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getButtonMiddle&quot;)
+ getButtonMiddle = PropertiesGet._getProperty(pvObject, &quot;ButtonMiddle&quot;)
+End Function &apos; getButtonMiddle
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getButtonRight(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getButtonRight&quot;)
+ getButtonRight = PropertiesGet._getProperty(pvObject, &quot;ButtonRight&quot;)
+End Function &apos; getButtonRight
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getCancel(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getCancel&quot;)
+ getCancel = PropertiesGet._getProperty(pvObject, &quot;Cancel&quot;)
+End Function &apos; getCancel
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getCaption(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getCaption&quot;)
+ getCaption = PropertiesGet._getProperty(pvObject, &quot;Caption&quot;)
+End Function &apos; getCaption
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getClickCount(Optional pvObject As Variant) As Long
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getClickCount&quot;)
+ getClickCount = PropertiesGet._getProperty(pvObject, &quot;ClickCount&quot;)
+End Function &apos; getClickCount
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getContextShortcut(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getContextShortcut&quot;)
+ getContextShortcut = PropertiesGet._getProperty(pvObject, &quot;ContextShortcut&quot;)
+End Function &apos; getContextShortcut
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getControlSource(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getControlSource&quot;)
+ getControlSource = PropertiesGet._getProperty(pvObject, &quot;ControlSource&quot;)
+End Function &apos; getControlSource
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getControlTipText(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getControlTipText&quot;)
+ getControlTipText = PropertiesGet._getProperty(pvObject, &quot;ControlTipText&quot;)
+End Function &apos; getControlTipText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getControlType(Optional pvObject As Variant) As Integer
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getControlType&quot;)
+ getControlType = PropertiesGet._getProperty(pvObject, &quot;ControlType&quot;)
+End Function &apos; getControlType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getCount(Optional pvObject As Variant) As Integer
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getCount&quot;)
+ getCount = PropertiesGet._getProperty(pvObject, &quot;Count&quot;)
+End Function &apos; getCount
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getCurrentRecord(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getCurrentRecord&quot;)
+ getCurrentRecord = PropertiesGet._getProperty(pvObject, &quot;CurrentRecord&quot;)
+End Function &apos; getCurrentRecord
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getDataType(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getDataType&quot;)
+ getDataType = PropertiesGet._getProperty(pvObject, &quot;DataType&quot;)
+End Function &apos; getDataType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getDbType(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getDbType&quot;)
+ getDbType = PropertiesGet._getProperty(pvObject, &quot;DbType&quot;)
+End Function &apos; getDbType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getDefault(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getDefault&quot;)
+ getDefault = PropertiesGet._getProperty(pvObject, &quot;Default&quot;)
+End Function &apos; getDefault
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getDefaultValue(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getDefaultValue&quot;)
+ getDefaultValue = PropertiesGet._getProperty(pvObject, &quot;DefaultValue&quot;)
+End Function &apos; getDefaultValue
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getDescription(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getDescription&quot;)
+ getDescription = PropertiesGet._getProperty(pvObject, &quot;Description&quot;)
+End Function &apos; getDescription
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getEditMode(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getEditMode&quot;)
+ getEditMode = PropertiesGet._getProperty(pvObject, &quot;EditMode&quot;)
+End Function &apos; getEditMode
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getEnabled(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getEnabled&quot;)
+ getEnabled = PropertiesGet._getProperty(pvObject, &quot;Enabled&quot;)
+End Function &apos; getEnabled
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getEOF(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getEOF&quot;)
+ getEOF = PropertiesGet._getProperty(pvObject, &quot;EOF&quot;)
+End Function &apos; getEOF
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getEventName(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getEventName&quot;)
+ getEventName = PropertiesGet._getProperty(pvObject, &quot;EventName&quot;)
+End Function &apos; getEventName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getEventType(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getEventType&quot;)
+ getEventType = PropertiesGet._getProperty(pvObject, &quot;EventType&quot;)
+End Function &apos; getEventType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFieldSize(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFieldSize&quot;)
+ getFieldSize = PropertiesGet._getProperty(pvObject, &quot;FieldSize&quot;)
+End Function &apos; getFieldSize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFilter(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFilter&quot;)
+ getFilter = PropertiesGet._getProperty(pvObject, &quot;Filter&quot;)
+End Function &apos; getFilter
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFilterOn(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFilterOn&quot;)
+ getFilterOn = PropertiesGet._getProperty(pvObject, &quot;FilterOn&quot;)
+End Function &apos; getFilterOn
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFocusChangeTemporary(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFocusChangeTemporary&quot;)
+ getFocusChangeTemporary = PropertiesGet._getProperty(pvObject, &quot;FocusChangeTemporary&quot;)
+End Function &apos; getFocusChangeTemporary
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFontBold(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFontBold&quot;)
+ getFontBold = PropertiesGet._getProperty(pvObject, &quot;FontBold&quot;)
+End Function &apos; getFontBold
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFontItalic(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFontItalic&quot;)
+ getFontItalic = PropertiesGet._getProperty(pvObject, &quot;FontItalic&quot;)
+End Function &apos; getFontItalic
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFontName(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFontName&quot;)
+ getFontName = PropertiesGet._getProperty(pvObject, &quot;FontName&quot;)
+End Function &apos; getFontName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFontSize(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFontSize&quot;)
+ getFontSize = PropertiesGet._getProperty(pvObject, &quot;FontSize&quot;)
+End Function &apos; getFontSize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFontUnderline(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFontUnderline&quot;)
+ getFontUnderline = PropertiesGet._getProperty(pvObject, &quot;FontUnderline&quot;)
+End Function &apos; getFontUnderline
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFontWeight(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFontWeight&quot;)
+ getFontWeight = PropertiesGet._getProperty(pvObject, &quot;FontWeight&quot;)
+End Function &apos; getFontWeight
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getForm(Optional pvObject As Variant) As Variant &apos; Return Subform pseudo
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getForm&quot;)
+ getForm = PropertiesGet._getProperty(pvObject, &quot;Form&quot;)
+End Function &apos; getForm
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getFormat(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getFormat&quot;)
+ getFormat = PropertiesGet._getProperty(pvObject, &quot;Format&quot;)
+End Function &apos; getFormat
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getHeight(Optional pvObject As Variant) As Long
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getHeight&quot;)
+ getHeight = PropertiesGet._getProperty(pvObject, &quot;Height&quot;)
+End Function &apos; getHeight
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getForeColor(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getForeColor&quot;)
+ getForeColor = PropertiesGet._getProperty(pvObject, &quot;ForeColor&quot;)
+End Function &apos; getForeColor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getIsLoaded(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getIsLoaded&quot;)
+ getIsLoaded = PropertiesGet._getProperty(pvObject, &quot;IsLoaded&quot;)
+End Function &apos; getIsLoaded
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getItemData(Optional pvObject As Variant, ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getItemData&quot;)
+ If IsMissing(pvIndex) Then
+ getItemData = PropertiesGet._getProperty(pvObject, &quot;ItemData&quot;)
+ Else
+ getItemData = PropertiesGet._getProperty(pvObject, &quot;ItemData&quot;, pvIndex)
+ End If
+End Function &apos; getItemData
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getKeyAlt(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getKeyAlt&quot;)
+ getKeyAlt = PropertiesGet._getProperty(pvObject, &quot;KeyAlt&quot;)
+End Function &apos; getKeyAlt
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getKeyChar(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getKeyChar&quot;)
+ getKeyChar = PropertiesGet._getProperty(pvObject, &quot;KeyChar&quot;)
+End Function &apos; getKeyChar
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getKeyCode(Optional pvObject As Variant) As Integer
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getKeyCode&quot;)
+ getKeyCode = PropertiesGet._getProperty(pvObject, &quot;KeyCode&quot;)
+End Function &apos; getKeyCode
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getKeyCtrl(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getKeyCtrl&quot;)
+ getKeyCtrl = PropertiesGet._getProperty(pvObject, &quot;KeyCtrl&quot;)
+End Function &apos; getKeyCtrl
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getKeyFunction(Optional pvObject As Variant) As Integer
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getKeyFunction&quot;)
+ getKeyFunction = PropertiesGet._getProperty(pvObject, &quot;KeyFunction&quot;)
+End Function &apos; getKeyFunction
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getKeyShift(pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getKeyShift&quot;)
+ getKeyShift = PropertiesGet._getProperty(pvObject, &quot;KeyShift&quot;)
+End Function &apos; getKeyShift
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getLinkChildFields(Optional pvObject As Variant, ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getLinkChildFields&quot;)
+ If IsMissing(pvObject) Then
+ getLinkChildFields = PropertiesGet._getProperty(pvObject, &quot;LinkChildFields&quot;)
+ Else
+ getLinkChildFields = PropertiesGet._getProperty(pvObject, &quot;LinkChildFields&quot;, pvIndex)
+ End If
+End Function &apos; getLinkChildFields
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getLinkMasterFields(Optional pvObject As Variant, ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getLinkMasterFields&quot;)
+ If IsMissing(pvIndex) Then
+ getLinkMasterFields = PropertiesGet._getProperty(pvObject, &quot;LinkMasterFields&quot;)
+ Else
+ getLinkMasterFields = PropertiesGet._getProperty(pvObject, &quot;LinkMasterFields&quot;, pvIndex)
+ End If
+End Function &apos; getLinkMasterFields
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getListCount(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getListCount&quot;)
+ getListCount = PropertiesGet._getProperty(pvObject, &quot;ListCount&quot;)
+End Function &apos; getListCount
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getListIndex(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getListIndex&quot;)
+ getListIndex = PropertiesGet._getProperty(pvObject, &quot;ListIndex&quot;)
+End Function &apos; getListIndex
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getLocked(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getLocked&quot;)
+ getLocked = PropertiesGet._getProperty(pvObject, &quot;Locked&quot;)
+End Function &apos; getLocked
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getMultiSelect(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getMultiSelect&quot;)
+ getMultiSelect = PropertiesGet._getProperty(pvObject, &quot;MultiSelect&quot;)
+End Function &apos; getMultiSelect
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getName(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getName&quot;)
+ getName = PropertiesGet._getProperty(pvObject, &quot;Name&quot;)
+End Function &apos; getName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getObjectType(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getObjectType&quot;)
+ getObjectType = PropertiesGet._getProperty(pvObject, &quot;ObjectType&quot;)
+End Function &apos; getObjectType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getOpenArgs(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getOpenArgs&quot;)
+ getOpenArgs = PropertiesGet._getProperty(pvObject, &quot;OpenArgs&quot;)
+End Function &apos; getOpenArgs
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getOptionGroup(Optional pvObject As Variant, pvName As variant) As Variant
+&apos; Return an OptionGroup object based on its name
+
+ Utils._SetCalledSub(&quot;getOptionGroup&quot;)
+ If IsMissing(pvObject) Or IsMissing(pvName) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If Not Utils._CheckArgument(pvObject, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvName, 2, vbString) Then Goto Exit_Function
+
+ getOptionGroup = pvObject.OptionGroup(pvName)
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;getOptionGroup&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;getOptionGroup&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; getOptionGroup V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getOptionValue(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getOptionValue&quot;)
+ getOptionValue = PropertiesGet._getProperty(pvObject, &quot;OptionValue&quot;)
+End Function &apos; getOptionValue
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getOrderBy(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getOrderBy&quot;)
+ getOrderBy = PropertiesGet._getProperty(pvObject, &quot;OrderBy&quot;)
+End Function &apos; getOrderBy
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getOrderByOn(Optional pvObject As Variant) As Boolean
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getOrderByOn&quot;)
+ getOrderByOn = PropertiesGet._getProperty(pvObject, &quot;OrderByOn&quot;)
+End Function &apos; getOrderByOn
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getPage(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getPage&quot;)
+ getPage = PropertiesGet._getProperty(pvObject, &quot;Page&quot;)
+End Function &apos; getPage V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getParent(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getParent&quot;)
+ getParent = PropertiesGet._getProperty(pvObject, &quot;Parent&quot;)
+End Function &apos; getParent V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional pvItem As Variant, Optional ByVal pvProperty As Variant, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return property value of object pvItem, and psProperty property name
+ Utils._SetCalledSub(&quot;getProperty&quot;)
+ If IsMissing(pvItem) Then Call _TraceArguments()
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ If IsMissing(pvIndex) Then getProperty = PropertiesGet._getProperty(pvItem, pvProperty) Else getProperty = PropertiesGet._getProperty(pvItem, pvProperty, pvIndex)
+ Utils._ResetCalledSub(&quot;getProperty&quot;)
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRecommendation(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRecommendation&quot;)
+ getRecommendation = PropertiesGet._getProperty(pvObject, &quot;Recommendation&quot;)
+End Function &apos; getRecommendation
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRecordCount(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRecordCount&quot;)
+ getRecordCount = PropertiesGet._getProperty(pvObject, &quot;RecordCount&quot;)
+End Function &apos; getRecordCount
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRecordset(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRecordset&quot;)
+ getRecordset = PropertiesGet._getProperty(pvObject, &quot;Recordset&quot;)
+End Function &apos; getRecordset V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRecordSource(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRecordSource&quot;)
+ getRecordSource = PropertiesGet._getProperty(pvObject, &quot;RecordSource&quot;)
+End Function &apos; getRecordSource
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRequired(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRequired&quot;)
+ getRequired = PropertiesGet._getProperty(pvObject, &quot;Required&quot;)
+End Function &apos; getRequired
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRowChangeAction(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRowChangeAction&quot;)
+ getRowChangeAction = PropertiesGet._getProperty(pvObject, &quot;RowChangeAction&quot;)
+End Function &apos; getRowChangeAction
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRowSource(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRowSource&quot;)
+ getRowSource = PropertiesGet._getProperty(pvObject, &quot;RowSource&quot;)
+End Function &apos; getRowSource
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getRowSourceType(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getRowSourceType&quot;)
+ getRowSourceType = PropertiesGet._getProperty(pvObject, &quot;RowSourceType&quot;)
+End Function &apos; getRowSourceType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSelected(Optional pvObject As Variant, ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSelected&quot;)
+ If IsMissing(pvIndex) Then
+ getSelected = PropertiesGet._getProperty(pvObject, &quot;Selected&quot;)
+ Else
+ getSelected = PropertiesGet._getProperty(pvObject, &quot;Selected&quot;, pvIndex)
+ End If
+End Function &apos; getSelected
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSize(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSize&quot;)
+ getSize = PropertiesGet._getProperty(pvObject, &quot;Size&quot;)
+End Function &apos; getSize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSource(Optional pvObject As Variant) As String
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSource&quot;)
+ getSource = PropertiesGet._getProperty(pvObject, &quot;Source&quot;)
+End Function &apos; getSource V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSourceField(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSourceField&quot;)
+ getSourceField = PropertiesGet._getProperty(pvObject, &quot;SourceField&quot;)
+End Function &apos; getSourceField
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSourceTable(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSourceTable&quot;)
+ getSourceTable = PropertiesGet._getProperty(pvObject, &quot;SourceTable&quot;)
+End Function &apos; getSourceTable
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSpecialEffect(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSpecialEffect&quot;)
+ getSpecialEffect = PropertiesGet._getProperty(pvObject, &quot;SpecialEffect&quot;)
+End Function &apos; getSpecialEffect
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSubType(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSubType&quot;)
+ getSubType = PropertiesGet._getProperty(pvObject, &quot;SubType&quot;)
+End Function &apos; getSubType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSubComponentName(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSubComponentName&quot;)
+ getSubComponentName = PropertiesGet._getProperty(pvObject, &quot;SubComponentName&quot;)
+End Function &apos; getSubComponentName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getSubComponentType(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getSubComponentType&quot;)
+ getSubComponentType = PropertiesGet._getProperty(pvObject, &quot;SubComponentType&quot;)
+End Function &apos; getSubComponentType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTabIndex(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTabIndex&quot;)
+ getTabIndex = PropertiesGet._getProperty(pvObject, &quot;TabIndex&quot;)
+End Function &apos; getTabIndex
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTabStop(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTabStop&quot;)
+ getTabStop = PropertiesGet._getProperty(pvObject, &quot;TabStop&quot;)
+End Function &apos; getTabStop
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTag(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTag&quot;)
+ getTag = PropertiesGet._getProperty(pvObject, &quot;Tag&quot;)
+End Function &apos; getTag
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getText(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getText&quot;)
+ getText = PropertiesGet._getProperty(pvObject, &quot;Text&quot;)
+End Function &apos; getText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTextAlign(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTextAlign&quot;)
+ getTextAlign = PropertiesGet._getProperty(pvObject, &quot;TextAlign&quot;)
+End Function &apos; getTextAlign
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTooltipText(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTooltipText&quot;)
+ getTooltipText = PropertiesGet._getProperty(pvObject, &quot;TooltipText&quot;)
+End Function &apos; getTooltipText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTripleState(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTripleState&quot;)
+ getTripleState = PropertiesGet._getProperty(pvObject, &quot;TripleState&quot;)
+End Function &apos; getTripleState
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getTypeName(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getTypeName&quot;)
+ getTypeName = PropertiesGet._getProperty(pvObject, &quot;TypeName&quot;)
+End Function &apos; getTypeName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getVisible(Optional pvObject As Variant) As Variant
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getVisible&quot;)
+ getVisible = PropertiesGet._getProperty(pvObject, &quot;Visible&quot;)
+End Function &apos; getVisible
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getWidth(Optional pvObject As Variant) As Long
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getWdth&quot;)
+ getWidth = PropertiesGet._getProperty(pvObject, &quot;Width&quot;)
+End Function &apos; getWidth
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getXPos(Optional pvObject As Variant) As Long
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getXPos&quot;)
+ getXPos = PropertiesGet._getProperty(pvObject, &quot;XPos&quot;)
+End Function &apos; getXPos
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getYPos(Optional pvObject As Variant) As Long
+ If IsMissing(pvObject) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;getYPos&quot;)
+ getYPos = PropertiesGet._getProperty(pvObject, &quot;YPos&quot;)
+End Function &apos; getYPos
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function _getProperty(pvItem As Variant, ByVal psProperty As String, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return property value of the psProperty property name within object pvItem
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;get&quot; &amp; psProperty)
+ _getProperty = Nothing
+
+&apos;pvItem must be an object and have the requested property
+ If Not Utils._CheckArgument(pvItem, 1, vbObject) Then Goto Exit_Function
+ If Not PropertiesGet._hasProperty(pvItem._Type, pvItem._PropertiesList(), psProperty) Then Goto Trace_Error
+&apos;Check Index argument
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 3, Utils._AddNumeric()) Then Goto Exit_Function
+ End If
+&apos;Execute
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AbsolutePosition&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ _getProperty = pvItem.AbsolutePosition
+ Case UCase(&quot;AllowAdditions&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.AllowAdditions
+ Case UCase(&quot;AllowDeletions&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.AllowDeletions
+ Case UCase(&quot;AllowEdits&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.AllowEdits
+ Case UCase(&quot;BackColor&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.BackColor
+ Case UCase(&quot;BeginGroup&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCOMMANDBARCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.BeginGroup
+ Case UCase(&quot;BOF&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ _getProperty = pvItem.BOF
+ Case UCase(&quot;Bookmark&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJRECORDSET)) Then Goto Exit_Function
+ _getProperty = pvItem.Bookmark
+ Case UCase(&quot;Bookmarkable&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ _getProperty = pvItem.Bookmarkable
+ Case UCase(&quot;BorderColor&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.BorderColor
+ Case UCase(&quot;BorderStyle&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.BorderStyle
+ Case UCase(&quot;BuiltIn&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJCOMMANDBAR, OBJCOMMANDBARCONTROL)) Then Goto Exit_Function
+ _getProperty = pvItem.BuiltIn
+ Case UCase(&quot;ButtonLeft&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.ButtonLeft
+ Case UCase(&quot;ButtonMiddle&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.ButtonMiddle
+ Case UCase(&quot;ButtonRight&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.ButtonRight
+ Case UCase(&quot;Cancel&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Cancel
+ Case UCase(&quot;Caption&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG, OBJCONTROL, OBJCOMMANDBARCONTROL)) Then Goto Exit_Function
+ _getProperty = pvItem.Caption
+ Case UCase(&quot;ClickCount&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.ClickCount
+ Case UCase(&quot;ContextShortcut&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.ContextShortcut
+ Case UCase(&quot;ControlSource&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.ControlSource
+ Case UCase(&quot;ControlTipText&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.ControlTipText
+ Case UCase(&quot;ControlType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.ControlType
+ Case UCase(&quot;Count&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJCOLLECTION,OBJOPTIONGROUP)) Then Goto Exit_Function
+ _getProperty = pvItem.Count
+ Case UCase(&quot;CurrentRecord&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.CurrentRecord
+ Case UCase(&quot;DataType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.DataType
+ Case UCase(&quot;DbType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.DbType
+ Case UCase(&quot;Default&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Default
+ Case UCase(&quot;DefaultValue&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJCONTROL, OBJFIELD)) Then Goto Exit_Function
+ _getProperty = pvItem.DefaultValue
+ Case UCase(&quot;Description&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.Description
+ Case UCase(&quot;EditMode&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ _getProperty = pvItem.EditMode
+ Case UCase(&quot;Enabled&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Enabled
+ Case UCase(&quot;EOF&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ _getProperty = pvItem.EOF
+ Case UCase(&quot;EventName&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.EventName
+ Case UCase(&quot;EventType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.EventType
+ Case UCase(&quot;FieldSize&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.FieldSize
+ Case UCase(&quot;Filter&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM, OBJRECORDSET)) Then Goto Exit_Function
+ _getProperty = pvItem.Filter
+ Case UCase(&quot;FilterOn&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.FilterOn
+ Case UCase(&quot;FocusChangeTemporary&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.FocusChangeTemporary
+ Case UCase(&quot;FontBold&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.FontBold
+ Case UCase(&quot;FontItalic&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.FontItalic
+ Case UCase(&quot;FontName&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.FontName
+ Case UCase(&quot;FontSize&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.FontSize
+ Case UCase(&quot;FontUnderline&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.FontUnderline
+ Case UCase(&quot;FontWeight&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.FontWeight
+ Case UCase(&quot;ForeColor&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.ForeColor
+ Case UCase(&quot;Form&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, CTLSUBFORM) Then Goto Exit_Function
+ _getProperty = pvItem.Form
+ Case UCase(&quot;Format&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Format
+ Case UCase(&quot;Height&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG)) Then Goto Exit_Function
+ _getProperty = pvItem.Height
+ Case UCase(&quot;Index&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCOMMANDBARCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Index
+ Case UCase(&quot;IsLoaded&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFORM) Then Goto Exit_Function
+ _getProperty = pvItem.IsLoaded
+ Case UCase(&quot;ItemData&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ If IsMissing(pvIndex) Then _getProperty = pvItem.ItemData Else _getProperty = pvItem.ItemData(pvIndex)
+ Case UCase(&quot;KeyAlt&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.KeyAlt
+ Case UCase(&quot;KeyChar&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.KeyChar
+ Case UCase(&quot;KeyCode&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.KeyCode
+ Case UCase(&quot;KeyCtrl&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.KeyCtrl
+ Case UCase(&quot;KeyFunction&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.KeyFunction
+ Case UCase(&quot;KeyShift&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.KeyShift
+ Case UCase(&quot;LinkChildFields&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJSUBFORM) Then Goto Exit_Function
+ If IsMissing(pvIndex) Then _getProperty = pvItem.LinkChildFields Else _getProperty = pvItem.LinkChildFields(pvIndex)
+ Case UCase(&quot;LinkMasterFields&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJSUBFORM) Then Goto Exit_Function
+ If IsMissing(pvIndex) Then _getProperty = pvItem.LinkMasterFields Else _getProperty = pvItem.LinkMasterFields(pvIndex)
+ Case UCase(&quot;ListCount&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.ListCount
+ Case UCase(&quot;ListIndex&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.ListIndex
+ Case UCase(&quot;Locked&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ If IsNull(pvItem.Locked) Then Goto Trace_Error
+ _ge ExitProperty = pvItem.Locked
+ Case UCase(&quot;MultiSelect&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.MultiSelect
+ Case UCase(&quot;Name&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, _
+ Array(OBJFORM, OBJSUBFORM, OBJCONTROL, OBJOPTIONGROUP, OBJPROPERTY, OBJDIALOG, OBJTABLEDEF, OBJRECORDSET, OBJFIELD, OBJTEMPVAR, OBJCOMMANDBAR) _
+ ) Then Goto Exit_Function
+ _getProperty = pvItem.Name
+ Case UCase(&quot;ObjectType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJDATABASE, OBJCOLLECTION, OBJFORM, OBJDIALOG, OBJSUBFORM, OBJCONTROL _
+ , OBJEVENT, OBJOPTIONGROUP, OBJPROPERTY, OBJRECORDSET, OBJTABLEDEF, OBJFIELD, OBJTEMPVAR _
+ , OBJCOMMANDBAR, OBJCOMMANDBARCONTROL) _
+ ) Then Goto Exit_Function
+ _getProperty = pvItem.ObjectType
+ Case UCase(&quot;OnAction&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCOMMANDBARCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.OnAction
+ Case UCase(&quot;OpenArgs&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFORM) Then Goto Exit_Function
+ _getProperty = pvItem.OpenArgs
+ Case UCase(&quot;OptionValue&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.OptionValue
+ Case UCase(&quot;OrderBy&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.OrderBy
+ Case UCase(&quot;OrderByOn&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.OrderByOn
+ Case UCase(&quot;Page&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJDIALOG, OBJCONTROL)) Then Goto Exit_Function
+ _getProperty = pvItem.Page
+ Case UCase(&quot;Parent&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJSUBFORM, OBJCONTROL, OBJCOMMANDBARCONTROL)) Then Goto Exit_Function
+ _getProperty = pvItem.Parent
+ Case UCase(&quot;Recommendation&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.Recommendation
+ Case UCase(&quot;RecordCount&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ _getProperty = pvItem.RecordCount
+ Case UCase(&quot;Recordset&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.Recordset
+ Case UCase(&quot;RecordSource&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ _getProperty = pvItem.RecordSource
+ Case UCase(&quot;Required&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Required
+ Case UCase(&quot;RowChangeAction&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.RowChangeAction
+ Case UCase(&quot;RowSource&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.RowSource
+ Case UCase(&quot;RowSourceType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.RowSourceType
+ Case UCase(&quot;Selected&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ If IsMissing(pvIndex) Then _getProperty = pvItem.Selected Else _getProperty = pvItem.Selected(pvIndex)
+ Case UCase(&quot;Size&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.Size
+ Case UCase(&quot;Source&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.Source
+ Case UCase(&quot;SourceTable&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.SourceTable
+ Case UCase(&quot;SourceField&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.SourceField
+ Case UCase(&quot;SpecialEffect&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.SpecialEffect
+ Case UCase(&quot;SubComponentName&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.SubComponentName
+ Case UCase(&quot;SubComponentType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ _getProperty = pvItem.SubComponentType
+ Case UCase(&quot;SubType&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.SubType
+ Case UCase(&quot;TabIndex&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.TabIndex
+ Case UCase(&quot;TabStop&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.TabStop
+ Case UCase(&quot;Tag&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Tag
+ Case UCase(&quot;Text&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.Text
+ Case UCase(&quot;TextAlign&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.TextAlign
+ Case UCase(&quot;TooltipText&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCOMMANDBARCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.TooltipText
+ Case UCase(&quot;TripleState&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ _getProperty = pvItem.TripleState
+ Case UCase(&quot;TypeName&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ _getProperty = pvItem.TypeName
+ Case UCase(&quot;Value&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJCONTROL, OBJOPTIONGROUP, OBJPROPERTY, OBJFIELD, OBJTEMPVAR)) Then Goto Exit_Function
+ _getProperty = pvItem.Value
+ Case UCase(&quot;Visible&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG, OBJCONTROL, OBJCOMMANDBAR, OBJCOMMANDBARCONTROL)) Then Goto Exit_Function
+ _getProperty = pvItem.Visible
+ Case UCase(&quot;Width&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG)) Then Goto Exit_Function
+ _getProperty = pvItem.Width
+ Case UCase(&quot;XPos&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ If IsNull(pvItem.XPos) Then Goto Trace_Error
+ _getProperty = pvItem.XPos
+ Case UCase(&quot;YPos&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJEVENT) Then Goto Exit_Function
+ If IsNull(pvItem.YPos) Then Goto Trace_Error
+ _getProperty = pvItem.YPos
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _getProperty = Nothing
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRINDEXVALUE, Utils._CalledSub(), 0, 1, psProperty)
+ _getProperty = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;_getProperty&quot;, Erl)
+ _getProperty = Nothing
+ GoTo Exit_Function
+End Function &apos; _getProperty V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _hasProperty(ByVal psObject As String, ByVal pvPropertiesList() As Variant, Optional ByVal pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+&apos; Generic hasProperty function called from all class modules
+
+Dim sObject As String
+ sObject = Utils._PCase(psObject)
+ Utils._SetCalledSub(sObject &amp; &quot;.hasProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+
+ _hasProperty = False
+ If Not Utils._CheckArgument(pvProperty, 1, vbString) Then Goto Exit_Function
+
+ _hasProperty = Utils._InList(pvProperty, pvPropertiesList(), False, True)
+
+Exit_Function:
+ Utils._ResetCalledSub(sObject &amp; &quot;.hasProperty&quot;)
+ Exit Function
+End Function &apos; _hasProperty
+
+REM ------------------------------------------------------------------------------------------------------------------------
+Public Function _ParentObject(psShortcut As String) As Object
+&apos; Return parent object from shortcut as a string
+
+Dim sParent As String, vParent() As Variant, iBound As Integer
+ vParent = Split(psShortcut, &quot;!&quot;)
+ iBound = UBound(vParent) - 1
+ ReDim Preserve vParent(0 To iBound) &apos; Remove last element
+ sParent = Join(vParent, &quot;!&quot;)
+
+ &apos;Remove &quot;.Form&quot; if present
+Const cstForm = &quot;.FORM&quot;
+ Set _ParentObject = Nothing
+ If Len(sParent) &gt; Len(cstForm) Then
+ If UCase(Right(sParent, Len(cstForm))) = cstForm Then
+ Set _ParentObject = getValue(sParent)
+ Else
+ Set _ParentObject = getObject(sParent)
+ End If
+ End If
+
+End Function &apos; _ParentObject V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _Properties(ByVal psObject As String _
+ , ByRef pvParent As Object _
+ , ByVal pvPropertiesList() As Variant _
+ , ByVal Optional pvIndex As Variant _
+ ) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+&apos; Generic function called from Properties methods stored in classes
+
+Dim vProperties As Variant, oCounter As Object, opProperty As Object
+Dim iArgNr As Integer, iLen As Integer
+
+ Utils._SetCalledSub(psObject &amp; &quot;.Properties&quot;)
+
+ vProperties = Null
+
+ If IsMissing(pvIndex) Then &apos; Call without index argument prepares a Collection object
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLPROPERTIES
+ Set oCounter._Parent = pvParent
+ oCounter._Count = UBound(pvPropertiesList) + 1
+ Set vProperties = oCounter
+ Else
+ iLen = Len(psObject) + 1
+ If Len(_A2B_.CalledSub) &gt; iLen Then
+ If Left(_A2B_.CalledSub, iLen) = psObject &amp; &quot;.&quot; Then iArgNr = 1 Else iArgNr = 2
+ End If
+ If Not Utils._CheckArgument(pvIndex, iArgNr, Utils._AddNumeric()) Then Goto Exit_Function
+ If pvIndex &lt; LBound(pvPropertiesList) Or pvIndex &gt; UBound(pvPropertiesList) Then
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Else
+ Set opProperty = New Property
+ Set opProperty._This = opProperty
+ opProperty._Name = pvPropertiesList(pvIndex)
+ opProperty._Value = Null
+ Set vProperties = opProperty
+ End If
+ End If
+
+Exit_Function:
+ Set _Properties = vProperties
+ Utils._ResetCalledSub(psObject &amp; &quot;.Properties&quot;)
+ Exit Function
+End Function &apos; _Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _PropertiesList(pvObject As Variant) As Variant
+&apos; Return an array of strings containing the list of valid properties of pvObject
+
+Dim vProperties As Variant
+Dim vPropertiesList As Variant, bPropertiesList() As Boolean, sPropertiesList() As String
+Dim i As Integer, j As Integer, iCount As Integer
+
+ Set vProperties = Nothing
+ Select Case pvObject._Type
+ Case OBJCOLLECTION, OBJPROPERTY, OBJFORM, OBJEVENT, OBJSUBFORM, OBJCONTROL, OBJOPTIONGROUP _
+ , OBJDATABASE, OBJTABLEDEF, OBJQUERYDEF, OBJDIALOG, OBJFIELD, OBJRECORDSET, OBJTEMPVAR _
+ , OBJCOMMANDBAR, OBJCOMMANDBARCONTROL
+ vPropertiesList = pvObject._PropertiesList()
+ Case Else
+ End Select
+
+Exit_Function:
+ Set _PropertiesList = vPropertiesList
+ Exit Function
+End Function &apos; PropertiesList V0.9.0
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/PropertiesSet.xba b/wizards/source/access2base/PropertiesSet.xba
new file mode 100644
index 000000000..100806bea
--- /dev/null
+++ b/wizards/source/access2base/PropertiesSet.xba
@@ -0,0 +1,577 @@
+<?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="PropertiesSet" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setAbsolutePosition(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setAbsolutePosition&quot;)
+ setAbsolutePosition = PropertiesSet._setProperty(pvObject, &quot;AbsolutePosition&quot;, pvValue)
+End Function &apos; setAbsolutePosition
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setAllowAdditions(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setAllowAdditions&quot;)
+ setAllowAdditions = PropertiesSet._setProperty(pvObject, &quot;AllowAdditions&quot;, pvValue)
+End Function &apos; setAllowAdditions
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setAllowDeletions(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setAllowDeletions&quot;)
+ setAllowDeletions = PropertiesSet._setProperty(pvObject, &quot;AllowDeletions&quot;, pvValue)
+End Function &apos; setAllowDeletions
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setAllowEdits(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setAllowEdits&quot;)
+ setAllowEdits = PropertiesSet._setProperty(pvObject, &quot;AllowEdits&quot;, pvValue)
+End Function &apos; setAllowEdits
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setBackColor(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setBackColor&quot;)
+ setBackColor = PropertiesSet._setProperty(pvObject, &quot;BackColor&quot;, pvValue)
+End Function &apos; setBackColor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setBookmark(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setBookmark&quot;)
+ setBookmark = PropertiesSet._setProperty(pvObject, &quot;Bookmark&quot;, pvValue)
+End Function &apos; setBookmark
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setBorderColor (Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setBorderColor&quot;)
+ setBorderColor = PropertiesSet._setProperty(pvObject, &quot;BorderColor&quot;, pvValue)
+End Function &apos; setBorderColor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setBorderStyle(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setBorderStyle&quot;)
+ setBorderStyle = PropertiesSet._setProperty(pvObject, &quot;BorderStyle&quot;, pvValue)
+End Function &apos; setBorderStyle
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setCancel(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setCancel&quot;)
+ setCancel = PropertiesSet._setProperty(pvObject, &quot;Cancel&quot;, pvValue)
+End Function &apos; setCancel
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setCaption(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setCaption&quot;)
+ setCaption = PropertiesSet._setProperty(pvObject, &quot;Caption&quot;, pvValue)
+End Function &apos; setCaption
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setControlTipText(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setControlTipText&quot;)
+ setControlTipText = PropertiesSet._setProperty(pvObject, &quot;ControlTipText&quot;, pvValue)
+End Function &apos; setControlTipText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setCurrentRecord(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setCurrentRecord&quot;)
+ setCurrentRecord = PropertiesSet._setProperty(pvObject, &quot;CurrentRecord&quot;, pvValue)
+End Function &apos; setCurrentRecord
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setDefault(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setDefault&quot;)
+ setDefault = PropertiesSet._setProperty(pvObject, &quot;Default&quot;, pvValue)
+End Function &apos; setDefault
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setDefaultValue(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setDefaultValue&quot;)
+ setDefaultValue = PropertiesSet._setProperty(pvObject, &quot;DefaultValue&quot;, pvValue)
+End Function &apos; setDefaultValue
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setDescription(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setDescription&quot;)
+ setDescription = PropertiesSet._setProperty(pvObject, &quot;Description&quot;, pvValue)
+End Function &apos; setDescription
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setEnabled(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setEnabled&quot;)
+ setEnabled = PropertiesSet._setProperty(pvObject, &quot;Enabled&quot;, pvValue)
+End Function &apos; setEnabled
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFilter(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFilter&quot;)
+ setFilter = PropertiesSet._setProperty(pvObject, &quot;Filter&quot;, pvValue)
+End Function &apos; setFilter
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFilterOn(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFilterOn&quot;)
+ setFilterOn = PropertiesSet._setProperty(pvObject, &quot;FilterOn&quot;, pvValue)
+End Function &apos; setFilterOn
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFontBold(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFontBold&quot;)
+ setFontBold = PropertiesSet._setProperty(pvObject, &quot;FontBold&quot;, pvValue)
+End Function &apos; setFontBold
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFontItalic(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFontItalic&quot;)
+ setFontItalic = PropertiesSet._setProperty(pvObject, &quot;FontItalic&quot;, pvValue)
+End Function &apos; setFontItalic
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFontName(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFontName&quot;)
+ setFontName = PropertiesSet._setProperty(pvObject, &quot;FontName&quot;, pvValue)
+End Function &apos; setFontName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFontSize(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFontSize&quot;)
+ setFontSize = PropertiesSet._setProperty(pvObject, &quot;FontSize&quot;, pvValue)
+End Function &apos; setFontSize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFontUnderline(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFontUnderline&quot;)
+ setFontUnderline = PropertiesSet._setProperty(pvObject, &quot;FontUnderline&quot;, pvValue)
+End Function &apos; setFontUnderline
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setFontWeight(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setFontWeight&quot;)
+ setFontWeight = PropertiesSet._setProperty(pvObject, &quot;FontWeight&quot;, pvValue)
+End Function &apos; setFontWeight
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setForeColor(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setForeColor&quot;)
+ setForeColor = PropertiesSet._setProperty(pvObject, &quot;ForeColor&quot;, pvValue)
+End Function &apos; setForeColor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setHeight(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setHeight&quot;)
+ setHeight = PropertiesSet._setProperty(pvObject, &quot;Height&quot;, pvValue)
+End Function &apos; setHeight
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setListIndex(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setListIndex&quot;)
+ setListIndex = PropertiesSet._setProperty(pvObject, &quot;ListIndex&quot;, pvValue)
+End Function &apos; setListIndex
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setLocked(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setLocked&quot;)
+ setLocked = PropertiesSet._setProperty(pvObject, &quot;Locked&quot;, pvValue)
+End Function &apos; setLocked
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setMultiSelect(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setMultiSelect&quot;)
+ setMultiSelect = PropertiesSet._setProperty(pvObject, &quot;MultiSelect&quot;, pvValue)
+End Function &apos; setMultiSelect
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setOnAction(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setOnAction&quot;)
+ setOnAction = PropertiesSet._setProperty(pvObject, &quot;OnAction&quot;, pvValue)
+End Function &apos; setOnAction
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setOptionValue(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setOptionValue&quot;)
+ setOptionValue = PropertiesSet._setProperty(pvObject, &quot;OptionValue&quot;, pvValue)
+End Function &apos; setOptionValue
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setOrderBy(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setOrderBy&quot;)
+ setOrderBy = PropertiesSet._setProperty(pvObject, &quot;OrderBy&quot;, pvValue)
+End Function &apos; setOrderBy
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setOrderByOn(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setOrderByOn&quot;)
+ setOrderByOn = PropertiesSet._setProperty(pvObject, &quot;OrderByOn&quot;, pvValue)
+End Function &apos; setOrderByOn
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setPage(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setPage&quot;)
+ setPage = PropertiesSet._setProperty(pvObject, &quot;Page&quot;, pvValue)
+End Function &apos; setPage V0.9.1
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(Optional pvItem As Variant, ByVal Optional psProperty As String, ByVal Optional pvValue As Variant, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;setProperty&quot;)
+ If IsMissing(pvItem) Or IsMissing(psProperty) Or IsMissing(pvValue) Or IsEmpty(pvItem) Then Call _TraceArguments()
+ If IsMissing(pvIndex) Then
+ setProperty = PropertiesSet._setProperty(pvItem, psProperty, pvValue)
+ Else
+ setProperty = PropertiesSet._setProperty(pvItem, psProperty, pvValue, pvIndex)
+ End If
+ Utils._ResetCalledSub(&quot;setProperty&quot;)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setRecordSource(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setRecordSource&quot;)
+ setRecordSource = PropertiesSet._setProperty(pvObject, &quot;RecordSource&quot;, pvValue)
+End Function &apos; setRecordSource
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setRequired(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setRequired&quot;)
+ setRequired = PropertiesSet._setProperty(pvObject, &quot;Required&quot;, pvValue)
+End Function &apos; setRequired
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setRowSource(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setRowSource&quot;)
+ setRowSource = PropertiesSet._setProperty(pvObject, &quot;RowSource&quot;, pvValue)
+End Function &apos; setRowSource
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setRowSourceType(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setRowSourceType&quot;)
+ setRowSourceType = PropertiesSet._setProperty(pvObject, &quot;RowSourceType&quot;, pvValue)
+End Function &apos; setRowSourceType
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setSelected(Optional pvObject As Variant, ByVal Optional pvValue As Variant, ByVal Optional pvIndex As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Then Call _TraceArguments(&quot;setSelected&quot;)
+ If IsEmpty(pvObject) Then Call _TraceArguments(&quot;setSelected&quot;)
+ If IsMissing(pvIndex) Then
+ setSelected = PropertiesSet._setProperty(pvObject, &quot;Selected&quot;, pvValue)
+ Else
+ setSelected = PropertiesSet._setProperty(pvObject, &quot;Selected&quot;, pvValue, pvIndex)
+ End If
+End Function &apos; setSelected
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setSelLength(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setSelLength&quot;)
+ setSelLength = PropertiesSet._setProperty(pvObject, &quot;SelLength&quot;, pvValue)
+End Function &apos; setSelLength
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setSelStart(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setSelStart&quot;)
+ setSelStart = PropertiesSet._setProperty(pvObject, &quot;SelStart&quot;, pvValue)
+End Function &apos; setSelStart
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setSelText(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setSelText&quot;)
+ setSelText = PropertiesSet._setProperty(pvObject, &quot;SelText&quot;, pvValue)
+End Function &apos; setSelText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setSpecialEffect(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setSpecialEffect&quot;)
+ setSpecialEffect = PropertiesSet._setProperty(pvObject, &quot;SpecialEffect&quot;, pvValue)
+End Function &apos; setSpecialEffect
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setTabIndex(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setTabIndex&quot;)
+ setTabIndex = PropertiesSet._setProperty(pvObject, &quot;TabIndex&quot;, pvValue)
+End Function &apos; setTabIndex
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setTabStop(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setTabStop&quot;)
+ setTabStop = PropertiesSet._setProperty(pvObject, &quot;TabStop&quot;, pvValue)
+End Function &apos; setTabStop
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setTag(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setTag&quot;)
+ setTag = PropertiesSet._setProperty(pvObject, &quot;Tag&quot;, pvValue)
+End Function &apos; setTag
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setTextAlign(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setTextAlign&quot;)
+ setTextAlign = PropertiesSet._setProperty(pvObject, &quot;TextAlign&quot;, pvValue)
+End Function &apos; setTextAlign
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setTooltipText(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setTooltipText&quot;)
+ setTooltipText = PropertiesSet._setProperty(pvObject, &quot;TooltipText&quot;, pvValue)
+End Function &apos; setTooltipText
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setTripleState(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setTripleState&quot;)
+ setTripleState = PropertiesSet._setProperty(pvObject, &quot;TripleState&quot;, pvValue)
+End Function &apos; setTripleState
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setVisible(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms and controls
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setVisible&quot;)
+ setVisible = PropertiesSet._setProperty(pvObject, &quot;Visible&quot;, pvValue)
+End Function &apos; setVisible
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setWidth(Optional pvObject As Variant, ByVal Optional pvValue As Variant) As Boolean
+&apos; Only for open forms
+ If IsMissing(pvObject) Or IsMissing(pvValue) Or IsEmpty(pvObject) Then Call _TraceArguments(&quot;setWidth&quot;)
+ setWidth = PropertiesSet._setProperty(pvObject, &quot;Width&quot;, pvValue)
+End Function &apos; setWidth
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private Function _CheckProperty(pvObject As Object, ByVal psProperty As String) As Boolean
+&apos; Return False if psProperty not within the PropertyValues set of pvItem
+
+Dim i As Integer, oPropertyValues As Variant, oProperty As Variant
+ oPropertyValues = pvObject.PropertyValues
+
+ For i = LBound(oPropertyValues) To UBound(oPropertyValues)
+ oProperty = oPropertyValues(i)
+ If UCase(oProperty.Name) = UCase(psProperty) Then
+ _CheckProperty = True
+ Exit Function
+ End If
+ Next i
+
+ _CheckProperty = False
+ Exit Function
+
+End Function &apos; CheckProperty V0.7.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _setProperty(pvItem As Variant, ByVal psProperty As String, ByVal pvValue As Variant, ByVal Optional pvIndex As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;set&quot; &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+&apos;pvItem must be an object and have the requested property
+ If Not Utils._CheckArgument(pvItem, 1, vbObject) Then Goto Exit_Function
+&apos;Check Index argument
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 4, Utils._AddNumeric()) Then Goto Exit_Function
+ End If
+&apos;Execute
+Dim iArgNr As Integer, lFormat As Long
+Dim i As Integer, iCount As Integer, iSelectedItems() As Integer, bListboxBound As Boolean
+Dim odbDatabase As Object, vNames As Variant, bFound As Boolean, sName As String, oModel As Object
+Dim ocButton As Variant, iRadioIndex As Integer
+ _setProperty = True
+ If _A2B_.CalledSub = &quot;setProperty&quot; Then iArgNr = 3 Else iArgNr = 2
+ If Not PropertiesGet._hasProperty(pvItem._Type, pvItem._PropertiesList(), psProperty) Then Goto Trace_Error_Control
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AbsolutePosition&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJRECORDSET) Then Goto Exit_Function
+ pvItem.AbsolutePosition = pvValue
+ Case UCase(&quot;AllowAdditions&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.AllowAdditions = pvValue
+ Case UCase(&quot;AllowDeletions&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.AllowDeletions = pvValue
+ Case UCase(&quot;AllowEdits&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.AllowEdits = pvValue
+ Case UCase(&quot;BackColor&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.BackColor = pvValue
+ Case UCase(&quot;Bookmark&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJRECORDSET)) Then Goto Exit_Function
+ pvItem.Bookmark = pvValue
+ Case UCase(&quot;BorderColor&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.BorderColor = pvValue
+ Case UCase(&quot;BorderStyle&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.BorderColor = pvValue
+ Case UCase(&quot;Cancel&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.Cancel = pvValue
+ Case UCase(&quot;Caption&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG, OBJCONTROL)) Then Goto Exit_Function
+ pvItem.Caption = pvValue
+ Case UCase(&quot;ControlTipText&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.ControlTipText = pvValue
+ Case UCase(&quot;CurrentRecord&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.CurrentRecord = pvValue
+ Case UCase(&quot;Default&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.Default = pvValue
+ Case UCase(&quot;DefaultValue&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJCONTROL, OBJFIELD)) Then Goto Exit_Function
+ pvItem.DefaultValue = pvValue
+ Case UCase(&quot;Description&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJFIELD) Then Goto Exit_Function
+ pvItem.DefaultValue = pvValue
+ Case UCase(&quot;Enabled&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.Enabled = pvValue
+ Case UCase(&quot;Filter&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM, OBJRECORDSET)) Then Goto Exit_Function
+ pvItem.Filter = pvValue
+ Case UCase(&quot;FilterOn&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.FilterOn = pvValue
+ Case UCase(&quot;FontBold&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.FontBold = pvValue
+ Case UCase(&quot;FontItalic&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.FontItalic = pvValue
+ Case UCase(&quot;FontName&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.FontName = pvValue
+ Case UCase(&quot;FontSize&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.FontSize = pvValue
+ Case UCase(&quot;FontUnderline&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.FontUnderline = pvValue
+ Case UCase(&quot;FontWeight&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.FontWeight = pvValue
+ Case UCase(&quot;ForeColor&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.ForeColor = pvValue
+ Case UCase(&quot;Height&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG)) Then Goto Exit_Function
+ pvItem.Height = pvValue
+ Case UCase(&quot;ListIndex&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.ListIndex = pvValue
+ Case UCase(&quot;Locked&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.Locked = pvValue
+ Case UCase(&quot;MultiSelect&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.MultiSelect = pvValue
+ Case UCase(&quot;OnAction&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCOMMANDBARCONTROL) Then Goto Exit_Function
+ pvItem.OnAction = pvValue
+ Case UCase(&quot;OptionValue&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.OptionValue = pvValue
+ Case UCase(&quot;OrderBy&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.OrderBy = pvValue
+ Case UCase(&quot;OrderByOn&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.OrderByOn = pvValue
+ Case UCase(&quot;Page&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJDIALOG, OBJCONTROL)) Then Goto Exit_Function
+ pvItem.Page = pvValue
+ Case UCase(&quot;RecordSource&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJSUBFORM)) Then Goto Exit_Function
+ pvItem.RecordSource = pvValue
+ Case UCase(&quot;Required&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.Required = pvValue
+ Case UCase(&quot;RowSource&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.RowSource = pvValue
+ Case UCase(&quot;RowSourceType&quot;) &apos; Refresh done when RowSource changes, not RowSourceType
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.RowSourceType = pvValue
+ Case UCase(&quot;Selected&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ If IsMissing(pvIndex) Then pvItem.Selected = pvValue Else pvItem.SelectedI(pvValue, pvIndex)
+ Case UCase(&quot;SelLength&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.SelLength = pvValue
+ Case UCase(&quot;SelStart&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.SelStart = pvValue
+ Case UCase(&quot;SelText&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.SelText = pvValue
+ Case UCase(&quot;SpecialEffect&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.SpecialEffect = pvValue
+ Case UCase(&quot;TabIndex&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.TabIndex = pvValue
+ Case UCase(&quot;TabStop&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.TabStop = pvValue
+ Case UCase(&quot;Tag&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.Tag = pvValue
+ Case UCase(&quot;TextAlign&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.TextAlign = pvValue
+ Case UCase(&quot;TooltipText&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCOMMANDBARCONTROL) Then Goto Exit_Function
+ pvItem.TooltipText = pvValue
+ Case UCase(&quot;TripleState&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, OBJCONTROL) Then Goto Exit_Function
+ pvItem.TripleState = pvValue
+ Case UCase(&quot;Value&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJCONTROL, OBJOPTIONGROUP, OBJFIELD, OBJTEMPVAR)) Then Goto Exit_Function
+ pvItem.Value = pvValue
+ Case UCase(&quot;Visible&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG, OBJCONTROL, OBJCOMMANDBAR, OBJCOMMANDBARCONTROL)) Then Goto Exit_Function
+ pvItem.Visible = pvValue
+ Case UCase(&quot;Width&quot;)
+ If Not Utils._CheckArgument(pvItem, 1, Array(OBJFORM, OBJDIALOG)) Then Goto Exit_Function
+ pvItem.Width = pvValue
+ Case Else
+ Goto Trace_Error_Control
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error_Form:
+ TraceError(TRACEFATAL, ERRFORMNOTFOUND, Utils._CalledSub(), 0, 1, pvItem._Name)
+ _setProperty = False
+ Goto Exit_Function
+Trace_Error_Control:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _setProperty = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _setProperty = False
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRINDEXVALUE, Utils._CalledSub(), 0, 1, psProperty)
+ _setProperty = Nothing
+ Goto Exit_Function
+Trace_Error_Array:
+ TraceError(TRACEFATAL, ERRPROPERTYNOTARRAY, Utils._CalledSub(), 0, 1, iArgNr)
+ _setProperty = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;_setProperty&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; _setProperty V0.9.1
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Property.xba b/wizards/source/access2base/Property.xba
new file mode 100644
index 000000000..8b881c284
--- /dev/null
+++ b/wizards/source/access2base/Property.xba
@@ -0,0 +1,152 @@
+<?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="Property" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be PROPERTY
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _Value As Variant
+Private _ParentDatabase As Object
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJPROPERTY
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ _Value = Null
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Value() As Variant
+ Value = _PropertyGet(&quot;Value&quot;)
+End Property &apos; Value (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;Property.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;Property.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+ _PropertiesList = Array(&quot;Name&quot;, &quot;ObjectType&quot;, &quot;Value&quot;)
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;Property.get&quot; &amp; psProperty)
+ _PropertyGet = Nothing
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Value&quot;)
+ _PropertyGet = _Value
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;Property.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Property._PropertyGet&quot;, Erl)
+ _PropertyGet = Nothing
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Python.xba b/wizards/source/access2base/Python.xba
new file mode 100644
index 000000000..94a442159
--- /dev/null
+++ b/wizards/source/access2base/Python.xba
@@ -0,0 +1,613 @@
+<?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="Python" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub DebugPrint(ParamArray pvArgs() As Variant)
+
+&apos;Print arguments unconditionally in console
+&apos;Arguments are separated by a TAB (simulated by spaces)
+&apos;Some pvArgs might be missing: a TAB is still generated
+
+Dim vVarTypes() As Variant, i As Integer
+Const cstTab = 5
+ On Local Error Goto Exit_Sub &apos; Never interrupt processing
+ Utils._SetCalledSub(&quot;DebugPrint&quot;)
+ vVarTypes = Utils._AddNumeric(Array(vbEmpty, vbNull, vbDate, vbString, vbBoolean, vbObject, vbVariant, vbByte, vbArray + vbByte))
+
+ If UBound(pvArgs) &gt;= 0 Then
+ For i = 0 To UBound(pvArgs)
+ If Not Utils._CheckArgument(pvArgs(i), i + 1, vVarTypes(), , False) Then pvArgs(i) = &quot;[TYPE?]&quot;
+ Next i
+ End If
+
+Dim sOutput As String, sArg As String
+ sOutput = &quot;&quot;
+ For i = 0 To UBound(pvArgs)
+ sArg = Replace(Utils._CStr(pvArgs(i), _A2B_.DebugPrintShort), &quot;\;&quot;, &quot;;&quot;)
+ &apos; Add argument to output
+ If i = 0 Then
+ sOutput = sArg
+ Else
+ sOutput = sOutput &amp; Space(cstTab - (Len(sOutput) Mod cstTab)) &amp; sArg
+ End If
+ Next i
+
+ TraceLog(TRACEANY, sOutput, False)
+
+Exit_Sub:
+ Utils._ResetCalledSub(&quot;DebugPrint&quot;)
+ Exit Sub
+End Sub &apos; DebugPrint V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PYTHON WRAPPERS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PythonEventsWrapper(Optional poEvent As Variant) As Variant
+&apos; Python wrapper when Application.Events() method is invoked
+&apos; The ParamArray mechanism empties UNO objects when they are member of the arguments list
+&apos; As a workaround, the Application.Events function is executed directly
+
+ If _ErrorHandler() Then On Local Error GoTo Exit_Function &apos; Do never interrupt
+ PythonEventsWrapper = Null
+
+Dim vReturn As Variant, vArray As Variant
+Const cstObject = 1
+
+ vReturn = Application.Events(poEvent)
+ vArray = Array(cstObject, _A2B_.AddPython(vReturn), vReturn._Type)
+
+ PythonEventsWrapper = vArray
+
+Exit_Function:
+ Exit Function
+End Function &apos; PythonEventsWrapper V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PythonWrapper(ByVal pvCallType As Variant _
+ , ByVal pvObject As Variant _
+ , ByVal pvScript As Variant _
+ , ParamArray pvArgs() As Variant _
+ ) As Variant
+&apos; Called from Python to apply
+&apos; - on object with entry pvObject in PythonCache
+&apos; Conventionally: -1 = Application
+&apos; -2 = DoCmd
+&apos; - a script pvScript which type is described by pvCallType
+&apos; - with arguments pvArgs(0)... (max. 8 for object methods)
+&apos; The value returned by the method/property is encapsulated in an array
+&apos; [0] =&gt; 0 = scalar or array returned by the method
+&apos; =&gt; 1 = basic object returned by the method
+&apos; =&gt; 2 = a null value
+&apos; [1] =&gt; the object reference or the returned value (complemented with arguments passed by reference, if any) or Null
+&apos; [2] =&gt; the object type or Null
+&apos; [3] =&gt; the object name, if any
+&apos; or, when pvCallType == vbUNO, as the UNO object returned by the property
+
+Dim vReturn As Variant, vArray As Variant
+Dim vObject As Variant, sScript As String, sModule As String
+Dim i As Integer, iNbArgs As Integer, vArg As Variant, vArgs() As Variant
+
+Const cstApplication = -1, cstDoCmd = -2
+Const cstScalar = 0, cstObject = 1, cstNull = 2, cstUNO = 3
+
+&apos;Conventional special values
+Const cstNoArgs = &quot;+++NOARGS+++&quot;, cstSymEmpty = &quot;+++EMPTY+++&quot;, cstSymNull = &quot;+++NULL+++&quot;, cstSymMissing = &quot;+++MISSING+++&quot;
+
+&apos;https://support.office.com/en-us/article/CallByName-fonction-49ce9475-c315-4f13-8d35-e98cfe98729a
+&apos;Determines the pvCallType
+Const vbGet = 2, vbLet = 4, vbMethod = 1, vbSet = 8, vbUNO = 16
+
+ If _ErrorHandler() Then On Local Error GoTo Error_Function
+ PythonWrapper = Null
+
+ &apos;Reinterpret arguments one by one into vArgs, examine iso-dates and conventional NoArgs/Empty/Null values
+ iNbArgs = -1
+ vArgs = Array()
+ If UBound(pvArgs) &gt;= 0 Then
+ For i = 0 To UBound(pvArgs)
+ vArg = pvArgs(i)
+ If i = 0 And VarType(vArg) = vbString Then
+ If vArg = cstNoArgs Then Exit For
+ End If
+ If VarType(vArg) = vbString Then
+ If vArg = cstSymEmpty Then
+ vArg = Empty
+ ElseIf vArg = cstSymNull Then
+ vArg = Null
+ ElseIf vArg = cstSymMissing Then
+ Exit For &apos; Next arguments must be missing also
+ Else
+ vArg = _CDate(vArg)
+ End If
+ End If
+ iNbArgs = iNbArgs + 1
+ ReDim Preserve vArgs(iNbArgs)
+ vArgs(iNbArgs) = vArg
+ Next i
+ End If
+
+ &apos;Check pvObject
+ Select Case pvObject &apos; Always numeric
+ Case cstApplication
+ sModule = &quot;Application&quot;
+ Select Case pvScript
+ Case &quot;AllDialogs&quot; : If iNbArgs &lt; 0 Then vReturn = Application.AllDialogs() Else vReturn = Application.AllDialogs(vArgs(0))
+ Case &quot;AllForms&quot; : If iNbArgs &lt; 0 Then vReturn = Application.AllForms() Else vReturn = Application.AllForms(vArgs(0))
+ Case &quot;AllModules&quot; : If iNbArgs &lt; 0 Then vReturn = Application.AllModules() Else vReturn = Application.AllModules(vArgs(0))
+ Case &quot;CloseConnection&quot;
+ vReturn = Application.CloseConnection()
+ Case &quot;CommandBars&quot; : If iNbArgs &lt; 0 Then vReturn = Application.CommandBars() Else vReturn = Application.CommandBars(vArgs(0))
+ Case &quot;CurrentDb&quot; : vReturn = Application.CurrentDb()
+ Case &quot;CurrentUser&quot; : vReturn = Application.CurrentUser()
+ Case &quot;DAvg&quot; : vReturn = Application.DAvg(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DCount&quot; : vReturn = Application.DCount(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DLookup&quot; : vReturn = Application.DLookup(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;DMax&quot; : vReturn = Application.DMax(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DMin&quot; : vReturn = Application.DMin(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DStDev&quot; : vReturn = Application.DStDev(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DStDevP&quot; : vReturn = Application.DStDevP(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DSum&quot; : vReturn = Application.DSum(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DVar&quot; : vReturn = Application.DVar(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;DVarP&quot; : vReturn = Application.DVarP(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;Forms&quot; : If iNbArgs &lt; 0 Then vReturn = Application.Forms() Else vReturn = Application.Forms(vArgs(0))
+ Case &quot;getObject&quot; : vReturn = Application.getObject(vArgs(0))
+ Case &quot;getValue&quot; : vReturn = Application.getValue(vArgs(0))
+ Case &quot;HtmlEncode&quot; : vReturn = Application.HtmlEncode(vArgs(0), vArgs(1))
+ Case &quot;OpenDatabase&quot; : vReturn = Application.OpenDatabase(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;ProductCode&quot; : vReturn = Application.ProductCode()
+ Case &quot;setValue&quot; : vReturn = Application.setValue(vArgs(0), vArgs(1))
+ Case &quot;SysCmd&quot; : vReturn = Application.SysCmd(vArgs(0), vArgs(1), vARgs(2))
+ Case &quot;TempVars&quot; : If iNbArgs &lt; 0 Then vReturn = Application.TempVars() Else vReturn = Application.TempVars(vArgs(0))
+ Case &quot;Version&quot; : vReturn = Application.Version()
+ Case Else
+ GoTo Error_Proc
+ End Select
+ Case cstDoCmd
+ sModule = &quot;DoCmd&quot;
+ Select Case pvScript
+ Case &quot;ApplyFilter&quot; : vReturn = DoCmd.ApplyFilter(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;Close&quot; : vReturn = DoCmd.mClose(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;CopyObject&quot; : vReturn = DoCmd.CopyObject(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;FindNext&quot; : vReturn = DoCmd.FindNext()
+ Case &quot;FindRecord&quot; : vReturn = DoCmd.FindRecord(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
+ Case &quot;GetHiddenAttribute&quot;
+ vReturn = DoCmd.GetHiddenAttribute(vArgs(0), vArgs(1))
+ Case &quot;GoToControl&quot; : vReturn = DoCmd.GoToControl(vArgs(0))
+ Case &quot;GoToRecord&quot; : vReturn = DoCmd.GoToRecord(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;Maximize&quot; : vReturn = DoCmd.Maximize()
+ Case &quot;Minimize&quot; : vReturn = DoCmd.Minimize()
+ Case &quot;MoveSize&quot; : vReturn = DoCmd.MoveSize(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;OpenForm&quot; : vReturn = DoCmd.OpenForm(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
+ Case &quot;OpenQuery&quot; : vReturn = DoCmd.OpenQuery(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;OpenReport&quot; : vReturn = DoCmd.OpenReport(vArgs(0), vArgs(1))
+ Case &quot;OpenSQL&quot; : vReturn = DoCmd.OpenSQL(vArgs(0), vArgs(1))
+ Case &quot;OpenTable&quot; : vReturn = DoCmd.OpenTable(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;OutputTo&quot; : vReturn = DoCmd.OutputTo(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
+ Case &quot;Quit&quot; : _A2B_.CalledSub = &quot;Quit&quot; : GoTo Error_Action
+ Case &quot;RunApp&quot; : vReturn = DoCmd.RunApp(vArgs(0))
+ Case &quot;RunCommand&quot; : vReturn = DoCmd.RunCommand(vArgs(0))
+ Case &quot;RunSQL&quot; : vReturn = DoCmd.RunSQL(vArgs(0), vArgs(1))
+ Case &quot;SelectObject&quot; : vReturn = DoCmd.SelectObject(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;SendObject&quot; : vReturn = DoCmd.SendObject(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7), vArgs(8), vArgs(9))
+ Case &quot;SetHiddenAttribute&quot;
+ vReturn = DoCmd.SetHiddenAttribute(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;SetOrderBy&quot; : vReturn = DoCmd.SetOrderBy(vArgs(0), vArgs(1))
+ Case &quot;ShowAllRecords&quot;
+ vReturn = DoCmd.ShowAllRecords()
+ Case Else
+ GoTo Error_Proc
+ End Select
+ Case Else
+ &apos; Locate targeted object
+ If pvObject &gt; UBound(_A2B_.PythonCache) Or pvObject &lt; 0 Then GoTo Error_Object
+ Set vObject = _A2B_.PythonCache(pvObject)
+ If IsNull(vObject) Then
+ If pvScript = &quot;Dispose&quot; Then GoTo Exit_Function Else GoTo Error_Object
+ End If
+ &apos; Preprocessing
+ sScript = pvScript
+ sModule = vObject._Type
+ Select Case sScript
+ Case &quot;Add&quot;
+ If vObject._Type = &quot;COLLECTION&quot; And vObject._CollType = COLLTABLEDEFS Then vArgs = Array(_A2B_.PythonCache(vArgs(0)))
+ Case &quot;Close&quot;
+ sSCript = &quot;mClose&quot;
+ Case &quot;Type&quot;
+ sScript = &quot;pType&quot;
+ Case Else
+ End Select
+ &apos; Execute method
+ Select Case UBound(vArgs) &apos; Dirty but ... CallByName does not support an array of arguments or return values
+ Case -1
+ If pvCallType = vbUNO Then
+ With vObject
+ Select Case sScript &apos; List all properties that should be called directly (UNO)
+ Case &quot;BoundField&quot; : vReturn = .BoundField
+ Case &quot;Column&quot; : vReturn = .Column
+ Case &quot;Connection&quot; : vReturn = .Connection
+ case &quot;ContainerWindow&quot; : vReturn = .ContainerWindow
+ Case &quot;ControlModel&quot; : vReturn = .ControlModel
+ Case &quot;ControlView&quot; : vReturn = .ControlView
+ Case &quot;DatabaseForm&quot; : vReturn = .DatabaseForm
+ Case &quot;Document&quot; : vReturn = .Document
+ Case &quot;FormsCollection&quot; : vReturn = .FormsCollection
+ Case &quot;LabelControl&quot; : vReturn = .LabelControl
+ Case &quot;MetaData&quot; : vReturn = .MetaData
+ Case &quot;ParentComponent&quot; : vReturn = .ParentComponent
+ Case &quot;Query&quot; : vReturn = .Query
+ Case &quot;RowSet&quot; : vReturn = .RowSet
+ Case &quot;Table&quot; : vReturn = .Table
+ Case &quot;UnoDialog&quot; : vReturn = .UnoDialog
+ Case Else
+ End Select
+ End With
+ ElseIf sScript = &quot;ItemData&quot; Then &apos; List all properties that should be called directly (arrays not supported by CallByName)
+ vReturn = vObject.ItemData
+ ElseIf sScript = &quot;LinkChildFields&quot; Then
+ vReturn = vObject.LinkChildFields
+ ElseIf sScript = &quot;LinkMasterFields&quot; Then
+ vReturn = vObject.LinkMasterFields
+ ElseIf sScript = &quot;OpenArgs&quot; Then
+ vReturn = vObject.OpenArgs
+ ElseIf sScript = &quot;Selected&quot; Then
+ vReturn = vObject.Selected
+ ElseIf sScript = &quot;Value&quot; Then
+ vReturn = vObject.Value
+ Else
+ vReturn = CallByName(vObject, sScript, pvCallType)
+ End If
+ Case 0
+ Select Case sScript
+ Case &quot;AppendChunk&quot; &apos; Arg is a vector, not supported by CallByName
+ vReturn = vObject.GetChunk(vArgs(0), vArgs(1))
+ Case &quot;GetRows&quot; &apos; Returns an array, not supported by CallByName
+ vReturn = vObject.GetRows(vArgs(0), True) &apos; Force iso dates
+ Case Else
+ vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0))
+ End Select
+ Case 1
+ Select Case sScript
+ Case &quot;GetChunk&quot; &apos; Returns a vector, not supported by CallByName
+ vReturn = vObject.GetChunk(vArgs(0), vArgs(1))
+ Case Else
+ vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1))
+ End Select
+ Case 2 : vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1), vArgs(2))
+ Case 3 : vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case 4 : vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
+ Case 5 : vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
+ Case 6 : vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
+ Case 7 : vReturn = CallByName(vObject, sScript, pvCallType, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
+ End Select
+ &apos; Postprocessing
+ Select Case pvScript
+ Case &quot;Close&quot;, &quot;Dispose&quot;, &quot;Terminate&quot;
+ Set _A2B_.PythonCache(pvObject) = Nothing
+ Case &quot;Move&quot;, &quot;MoveFirst&quot;, &quot;MoveLast&quot;, &quot;MoveNext&quot;, &quot;MovePrevious&quot; &apos; Pass the new BOF, EOF values (binary format)
+ If vObject._Type = &quot;RECORDSET&quot; Then
+ vReturn = (Iif(vObject.BOF, 1, 0) * 2 + Iif(vObject.EOF, 1, 0)) * Iif(vReturn, 1, -1)
+ End If
+ Case &quot;Find&quot; &apos; Store in array the arguments passed by reference
+ If vObject._Type = &quot;MODULE&quot; And vReturn = True Then
+ vReturn = Array(vReturn, vArgs(1), vArgs(2), vArgs(3), vArgs(4))
+ End If
+ Case &quot;ProcOfLine&quot; &apos; Store in array the arguments passed by reference
+ vReturn = Array(vReturn, vArgs(1))
+ Case Else
+ End Select
+ End Select
+
+ &apos; Structure the returned array
+ If pvCallType = vbUNO Then
+ vArray = vReturn
+ Else
+ If IsNull(vReturn) Then
+ vArray = Array(cstNull, Null, Null)
+ ElseIf IsObject(vReturn) Then
+ Select Case vReturn._Type
+ Case &quot;COLLECTION&quot;, &quot;COMMANDBARCONTROL&quot;, &quot;EVENT&quot;
+ vArray = Array(cstObject, _A2B_.AddPython(vReturn), vReturn._Type)
+ Case Else
+ vArray = Array(cstObject, _A2B_.AddPython(vReturn), vReturn._Type, vReturn.Name)
+ End Select
+ Else
+ If VarType(vReturn) = vbDate Then
+ vArray = Array(cstScalar, _CStr(vReturn), Null)
+ ElseIf VarType(vReturn) = vbBigint Then &apos; Could happen for big integer database fields
+ vArray = Array(cstScalar, CLng(vReturn), Null)
+ Else
+ vArray = Array(cstScalar, vReturn, Null)
+ End If
+ End If
+ End If
+
+ PythonWrapper = vArray
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;PythonWrapper&quot;, Erl)
+ GoTo Exit_Function
+Error_Object:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, &quot;Python Wrapper (&quot; &amp; pvScript &amp; &quot;)&quot;, 0, , Array(_GetLabel(&quot;OBJECT&quot;), &quot;#&quot; &amp; pvObject))
+ GoTo Exit_Function
+Error_Action:
+ TraceError(TRACEFATAL, ERRACTION, Utils._CalledSub(), 0)
+ GoTo Exit_Function
+Error_Proc:
+ TraceError(TRACEFATAL, ERRPROCEDURENOTFOUND, &quot;Python Wrapper&quot;, 0, , Array(pvScript, sModule))
+ GoTo Exit_Function
+End Function &apos; PythonWrapper V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PYTHON HELPER FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyConvertFromUrl(ByVal pvFile As Variant) As String
+&apos; Convenient function to have common conversions of filenames from/to url notations both in Python and Basic
+
+ On Local Error GoTo Exit_Function
+ PyConvertFromUrl = &quot;&quot;
+ If Not Utils._CheckArgument(pvFile, 1, vbString) Then Goto Exit_Function
+
+ PyConvertFromUrl = ConvertFromUrl(pvFile)
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyConvertFromUrl V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyConvertToUrl(ByVal pvFile As Variant) As String
+&apos; Convenient function to have common conversions of filenames from/to url notations both in Python and Basic
+
+ On Local Error GoTo Exit_Function
+ PyConvertToUrl = &quot;&quot;
+ If Not Utils._CheckArgument(pvFile, 1, vbString) Then Goto Exit_Function
+
+ PyConvertToUrl = ConvertToUrl(pvFile)
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyConvertToUrl V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyCreateUnoService(ByVal pvService As Variant) As Variant
+&apos; Convenient function to create a UNO service in Python
+
+ On Local Error GoTo Exit_Function
+ Set PyCreateUnoService = Nothing
+ If Not Utils._CheckArgument(pvService, 1, vbString) Then Goto Exit_Function
+
+ Set PyCreateUnoService = CreateUnoService(pvService)
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyCreateUnoService V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyDateAdd(ByVal pvAdd As Variant _
+ , ByVal pvCount As Variant _
+ , ByVal pvDate As Variant _
+ ) As Variant
+&apos; Convenient shortcut to useful and easy-to-use Basic date functions
+
+Dim vDate As Variant, vNewDate As Variant
+ On Local Error GoTo Exit_Function
+ PyDateAdd = Null
+
+ If Not Utils._CheckArgument(pvAdd, 1, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvCount, 2, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvDate, 3, vbString) Then Goto Exit_Function
+
+ vDate = _CDate(pvDate)
+ vNewDate = DateAdd(pvAdd, pvCount, vDate)
+ If VarType(vNewDate) = vbDate Then PyDateAdd = _CStr(vNewDate) Else PyDateAdd = vNewDate
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyDateAdd V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyDateDiff(ByVal pvAdd As Variant _
+ , ByVal pvDate1 As Variant _
+ , ByVal pvDate2 As Variant _
+ , ByVal pvWeekStart As Variant _
+ , ByVal pvYearStart As Variant _
+ ) As Variant
+&apos; Convenient shortcut to useful and easy-to-use Basic date functions
+
+Dim vDate1 As Variant, vDate2 As Variant
+ On Local Error GoTo Exit_Function
+ PyDateDiff = Null
+
+ If Not Utils._CheckArgument(pvAdd, 1, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvDate1, 2, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvDate2, 3, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWeekStart, 4, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWeekStart, 5, Utils._AddNumeric()) Then Goto Exit_Function
+
+ vDate1 = _CDate(pvDate1)
+ vDate2 = _CDate(pvDate2)
+ PyDateDiff = DateDiff(pvAdd, vDate1, vDate2, pvWeekStart, pvYearStart)
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyDateDiff V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyDatePart(ByVal pvAdd As Variant _
+ , ByVal pvDate As Variant _
+ , ByVal pvWeekStart As Variant _
+ , ByVal pvYearStart As Variant _
+ ) As Variant
+&apos; Convenient shortcut to useful and easy-to-use Basic date functions
+
+Dim vDate As Variant
+ On Local Error GoTo Exit_Function
+ PyDatePart = Null
+
+ If Not Utils._CheckArgument(pvAdd, 1, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvDate, 2, vbString) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWeekStart, 3, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvWeekStart, 4, Utils._AddNumeric()) Then Goto Exit_Function
+
+ vDate = _CDate(pvDate)
+ PyDatePart = DatePart(pvAdd, vDate, pvWeekStart, pvYearStart)
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyDatePart V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyDateValue(ByVal pvDate As Variant) As Variant
+&apos; Convenient shortcut to useful and easy-to-use Basic date functions
+
+Dim vDate As Variant
+ On Local Error GoTo Exit_Function
+ PyDateValue = Null
+ If Not Utils._CheckArgument(pvDate, 1, vbString) Then Goto Exit_Function
+
+ vDate = DateValue(pvDate)
+ If VarType(vDate) = vbDate Then PyDateValue = _CStr(vDate) Else PyDateValue = vDate
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyDateValue V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyFormat(ByVal pvValue As Variant, pvFormat As Variant) As String
+&apos; Convenient function to format numbers or dates
+
+ On Local Error GoTo Exit_Function
+ PyFormat = &quot;&quot;
+ If Not Utils._CheckArgument(pvValue, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ pvValue = _CDate(pvValue)
+ If IsEmpty(pvFormat) Then
+ PyFormat = Str(pvValue)
+ Else
+ If Not Utils._CheckArgument(pvFormat, 2, vbString) Then Goto Exit_Function
+ PyFormat = Format(pvValue, pvFormat)
+ End If
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyFormat V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyGetGUIType() As Variant
+
+ PyGetGUIType = GetGUIType()
+
+End Function &apos; PyGetGUIType V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyGetSystemTicks() As Variant
+
+ PyGetSystemTicks = GetSystemTicks()
+
+End Function &apos; PyGetSystemTicks V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyGlobalScope(ByVal pvLib As Variant) As Variant
+
+ Select Case pvLib
+ Case &quot;Basic&quot;
+ PyGlobalScope = GlobalScope.BasicLibraries()
+ Case &quot;Dialog&quot;
+ PyGlobalScope = GlobalScope.DialogLibraries()
+ Case Else
+ End Select
+
+End Function &apos; PyGlobalScope V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyInputBox(ByVal pvText As Variant _
+ , ByVal pvTitle As Variant _
+ , ByVal pvDefault As Variant _
+ , ByVal pvXPos As Variant _
+ , ByVal pvYPos As Variant _
+ ) As Variant
+&apos; Convenient function to open input box from Python
+
+ On Local Error GoTo Exit_Function
+ PyInputBox = Null
+
+ If Not Utils._CheckArgument(pvText, 1, vbString) Then Goto Exit_Function
+ If IsEmpty(pvTitle) Then pvTitle = &quot;&quot;
+ If Not Utils._CheckArgument(pvTitle, 2, vbString) Then Goto Exit_Function
+ If IsEmpty(pvDefault) Then pvDefault = &quot;&quot;
+ If Not Utils._CheckArgument(pvDefault, 3, vbString) Then Goto Exit_Function
+
+ If IsEmpty(pvXPos) Or IsEmpty(pvYPos) Then
+ PyInputBox = InputBox(pvText, pvTitle, pvDefault)
+ Else
+ If Not Utils._CheckArgument(pvXPos, 4, Utils._AddNumeric()) Then Goto Exit_Function
+ If Not Utils._CheckArgument(pvYPos, 5, Utils._AddNumeric()) Then Goto Exit_Function
+ PyInputBox = InputBox(pvText, pvTitle, pvDefault, pvXPos, pvYPos)
+ End If
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyInputBox V6.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyMsgBox(ByVal pvText As Variant _
+ , ByVal pvType As Variant _
+ , ByVal pvDialogTitle As Variant _
+ ) As Variant
+&apos; Convenient function to open message box from Python
+
+ On Local Error GoTo Exit_Function
+ PyMsgBox = Null
+
+ If Not Utils._CheckArgument(pvText, 1, vbString) Then Goto Exit_Function
+ If IsEmpty(pvType) Then pvType = 0
+ If Not Utils._CheckArgument(pvType, 2, Utils._AddNumeric()) Then Goto Exit_Function
+ If IsEmpty(pvDialogTitle) Then
+ PyMsgBox = MsgBox(pvText, pvType)
+ Else
+ If Not Utils._CheckArgument(pvDialogTitle, 3, vbString) Then Goto Exit_Function
+ PyMsgBox = MsgBox(pvText, pvType, pvDialogTitle)
+ End If
+
+Exit_Function:
+ Exit Function
+End Function &apos; PyMsgBox V6.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function PyTimer() As Long
+&apos; Convenient function to call Timer from Python
+
+ PyTimer = Timer
+
+End Function &apos; PyTimer V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _CDate(ByVal pvValue As Variant) As Variant
+&apos; Return a Date type if iso date, otherwise return input
+
+Dim vValue As Variant
+ vValue = pvValue
+ If VarType(pvValue) = vbString Then
+ If pvValue &lt;&gt; &quot;&quot; And IsDate(pvValue) Then vValue = CDate(pvValue) &apos; IsDate(&quot;&quot;) gives True !?
+ End If
+ _CDate = vValue
+
+End Function
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Recordset.xba b/wizards/source/access2base/Recordset.xba
new file mode 100644
index 000000000..eaa186fa6
--- /dev/null
+++ b/wizards/source/access2base/Recordset.xba
@@ -0,0 +1,1274 @@
+<?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="Recordset" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be RECORDSET
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String &apos; Unique, generated
+Private _Fields() As Variant
+Private _ParentName As String
+Private _ParentType As String
+Private _ParentDatabase As Object
+Private _ForwardOnly As Boolean
+Private _PassThrough As Boolean
+Private _ReadOnly As Boolean
+Private _CommandType As Long
+Private _Command As String
+Private _DataSet As Boolean &apos; True if execute() successful
+Private _BOF As Boolean
+Private _EOF As Boolean
+Private _Filter As String
+Private _EditMode As Integer &apos; dbEditxxx constants
+Private _BookmarkBeforeNew As Variant
+Private _BookmarkLastModified As Variant
+Private _IsClone As Boolean
+Private _ManageChunks As Variant &apos; Array of ChunkDescriptors
+Private RowSet As Object &apos; com.sun.star.comp.dba.ORowSet
+
+Type ChunkDescriptor
+ ChunksRequested As Boolean
+ FieldName As String
+ ChunkType As Integer &apos; vbString or vbByte
+ FileName As String
+ FileHandler As Object
+End Type
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJRECORDSET
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ _Fields = Array()
+ _ParentName = &quot;&quot;
+ Set _ParentDatabase = Nothing
+ _ParentType = &quot;&quot;
+ _ForwardOnly = False
+ _PassThrough = False
+ _ReadOnly = False
+ _CommandType = 0
+ _Command = &quot;&quot;
+ _DataSet = False
+ _BOF = True
+ _EOF = True
+ _Filter = &quot;&quot;
+ _EditMode = dbEditNone
+ _BookmarkBeforeNew = Null
+ _BookmarkLastModified = Null
+ _IsClone = False
+ Set _ManageChunks = Array()
+ Set RowSet = Nothing
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ mClose()
+End Sub
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AbsolutePosition() As Variant
+ AbsolutePosition = _PropertyGet(&quot;AbsolutePosition&quot;)
+End Property &apos; AbsolutePosition (get)
+
+Property Let AbsolutePosition(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AbsolutePosition&quot;, pvValue)
+End Property &apos; AbsolutePosition (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get BOF() As Boolean
+ BOF = _PropertyGet(&quot;BOF&quot;)
+End Property &apos; BOF (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Bookmark() As Variant
+ Bookmark = _PropertyGet(&quot;Bookmark&quot;)
+End Property &apos; Bookmark (get)
+
+Property Let Bookmark(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Bookmark&quot;, pvValue)
+End Property &apos; Bookmark (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Bookmarkable() As Boolean
+ Bookmarkable = _PropertyGet(&quot;Bookmarkable&quot;)
+End Property &apos; Bookmarkable (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get EOF() As Boolean
+ EOF = _PropertyGet(&quot;EOF&quot;)
+End Property &apos; EOF (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get EditMode() As Integer
+ EditMode = _PropertyGet(&quot;EditMode&quot;)
+End Property &apos; EditMode (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Filter() As Variant
+ Filter = _PropertyGet(&quot;Filter&quot;)
+End Property &apos; Filter (get)
+
+Property Let Filter(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Filter&quot;, pvValue)
+End Property &apos; Filter (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get LastModified() As Variant
+&apos; DO NOT PUBLISH
+ LastModified = _PropertyGet(&quot;LastModified&quot;)
+End Property &apos; LastModified (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get RecordCount() As Long
+ RecordCount = _PropertyGet(&quot;RecordCount&quot;)
+End Property &apos; RecordCount (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AddNew() As Boolean
+&apos; Initiates the creation of a new record
+
+Const cstThisSub = &quot;Recordset.AddNew&quot;
+Dim i As Integer, iFieldsCount As Integer, oField As Object
+Dim sDefault As String, oColumn As Object
+Dim iValue As Integer, lValue As Long, sgValue As Single, dbValue As Double, dValue As Date
+Dim vTemp As Variant
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ AddNew = False
+
+ With RowSet
+ &apos;Is inserting a new row allowed ?
+ If _ForwardOnly Or _ReadOnly Then Goto Error_NoUpdate
+ If Not .CanUpdateInsertedRows Then Goto Error_NoUpdate
+ If Not .IsBookmarkable Then Goto Error_NoUpdate
+ If _EditMode &lt;&gt; dbEditNone Then CancelUpdate()
+ If _BOF And _EOF Then &apos; Records before first or after last do not have a bookmark
+ _BookmarkBeforeNew = &quot;_BOF_&quot;
+ ElseIf .isBeforeFirst() Then
+ _BookmarkBeforeNew = &quot;_BOF_&quot;
+ ElseIf .isAfterLast() Then
+ _BookmarkBeforeNew = &quot;_EOF_&quot;
+ Else
+ _BookmarkBeforeNew = .getBookmark()
+ End If
+
+ .moveToInsertRow()
+
+ &apos;Set all fields to their default value
+ iFieldsCount = Fields().Count
+ On Local Error Resume Next &apos; Do not stop if default setting fails
+ For i = 0 To iFieldsCount - 1
+ Set oField = Fields(i)
+ Set oColumn = oField.Column
+ sDefault = oField.DefaultValue
+ If sDefault = &quot;&quot; Then &apos; No default value
+ If oColumn.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE Then oColumn.updateNull()
+ Else
+ With com.sun.star.sdbc.DataType
+ Select Case oColumn.Type
+ Case .BIT, .BOOLEAN
+ If sDefault = &quot;1&quot; Then oColumn.updateBoolean(True) Else oColumn.updateBoolean(False)
+ Case .TINYINT
+ iValue = CInt(sDefault)
+ If iValue &gt;= -128 And iValue &lt;= +127 Then oColumn.updateShort(iValue)
+ Case .SMALLINT
+ lValue = CLng(sDefault)
+ If lValue &gt;= -32768 And lValue &lt;= 32767 Then oColumn.updateInt(lValue)
+ Case .INTEGER
+ lValue = CLng(sDefault)
+ If lValue &gt;= -2147483648 And lValue &lt;= 2147483647 Then oColumn.updateInt(lValue)
+ Case .BIGINT
+ lValue = CLng(sDefault)
+ Column.updateLong(lValue) &apos; No proper type conversion for HYPER data type
+ Case .FLOAT
+ sgValue = CSng(sDefault)
+ If Abs(sgValue) &lt; 3.402823E38 And Abs(sgValue) &gt; 1.401298E-45 Then oColumn.updateFloat(sgValue)
+ Case .REAL, .DOUBLE
+ dbValue = CDbl(sDefault)
+ &apos;If Abs(dbValue) &lt; 1.79769313486232E308 And Abs(dbValue) &gt; 4.94065645841247E-307 Then oColumn.updateDouble(dbValue)
+ oColumn.updateDouble(dbValue)
+ Case .NUMERIC, .DECIMAL
+ dbValue = CDbl(sDefault)
+ If Utils._hasUNOProperty(Column, &quot;Scale&quot;) Then
+ If Column.Scale &gt; 0 Then
+ &apos;If Abs(dbValue) &lt; 1.79769313486232E308 And Abs(dbValue) &gt; 4.94065645841247E-307 Then oColumn.updateDouble(dbValue)
+ oColumn.updateDouble(dbValue)
+ Else
+ oColumn.updateString(sDefault)
+ End If
+ Else
+ oColumn.updateString(sDefault)
+ End If
+ Case .CHAR, .VARCHAR, .LONGVARCHAR
+ oColumn.updateString(sDefault) &apos; vbString
+ Case .DATE
+ dValue = DateValue(sDefault)
+ vTemp = New com.sun.star.util.Date
+ With vTemp
+ .Day = Day(dValue)
+ .Month = Month(dValue)
+ .Year = Year(dValue)
+ End With
+ oColumn.updateDate(vTemp)
+ Case .TIME
+ dValue = TimeValue(sDefault)
+ vTemp = New com.sun.star.util.Time
+ With vTemp
+ .Hours = Hour(dValue)
+ .Minutes = Minute(dValue)
+ .Seconds = Second(dValue)
+ &apos;.HundredthSeconds = 0
+ End With
+ oColumn.updateTime(vTemp)
+ Case .TIMESTAMP
+ dValue = DateValue(sDefault)
+ vTemp = New com.sun.star.util.DateTime
+ With vTemp
+ .Day = Day(dValue)
+ .Month = Month(dValue)
+ .Year = Year(dValue)
+ .Hours = Hour(dValue)
+ .Minutes = Minute(dValue)
+ .Seconds = Second(dValue)
+ &apos;.HundredthSeconds = 0
+ End With
+ oColumn.updateTimestamp(vTemp)
+&apos; Case .BINARY, .VARBINARY, .LONGVARBINARY
+ &apos; Case .BLOB
+&apos; Case .CLOB
+ Case Else
+ End Select
+ End With
+ End If
+ Next i
+ End With
+ If _ErrorHandler() Then On Local Error Goto Error_Function Else On Local Error Goto 0
+
+ _EditMode = dbEditAdd
+ AddNew = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; AddNew
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CancelUpdate() As Boolean
+&apos; Cancel any edit action
+
+Const cstThisSub = &quot;Recordset.CancelUpdate&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ CancelUpdate = False
+
+ With RowSet
+ Select Case _EditMode
+ Case dbEditNone
+ Case dbEditAdd
+ _AppendChunkClose(True)
+ If Not IsNull(_BookmarkBeforeNew) Then
+ Select Case _BookmarkBeforeNew
+ Case &quot;_BOF_&quot; : .beforeFirst()
+ Case &quot;_EOF_&quot; : .afterLast()
+ Case Else : .moveToBookmark(_BookmarkBeforeNew)
+ End Select
+ End If
+ Case dbEditInProgress
+ .cancelRowUpdates()
+ _AppendChunkClose(True)
+ End Select
+ End With
+
+ _EditMode = dbEditNone
+ _BookmarkBeforeNew = Null
+ _BookmarkLastModified = Null
+ CancelUpdate = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; CancelUpdate
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Clone() As Object
+&apos; Duplicate an existing recordset
+
+Const cstThisSub = &quot;Recordset.Clone&quot;
+
+Const cstNull = -1
+Dim iType As Integer, iOptions As Integer, iLockEdit As Integer
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ Set Clone = Nothing
+
+ If _IsClone Then Goto Error_Clone
+ If _ForwardOnly Then iType = dbOpenForwardOnly Else iType = cstNull
+ If _PassThrough Then iOptions = dbSQLPassThrough Else iOptions = cstNull
+ iLockEdit = dbReadOnly &apos; Always read-only
+
+ Set Clone = OpenRecordset(iType, iOptions, iLockEdit, True)
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_Clone:
+ TraceError(TRACEFATAL, ERRRECORDSETCLONE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; Clone
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function mClose(ByVal Optional pbRemove As Boolean) As Variant
+&apos; Dispose UNO objects
+&apos; If pbRemove = True, remove recordset from Recordsets collection
+
+Const cstThisSub = &quot;Recordset.Close&quot;
+Dim i As Integer
+
+ If _ErrorHandler() Then On Local Error Goto Exit_Function &apos; Do not stop execution
+ Utils._SetCalledSub(cstThisSub)
+ If Not IsNull(RowSet) Then
+ RowSet.close()
+ RowSet.dispose()
+ End If
+ _ForwardOnly = False
+ _PassThrough = False
+ _ReadOnly = False
+ _CommandType = 0
+ _Command = &quot;&quot;
+ _ParentName = &quot;&quot;
+ _ParentType = &quot;&quot;
+ _DataSet = False
+ _BOF = True
+ _EOF = True
+ _Filter = &quot;&quot;
+ _EditMode = dbEditNone
+ _BookmarkBeforeNew = Null
+ _BookmarkLastModified = Null
+ _IsClone = False
+ For i = 0 To UBound(_Fields)
+ If Not IsNull(_Fields(i)) Then
+ _Fields(i).Dispose()
+ Set _Fields(i) = Nothing
+ End If
+ Next i
+ _Fields = Array()
+ Set RowSet = Nothing
+ If IsMissing(pbRemove) Then pbRemove = True
+ If pbRemove Then _ParentDatabase.RecordsetsColl.Remove(_Name)
+ Set _ParentDatabase = Nothing
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Close
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Delete() As Boolean
+&apos; Deletes the current record
+
+Const cstThisSub = &quot;Recordset.Delete&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ Delete = False
+
+ &apos;Is deleting a row allowed ?
+ If _ForwardOnly Or _ReadOnly Then Goto Error_NoUpdate
+ If _EditMode &lt;&gt; dbEditNone Then
+ CancelUpdate()
+ Goto Error_Sequence
+ End If
+ If RowSet.rowDeleted() Then Goto Error_RowDeleted
+
+ RowSet.deleteRow()
+ Delete = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_RowDeleted:
+ TraceError(TRACEFATAL, ERRROWDELETED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Sequence:
+ TraceError(TRACEFATAL, ERRUPDATESEQUENCE, Utils._CalledSub(), 0, 1)
+ Goto Exit_Function
+End Function &apos; Delete
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Edit() As Boolean
+&apos; Updates the current record
+
+Const cstThisSub = &quot;Recordset.Edit&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ Edit = False
+
+ &apos;Is updating a row allowed ?
+ If _ForwardOnly Or _ReadOnly Then Goto Error_NoUpdate
+ If _EditMode &lt;&gt; dbEditNone Then CancelUpdate()
+ If RowSet.rowDeleted() Then Goto Error_RowDeleted
+
+ _EditMode = dbEditInProgress
+ Edit = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_RowDeleted:
+ TraceError(TRACEFATAL, ERRROWDELETED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; Edit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Fields(ByVal Optional pvIndex As Variant) As Object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Recordset.Fields&quot;
+ Utils._SetCalledSub(cstThisSub)
+
+ Set Fields = Nothing
+ If Not IsMissing(pvIndex) Then
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+ End If
+
+Dim sObjects() As String, sObjectName As String, oObject As Object
+Dim i As Integer, oFields As Object, iIndex As Integer
+
+ &apos; No argument, return a collection
+ If IsMissing(pvIndex) Then
+ Set oObject = New Collect
+ Set oObject._This = oObject
+ oObject._CollType = COLLFIELDS
+ Set oObject._Parent = _This
+ oObject._Count = RowSet.getColumns().Count
+ Goto Exit_Function
+ End If
+
+ Set oFields = RowSet.getColumns()
+ sObjects = oFields.ElementNames()
+
+ &apos; Argument is the field name
+ If VarType(pvIndex) = vbString Then
+ iIndex = -1
+ &apos; Check existence of object and find its exact (case-sensitive) name
+ For i = 0 To UBound(sObjects)
+ If UCase(pvIndex) = UCase(sObjects(i)) Then
+ sObjectName = sObjects(i)
+ iIndex = i
+ Exit For
+ End If
+ Next i
+ If iIndex &lt; 0 Then Goto Trace_NotFound
+ &apos; Argument is numeric
+ Else
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(sObjects) Then Goto Trace_IndexError
+ sObjectName = sObjects(pvIndex)
+ iIndex = pvIndex
+ End If
+
+ &apos; Check if field object already buffered in _Fields() array
+ If UBound(_Fields) &lt; 0 Then &apos; Initialize _Fields
+ ReDim _Fields(0 To UBound(sObjects))
+ For i = 0 To UBound(sObjects)
+ Set _Fields(i) = Nothing
+ Next i
+ End If
+ If Not IsNull(_Fields(iIndex)) Then
+ Set oObject = _Fields(iIndex)
+ &apos; Otherwise create new field object
+ Else
+ Set oObject = New Field
+ Set oObject._This = oObject
+ oObject._Name = sObjectName
+ Set oObject.Column = oFields.getByName(sObjectName)
+ If Utils._hasUNOProperty(oObject.Column, &quot;Precision&quot;) Then oObject._Precision = oObject.Column.Precision
+ oObject._ParentName = _Name
+ oObject._ParentType = _Type
+ Set oObject._ParentDatabase = _ParentDatabase
+ Set oObject._ParentRecordset = _This
+ Set _Fields(iIndex) = oObject
+ End If
+
+Exit_Function:
+ Set Fields = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERROBJECTNOTFOUND, Utils._CalledSub(), 0, , Array(_GetLabel(&quot;FIELD&quot;), pvIndex))
+ Goto Exit_Function
+Trace_IndexError:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; Fields
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+Const cstThisSub = &quot;Recordset.getProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function GetRows(ByVal Optional pvNumRows As variant, ByVal Optional pbStrDate As Boolean) As Variant
+&apos; UNPUBLISHED - pbStrDate = True forces all dates to be converted into strings
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Const cstThisSub = &quot;Recordset.GetRows&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pbStrDate) Then pbStrDate = False
+
+Dim vMatrix() As Variant, lSize As Long, iNumFields As Integer, i As Integer
+ vMatrix() = Array()
+ If IsMissing(pvNumRows) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvNumRows, 1, Utils._AddNumeric()) Then Goto Exit_Function
+ If pvNumRows &lt; 1 Then Goto Trace_Error
+ If IsNull(RowSet) Then Goto Trace_Closed
+ If Not _DataSet Then Goto Exit_Function
+
+ If _EditMode &lt;&gt; dbEditNone Then CancelUpdate()
+
+ If _EOF Then Goto Exit_Function
+
+ lSize = -1
+ iNumFields = RowSet.getColumns().Count - 1
+ If iNumFields &lt; 0 Then Goto Exit_Function
+
+ ReDim vMatrix(0 To iNumFields, 0 To pvNumRows - 1)
+
+ Do While Not _EOF And lSize &lt; pvNumRows - 1
+ lSize = lSize + 1
+ For i = 0 To iNumFields
+ vMatrix(i, lSize) = Utils._getResultSetColumnValue(RowSet, i + 1)
+ If pbStrDate And IsDate(vMatrix(i, lSize)) Then vMatrix(i, lSize) = _CStr(vMatrix(i, lSize))
+ Next i
+ _Move(&quot;NEXT&quot;)
+ Loop
+ If lSize &lt; pvNumRows - 1 Then &apos; Resize to number of fetched records
+ ReDim Preserve vMatrix(0 To iNumFields, 0 To lSize)
+ End If
+
+Exit_Function:
+ GetRows() = vMatrix()
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, , Array(1, pvNumRows))
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_Closed:
+ TraceError(TRACEFATAL, ERRRECORDSETCLOSED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; GetRows V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+Const cstThisSub = &quot;Recordset.hasProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Move(ByVal Optional pvRelative As Variant, ByVal Optional pvBookmark As variant) As Boolean
+&apos; Move record pointer Relative rows vs. bookmark or current record
+
+ If IsMissing(pvRelative) Then Call _TraceArguments()
+ If Not Utils._CheckArgument(pvRelative, 1, Utils._AddNumeric()) Then Goto Exit_Function
+
+ If IsMissing(pvBookmark) Then Move = _Move(pvRelative) Else Move = _Move(pvRelative, pvBookmark)
+
+Exit_Function:
+ Exit Function
+End Function &apos; Move
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function MoveFirst() As Boolean
+ MoveFirst = _Move(&quot;First&quot;)
+End Function &apos; MoveFirst
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function MoveLast() As Boolean
+ MoveLast = _Move(&quot;Last&quot;)
+End Function &apos; MoveLast
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function MoveNext() As Boolean
+ MoveNext = _Move(&quot;Next&quot;)
+End Function &apos; MoveNext
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function MovePrevious() As Boolean
+ MovePrevious = _Move(&quot;Previous&quot;)
+End Function &apos; MovePrevious
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OpenRecordset(ByVal Optional pvType As Variant _
+ , ByVal Optional pvOptions As Variant _
+ , ByVal Optional pvLockEdit As Variant _
+ , ByVal Optional pbClone As Boolean) As Object
+&apos;Return a Recordset object based on current recordset object with filter addition
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = Utils._PCase(_Type) &amp; &quot;.OpenRecordset&quot;
+ Utils._SetCalledSub(cstThisSub)
+ Set OpenRecordset = Nothing
+Const cstNull = -1
+
+Dim oObject As Object
+ Set oObject = Nothing
+ If IsMissing(pvType) Then
+ pvType = cstNull
+ Else
+ If Not Utils._CheckArgument(pvType, 1, Utils._AddNumeric(), Array(cstNull, dbOpenForwardOnly)) Then Goto Exit_Function
+ End If
+ If IsMissing(pvOptions) Then
+ pvOptions = cstNull
+ Else
+ If Not Utils._CheckArgument(pvOptions, 2, Utils._AddNumeric(), Array(cstNull, dbSQLPassThrough)) Then Goto Exit_Function
+ End If
+ If IsMissing(pvLockEdit) Then
+ pvLockEdit = cstNull
+ Else
+ If Not Utils._CheckArgument(pvLockEdit, 3, Utils._AddNumeric(), Array(cstNull, dbReadOnly)) Then Goto Exit_Function
+ End If
+ If IsMissing(pbClone) Then pbClone = False &apos; pbClone is a not published argument
+
+ Set oObject = New Recordset
+ With oObject
+ ._CommandType = _CommandType
+ ._Command = _Command
+ ._ParentName = _Name
+ ._ParentType = _Type
+ Set ._ParentDatabase = _ParentDatabase
+ Set ._This = oObject
+ ._ForwardOnly = ( pvType = dbOpenForwardOnly )
+ ._PassThrough = ( pvOptions = dbSQLPassThrough )
+ ._ReadOnly = ( (pvLockEdit = dbReadOnly) Or _ReadOnly )
+ Select Case True
+ Case pbClone : Call ._Initialize(, RowSet)
+ Case _Filter &lt;&gt; &quot;&quot; : Call ._Initialize(_Filter)
+ Case Else : Call ._Initialize()
+ End Select
+ End With
+ With _ParentDatabase
+ .RecordsetMax = .RecordsetMax + 1
+ oObject._Name = Format(.RecordsetMax, &quot;0000000&quot;)
+ .RecordsetsColl.Add(oObject, UCase(oObject._Name))
+ End With
+
+ If Not ( oObject._BOF And oObject._EOF ) Then oObject.MoveFirst() &apos; Do nothing if resultset empty
+
+Exit_Function:
+ Set OpenRecordset = oObject
+ Set oObject = Nothing
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ GoTo Exit_Function
+End Function &apos; OpenRecordset
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Const cstThisSub = &quot;Recordset.Properties&quot;
+ Utils._SetCalledSub(cstThisSub)
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+ Set vProperty._ParentDatabase = _ParentDatabase
+
+Exit_Function:
+ Set Properties = vProperty
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+Const cstThisSub = &quot;Recordset.setProperty&quot;
+ Utils._SetCalledSub(cstThisSub)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(cstThisSub)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Update() As Boolean
+&apos; Finalize the updates of the current record
+
+Const cstThisSub = &quot;Recordset.Update&quot;
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(cstThisSub)
+ Update = False
+
+ &apos;Is updating a row allowed ?
+ If _ForwardOnly Or _ReadOnly Then Goto Error_NoUpdate
+ With RowSet
+ If .rowDeleted() Then Goto Error_RowDeleted
+ Select Case _EditMode
+ Case dbEditNone
+ Goto Trace_Error_Update
+ Case dbEditAdd
+ _AppendChunkClose(False)
+ If .IsNew And .IsModified Then .insertRow()
+ _BookmarkLastModified = .getBookmark()
+ If Not IsNull(_BookmarkBeforeNew) Then
+ Select Case _BookmarkBeforeNew
+ Case &quot;_BOF_&quot; : .beforeFirst()
+ Case &quot;_EOF_&quot; : .afterLast()
+ Case Else : .moveToBookmark(_BookmarkBeforeNew)
+ End Select
+ End If
+ Case dbEditInProgress
+ _AppendChunkClose(False)
+ If .IsModified Then
+ .updateRow()
+ _BookmarkLastModified = .getBookmark()
+ End If
+ End Select
+ End With
+ _EditMode = dbEditNone
+ Update = True
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+Error_NoUpdate:
+ TraceError(TRACEFATAL, ERRNOTUPDATABLE, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Trace_Error_Update:
+ TraceError(TRACEFATAL, ERRUPDATESEQUENCE, Utils._CalledSub(), 0, 1)
+ Goto Exit_Function
+Error_RowDeleted:
+ TraceError(TRACEFATAL, ERRROWDELETED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+End Function &apos; Update
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _AppendChunk(ByVal psFieldName As String, ByRef pvChunk As Variant, piChunkType) As Boolean
+&apos; Write chunk at the end of the file dedicated to the given field
+
+ If _ErrorHandler() Then On Local Error GoTo Error_Function
+Dim oFileAccess As Object
+Dim i As Integer, oChunk As Object, iChunk As Integer
+
+ &apos; Do nothing if chunk meaningless
+ _AppendChunk = False
+ If IsNull(pvChunk) Then GoTo Exit_Function
+ If IsArray(pvChunk) Then
+ If UBound(pvChunk) &lt; LBound(pvChunk) Then GoTo Exit_Function &apos; Empty array
+ End If
+
+ &apos; Find or create relevant chunk entry
+ iChunk = -1
+ For i = 0 To UBound(_ManageChunks)
+ Set oChunk = _ManageChunks(i)
+ If oChunk.FieldName = psFieldName Then
+ iChunk = i
+ Exit For
+ End If
+ Next i
+ If iChunk = -1 Then
+ _AppendChunkInit(psFieldName)
+ iChunk = UBound(_ManageChunks)
+ End If
+
+ Set oChunk = _ManageChunks(iChunk)
+ With oChunk
+ If Not .ChunksRequested Then &apos; First chunk
+ .ChunksRequested = True
+ .ChunkType = piChunkType
+ .FileName = Utils._GetRandomFileName(_Name)
+ Set oFileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ .FileHandler = oFileAccess.openFileWrite(.FileName)
+ End If
+ .FileHandler.writeBytes(pvChunk)
+ End With
+ _AppendChunk = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Recordset._AppendChunk&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; AppendChunk V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _AppendChunkClose(ByVal pbCancel As Boolean) As Boolean
+&apos; Stores file content to database field(s)
+&apos; Called from Update() [pbCancel = False] or CancelUpdate() [pbCancel = True]
+
+ If _ErrorHandler() Then On Local Error GoTo Error_Function
+Dim oFileAccess As Object, oStream As Object, lFileLength As Long, oField As Object
+Dim i As Integer, oChunk As Object
+
+ _AppendChunkClose = False
+ For i = 0 To UBound(_ManageChunks)
+ Set oChunk = _ManageChunks(i)
+ With oChunk
+ If Not .ChunksRequested Then GoTo Exit_Function
+ If IsNull(.FileHandler) Then GoTo Exit_Function
+ .Filehandler.closeOutput
+ Set oFileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ &apos; Copy file to field
+ If Not pbCancel Then
+ Set oStream = oFileAccess.openFileRead(.FileName)
+ lFileLength = oStream.getLength()
+ If lFileLength &gt; 0 Then
+ Set oField = RowSet.getColumns.getByName(.FieldName)
+ Select Case .ChunkType
+ Case vbByte
+ oField.updateBinaryStream(oStream, lFileLength)
+&apos; Case vbString &apos; DOES NOT WORK FOR CHARACTER TYPES
+&apos; oField.updateCharacterStream(oStream, lFileLength)
+ End Select
+ End If
+ oStream.closeInput()
+ End If
+ If oFileAccess.exists(.FileName) Then oFileAccess.kill(.FileName)
+ End With
+ Next i
+ Set _ManageChunks = Array()
+ _AppendChunkClose = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;Recordset._AppendChunkClose&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; AppendChunkClose V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _AppendChunkInit(psFieldName As String) As Boolean
+&apos; Initialize chunks manager
+
+Dim iSize As Integer
+ iSize = UBound(_ManageChunks) + 1
+ ReDim Preserve _ManageChunks(0 To iSize)
+ Set _ManageChunks(iSize) = New ChunkDescriptor
+ With _ManageChunks(iSize)
+ .ChunksRequested = False
+ .FieldName = psFieldName
+ .FileName = &quot;&quot;
+ Set .FileHandler = Nothing
+ End With
+
+End Function &apos; AppendChunkInit V1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _Initialize(ByVal Optional pvFilter As Variant, Optional poRowSet As Object)
+&apos; Initialize new recordset
+
+Dim sFilter As String
+
+ If _Command = &quot;&quot; Then Exit Sub
+
+ If _ErrorHandler() Then On Local Error Goto Error_Sub
+ If VarType(pvFilter) = vbError Then
+ sFilter = &quot;&quot;
+ ElseIf IsMissing(pvFilter) Then
+ sFilter = &quot;&quot;
+ Else
+ sFilter = pvFilter
+ End If
+ If Not IsMissing(poRowSet) Then &apos; Clone
+ Set RowSet = poRowSet.createResultSet()
+ _IsClone = True
+ RowSet.last() &apos; Solves bookmark desynchro when parent bookmark is used ?!?
+ Else
+ Set RowSet = CreateUnoService(&quot;com.sun.star.sdb.RowSet&quot;)
+ _IsClone = False
+ With RowSet
+ If IsNull(.ActiveConnection) Then Set .ActiveConnection = _ParentDatabase.Connection
+ .CommandType = _CommandType
+ .Command = _Command
+ If _ForwardOnly Then .ResultSetType = com.sun.star.sdbc.ResultSetType.FORWARD_ONLY _
+ Else .ResultSetType = com.sun.star.sdbc.ResultSetType.SCROLL_SENSITIVE
+ If _PassThrough Then .EscapeProcessing = False _
+ Else .EscapeProcessing = True
+ If _ReadOnly Then
+ .ResultSetConcurrency = com.sun.star.sdbc.ResultSetConcurrency.READ_ONLY
+ .TransactionIsolation = com.sun.star.sdbc.TransactionIsolation.READ_UNCOMMITTED &apos; Dirty read
+ Else
+ .ResultSetConcurrency = com.sun.star.sdbc.ResultSetConcurrency.UPDATABLE
+ .TransactionIsolation = com.sun.star.sdbc.TransactionIsolation.READ_COMMITTED
+ End If
+ End With
+
+ If sFilter &lt;&gt; &quot;&quot; Then &apos; Filter must be set before execute()
+ RowSet.Filter = sFilter
+ RowSet.ApplyFilter = True
+ End If
+ On Local Error Goto SQL_Error
+ RowSet.execute()
+ On Local Error Goto Error_Sub
+ End If
+ _DataSet = True
+&apos;If the Recordset contains no records, the BOF and EOF properties are True, and there is no current record.
+ _BOF = ( RowSet.IsRowCountFinal And RowSet.RowCount = 0 )
+ _EOF = _BOF
+
+Exit_Sub:
+ Exit Sub
+SQL_Error:
+ TraceError(TRACEFATAL, ERRSQLSTATEMENT, Utils._CalledSub(), 0, , _Command)
+ Goto Exit_Sub
+Error_Sub:
+ TraceError(TRACEABORT, Err, &quot;Recordset._Initialize&quot;, Erl)
+ GoTo Exit_Sub
+End Sub &apos; _Initialize
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _Move(pvTarget As Variant, ByVal Optional pvBookmark As Variant, ByVal Optional pbAbsolute As Boolean) As Boolean
+&apos;Move to the first, last, next, or previous record in a specified Recordset object and make that record the current record.
+
+Dim cstThisSub As String
+ cstThisSub = &quot;Recordset.Move&quot; &amp; Iif(VarType(pvTarget) = vbString, pvTarget, &quot;&quot;)
+ Utils._SetCalledSub(cstThisSub)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ If IsNull(RowSet) Then Goto Trace_Closed
+ If Not _DataSet Then Goto Trace_NoData
+ If _BOF And _EOF Then Goto Trace_NoData
+ _Move = False
+ CancelUpdate() &apos; Any Move cancels all updates, even Move(0) !
+
+Dim l As Long, lRow As Long
+ With RowSet
+ Select Case VarType(pvTarget)
+ Case vbString
+ Select Case UCase(pvTarget)
+ Case &quot;FIRST&quot;
+ If _ForwardOnly Then
+ If Not ( .isBeforeFirst() Or .isFirst() ) Then
+ Goto Trace_Forward
+ Else
+ .next()
+ End If
+ Else
+ .first()
+ End If
+ Case &quot;LAST&quot;
+ If _ForwardOnly Then
+ If .isAfterLast() Then Goto Trace_Forward
+ Do While Not ( .isRowCountFinal And .Row = .RowCount ) &apos; isLast() = True after reading of first records chunk
+ .next()
+ Loop
+ Else
+ .last()
+ End If
+ Case &quot;NEXT&quot;
+ If _EOF Then Goto Trace_OutOfRange
+ .next()
+ Case &quot;PREVIOUS&quot;
+ If _ForwardOnly Then Goto Trace_Forward
+ If _BOF Then Goto Trace_OutOfRange
+ .previous()
+ End Select
+ Case Else &apos; Relative or absolute move
+ If IsMissing(pbAbsolute) Then pbAbsolute = False &apos; Relative move is default
+ If _ForwardOnly And pvTarget &lt; 0 then Goto Trace_Forward
+ If IsMissing(pvBookmark) Then
+ If pvTarget = 0 Then Goto Exit_Function &apos; Do nothing
+ If _ForwardOnly Then
+ If pbAbsolute Then lRow = .getRow() Else lRow = 0
+ For l = 1 To pvTarget - lRow
+ If .isAfterLast() Then Exit For
+ .next()
+ Next l
+ Else
+ If pbAbsolute Then .absolute(pvTarget) Else .relative(pvTarget)
+ End If
+ Else &apos; Move is always relative when bookmark argument present
+ If _ForwardOnly Then Goto Trace_Forward
+ If pvTarget = 0 Then
+ .moveToBookmark(pvBookmark)
+ Else
+ .moveRelativeToBookmark(pvBookmark, pvTarget)
+ End If
+ End If
+ End Select
+
+ _BOF = .isBeforeFirst() &apos; https://forum.openoffice.org/en/forum/viewtopic.php?f=47&amp;t=76640
+ _EOF = .isAfterlast()
+ If _BOF Or _EOF Then
+ _Move = False
+ Else
+ If .rowDeleted() Then Goto Error_RowDeleted
+ If .rowUpdated() Then .refreshRow()
+ _Move = True
+ End If
+ End With
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Exit_Close: &apos; Force close of recordset when error raised
+ mClose()
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Close
+Trace_Forward:
+ TraceError(TRACEFATAL, ERRRECORDSETFORWARD, Utils._CalledSub(), 0)
+ Goto Exit_Close
+Trace_NoData:
+ TraceError(TRACEFATAL, ERRRECORDSETNODATA, Utils._CalledSub(), 0)
+ Goto Exit_Close
+Trace_OutOfRange:
+ TraceError(TRACEFATAL, ERRRECORDSETRANGE, Utils._CalledSub(), 0)
+ Goto Exit_Close
+Error_RowDeleted:
+ TraceError(TRACEFATAL, ERRROWDELETED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Trace_Closed:
+ TraceError(TRACEFATAL, ERRRECORDSETCLOSED, Utils._CalledSub(), 0)
+ Goto Exit_Close
+End Function &apos; Move
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ _PropertiesList = Array(&quot;AbsolutePosition&quot;, &quot;BOF&quot;, &quot;Bookmarkable&quot;, &quot;Bookmark&quot;, &quot;EditMode&quot; _
+ , &quot;EOF&quot;, &quot;Filter&quot;, &quot;LastModified&quot;, &quot;Name&quot;, &quot;ObjectType&quot; , &quot;RecordCount&quot; _
+ )
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+Dim cstThisSub As String
+ cstThisSub = &quot;Recordset.get&quot;
+ Utils._SetCalledSub(cstThisSub &amp; psProperty)
+
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AbsolutePosition&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ With RowSet
+ Select Case True
+ Case _BOF And _EOF : _PropertyGet = -1
+ Case .isBeforeFirst() Or .isAfterLast() : _PropertyGet = -1
+ Case Else : _PropertyGet = .getRow() &apos; Not getRow() - 1 as MSAccess requires
+ End Select
+ End With
+ Case UCase(&quot;BOF&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ Select Case True
+ Case _BOF And _EOF : _PropertyGet = True
+ Case RowSet.isBeforeFirst() : _PropertyGet = True
+ Case Else : _PropertyGet = False
+ End Select
+ Case UCase(&quot;Bookmarkable&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ If _ForwardOnly Then _PropertyGet = False Else _PropertyGet = RowSet.IsBookmarkable
+ Case UCase(&quot;Bookmark&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ If RowSet.IsBookmarkable And Not _ForwardOnly Then
+ If _BOF Or _EOF Then _PropertyGet = Null Else _PropertyGet = RowSet.getBookmark()
+ Else
+ _PropertyGet = Null
+ If _ForwardOnly Then Goto Trace_Forward
+ End If
+ Case UCase(&quot;EditMode&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ _PropertyGet = _EditMode
+ Case UCase(&quot;EOF&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ Select Case True
+ Case _BOF And _EOF : _PropertyGet = True
+ Case RowSet.isAfterLast() : _PropertyGet = True
+ Case Else : _PropertyGet = False
+ End Select
+ Case UCase(&quot;Filter&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ _PropertyGet = RowSet.Filter
+ Case UCase(&quot;LastModified&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ If RowSet.IsBookmarkable And Not _ForwardOnly Then
+ _PropertyGet = _BookmarkLastModified
+ Else
+ _PropertyGet = Null
+ If _ForwardOnly Then Goto Trace_Forward
+ End If
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;RecordCount&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ _PropertyGet = RowSet.RowCount
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, , psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Forward:
+ TraceError(TRACEFATAL, ERRRECORDSETFORWARD, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Trace_Closed:
+ TraceError(TRACEFATAL, ERRRECORDSETCLOSED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub &amp; &quot;._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+
+Dim cstThisSub As String
+ cstThisSub = &quot;Recordset.set&quot;
+ Utils._SetCalledSub(cstThisSub &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _PropertySet = True
+
+&apos;Execute
+Dim iArgNr As Integer
+Dim oObject As Object
+
+ If _IsLeft(_A2B_.CalledSub, &quot;Recordset.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AbsolutePosition&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ If pvValue &lt; 1 Then Goto Trace_Error_Value
+ _Move(pvValue, , True)
+ Case UCase(&quot;Bookmark&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ _Move(0, pvValue)
+ Case UCase(&quot;Filter&quot;)
+ If IsNull(RowSet) Then Goto Trace_Closed
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ _Filter = _ParentDatabase._ReplaceSquareBrackets(pvValue)
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Closed:
+ TraceError(TRACEFATAL, ERRRECORDSETCLOSED, Utils._CalledSub(), 0)
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, Utils._CalledSub(), Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module>
diff --git a/wizards/source/access2base/Root_.xba b/wizards/source/access2base/Root_.xba
new file mode 100644
index 000000000..73f743278
--- /dev/null
+++ b/wizards/source/access2base/Root_.xba
@@ -0,0 +1,311 @@
+<?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="Root_" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- FOR INTERNAL USE ONLY ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private ErrorHandler As Boolean
+Private MinimalTraceLevel As Integer
+Private TraceLogs() As Variant
+Private TraceLogCount As Integer
+Private TraceLogLast As Integer
+Private TraceLogMaxEntries As Integer
+Private LastErrorCode As Integer
+Private LastErrorLevel As String
+Private ErrorText As String
+Private ErrorLongText As String
+Private CalledSub As String
+Private DebugPrintShort As Boolean
+Private Introspection As Object &apos; com.sun.star.beans.Introspection
+Private VersionNumber As String &apos; Actual Access2Base version number
+Private Locale As String
+Private ExcludeA2B As Boolean
+Private TextSearch As Object
+Private SearchOptions As Variant
+Private FindRecord As Object
+Private StatusBar As Object
+Private Dialogs As Object &apos; Collection
+Private TempVars As Object &apos; Collection
+Private CurrentDoc() As Variant &apos; Array of document containers - [0] = Base document, [1 ... N] = other documents
+Private PythonCache() As Variant &apos; Array of objects created in Python scripts
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ VersionNumber = Access2Base_Version
+ ErrorHandler = True
+ MinimalTraceLevel = 0
+ TraceLogs() = Array()
+ TraceLogCount = 0
+ TraceLogLast = 0
+ TraceLogMaxEntries = 0
+ LastErrorCode = 0
+ LastErrorLevel = &quot;&quot;
+ ErrorText = &quot;&quot;
+ ErrorLongText = &quot;&quot;
+ CalledSub = &quot;&quot;
+ DebugPrintShort = True
+ Locale = L10N._GetLocale()
+ ExcludeA2B = True
+ Set Introspection = CreateUnoService(&quot;com.sun.star.beans.Introspection&quot;)
+ Set TextSearch = CreateUnoService(&quot;com.sun.star.util.TextSearch&quot;)
+ SearchOptions = New com.sun.star.util.SearchOptions
+ With SearchOptions
+ .algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
+ .searchFlag = 0
+ .transliterateFlags = com.sun.star.i18n.TransliterationModules.IGNORE_CASE
+ End With
+ Set FindRecord = Nothing
+ Set StatusBar = Nothing
+ Set Dialogs = New Collection
+ Set TempVars = New Collection
+ CurrentDoc = Array()
+ ReDim CurrentDoc(0 To 0)
+ Set CurrentDoc(0) = Nothing
+ PythonCache = Array()
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function AddPython(ByRef pvObject As Variant) As Long
+&apos; Store the object as a new entry in PythonCache and return its entry number
+
+Dim lVars As Long, vObject As Variant
+
+ lVars = UBound(PythonCache) + 1
+ ReDim Preserve PythonCache(0 To lVars)
+ PythonCache(lVars) = pvObject
+
+ AddPython = lVars
+
+End Function &apos; AddPython V6.4
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub CloseConnection()
+&apos; Close all connections established by current document to free memory.
+&apos; - if Base document =&gt; close the one concerned database connection
+&apos; - if non-Base documents =&gt; close the connections of each individual standalone form
+
+Dim i As Integer, iCurrentDoc As Integer
+Dim vDbContainer As Variant, vDbContainers() As Variant, vDocContainer As Variant
+
+ If ErrorHandler Then On Local Error Goto Error_Sub
+
+ If Not IsArray(CurrentDoc) Then Goto Exit_Sub
+ If UBound(CurrentDoc) &lt; 0 Then Goto Exit_Sub
+ iCurrentDoc = CurrentDocIndex( , False) &apos; False prevents error raising if not found
+ If iCurrentDoc &lt; 0 Then GoTo Exit_Sub &apos; If not found ignore
+
+ vDocContainer = CurrentDocument(iCurrentDoc)
+ With vDocContainer
+ If Not .Active Then GoTo Exit_Sub &apos; e.g. if multiple calls to CloseConnection()
+ For i = 0 To UBound(.DbContainers)
+ If Not IsNull(.DbContainers(i).Database) Then
+ .DbContainers(i).Database.Dispose()
+ Set .DbContainers(i).Database = Nothing
+ End If
+ TraceLog(TRACEANY, UCase(CalledSub) &amp; &quot; &quot; &amp; .URL &amp; Iif(i = 0, &quot;&quot;, &quot; Form=&quot; &amp; .DbContainers(i).FormName), False)
+ Set .DbContainers(i) = Nothing
+ Next i
+ .DbContainers = Array()
+ .URL = &quot;&quot;
+ .DbConnect = 0
+ .Active = False
+ Set .Document = Nothing
+ End With
+ CurrentDoc(iCurrentDoc) = vDocContainer
+
+Exit_Sub:
+ Exit Sub
+Error_Sub:
+ TraceError(TRACEABORT, Err, CalledSub, Erl, False) &apos; No error message addressed to the user, only stored in console
+ GoTo Exit_Sub
+End Sub &apos; CloseConnection
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CurrentDb() As Object
+&apos; Returns _A2B_.CurrentDocument().Database as an object to allow access to its properties
+
+Dim iCurrentDoc As Integer
+
+ Set CurrentDb = Nothing
+
+ If Not IsArray(CurrentDoc) Then Goto Exit_Function
+ If UBound(CurrentDoc) &lt; 0 Then Goto Exit_Function
+ iCurrentDoc = CurrentDocIndex(, False) &apos; False = no abort
+ If iCurrentDoc &gt;= 0 Then
+ If UBound(CurrentDoc(iCurrentDoc).DbContainers) &gt;= 0 Then Set CurrentDb = CurrentDoc(iCurrentDoc).DbContainers(0).Database
+ End If
+
+Exit_Function:
+ Exit Function
+End Function &apos; CurrentDb
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CurrentDocIndex(Optional pvURL As Variant, Optional pbAbort As Variant) As Integer
+&apos; Returns the entry in CurrentDoc(...) referring to the current document
+
+Dim i As Integer, bFound As Boolean, sURL As String
+Const cstBase = &quot;com.sun.star.comp.dba.ODatabaseDocument&quot;
+
+ bFound = False
+ CurrentDocIndex = -1
+
+ If Not IsArray(CurrentDoc) Then Goto Trace_Error
+ If UBound(CurrentDoc) &lt; 0 Then Goto Trace_Error
+ For i = 1 To UBound(CurrentDoc) &apos; [0] reserved to database .odb document
+ If IsMissing(pvURL) Then &apos; Not on 1 single line ?!?
+ If Utils._hasUNOProperty(ThisComponent, &quot;URL&quot;) Then
+ sURL = ThisComponent.URL
+ Else
+ Exit For &apos; f.i. ThisComponent = Basic IDE ...
+ End If
+ Else
+ sURL = pvURL &apos; To support the SelectObject action
+ End If
+ If CurrentDoc(i).Active And CurrentDoc(i).URL = sURL Then
+ CurrentDocIndex = i
+ bFound = True
+ Exit For
+ End If
+ Next i
+
+ If Not bFound Then
+ If IsNull(CurrentDoc(0)) Then GoTo Trace_Error
+ With CurrentDoc(0)
+ If Not .Active Then GoTo Trace_Error
+ If IsNull(.Document) Then GoTo Trace_Error
+ End With
+ CurrentDocIndex = 0
+ End If
+
+Exit_Function:
+ Exit Function
+Trace_Error:
+ If IsMissing(pbAbort) Then pbAbort = True
+ If pbAbort Then TraceError(TRACEABORT, ERRDBNOTCONNECTED, Utils._CalledSub(), 0, 1) Else CurrentDocIndex = -1
+ Goto Exit_Function
+End Function &apos; CurrentDocIndex
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function CurrentDocument(ByVal Optional piDocIndex As Integer) As Variant
+&apos; Returns the CurrentDoc(...) referring to the current document or to the argument
+
+Dim iDocIndex As Integer
+ If IsMissing(piDocIndex) Then iDocIndex = CurrentDocIndex(, False) Else iDocIndex = piDocIndex
+ If iDocIndex &gt;= 0 And iDocIndex &lt;= UBound(CurrentDoc) Then Set CurrentDocument = CurrentDoc(iDocIndex) Else Set CurrentDocument = Nothing
+
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dump()
+&apos; For debugging purposes
+Dim i As Integer, j As Integer, vCurrentDoc As Variant
+ On Local Error Resume Next
+
+ DebugPrint &quot;Version&quot;, VersionNumber
+ DebugPrint &quot;TraceLevel&quot;, MinimalTraceLevel
+ DebugPrint &quot;TraceCount&quot;, TraceLogCount
+ DebugPrint &quot;CalledSub&quot;, CalledSub
+ If IsArray(CurrentDoc) Then
+ For i = 0 To UBound(CurrentDoc)
+ vCurrentDoc = CurrentDoc(i)
+ If Not IsNull(vCurrentDoc) Then
+ DebugPrint i, &quot;URL&quot;, vCurrentDoc.URL
+ For j = 0 To UBound(vCurrentDoc.DbContainers)
+ DebugPrint i, j, &quot;Form&quot;, vCurrentDoc.DbContainers(j).FormName
+ DebugPrint i, j, &quot;Database&quot;, vCurrentDoc.DbContainers(j).Database.Title
+ Next j
+ End If
+ Next i
+ End If
+
+End Sub
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasItem(psCollType As String, ByVal psName As String) As Boolean
+&apos; Return True if psName if in the collection
+
+Dim oItem As Object
+ On Local Error Goto Error_Function &apos; Whatever ErrorHandler !
+
+ hasItem = True
+ Select Case psCollType
+ Case COLLALLDIALOGS
+ Set oItem = Dialogs.Item(UCase(psName))
+ Case COLLTEMPVARS
+ Set oItem = TempVars.Item(UCase(psName))
+ Case Else
+ hasItem = False
+ End Select
+
+Exit_Function:
+ Exit Function
+Error_Function: &apos; Item by key aborted
+ hasItem = False
+ GoTo Exit_Function
+End Function &apos; hasItem
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CurrentDb(ByVal Optional piDocEntry As Integer, ByVal Optional piDbEntry As Integer) As Variant
+REM Without arguments same as CurrentDb() except that it generates an error if database not connected (internal use)
+REM With 2 arguments return the corresponding entry in Root
+
+Dim odbDatabase As Variant
+ If IsMissing(piDocEntry) Then
+ Set odbDatabase = CurrentDb()
+ Else
+ If Not IsArray(CurrentDoc) Then Goto Trace_Error
+ If piDocEntry &lt; 0 Or piDbEntry &lt; 0 Then Goto Trace_Error
+ If piDocEntry &gt; UBound(CurrentDoc) Then Goto Trace_Error
+ If piDbEntry &gt; UBound(CurrentDoc(piDocEntry).DbContainers) Then Goto Trace_Error
+ Set odbDatabase = CurrentDoc(piDocEntry).DbContainers(piDbEntry).Database
+ End If
+ If IsNull(odbDatabase) Then GoTo Trace_Error
+
+Exit_Function:
+ Set _CurrentDb = odbDatabase
+ Exit Function
+Trace_Error:
+ TraceError(TRACEABORT, ERRDBNOTCONNECTED, Utils._CalledSub(), 0, 1)
+ Goto Exit_Function
+End Function &apos; _CurrentDb
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/SubForm.xba b/wizards/source/access2base/SubForm.xba
new file mode 100644
index 000000000..d905a9836
--- /dev/null
+++ b/wizards/source/access2base/SubForm.xba
@@ -0,0 +1,757 @@
+<?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="SubForm" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be SUBFORM
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Shortcut As String
+Private _Name As String
+Private _MainForm As String
+Private _DocEntry As Integer
+Private _DbEntry As Integer
+Private _OrderBy As String
+Public ParentComponent As Object &apos; com.sun.star.text.TextDocument
+Public DatabaseForm As Object &apos; com.sun.star.form.component.DataForm and com.sun.star.sdb.ResultSet (a.o.)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJSUBFORM
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Shortcut = &quot;&quot;
+ _Name = &quot;&quot;
+ _MainForm = &quot;&quot;
+ _DocEntry = -1
+ _DbEntry = -1
+ _OrderBy = &quot;&quot;
+ Set ParentComponent = Nothing
+ Set DatabaseForm = Nothing
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AllowAdditions() As Variant
+ AllowAdditions = _PropertyGet(&quot;AllowAdditions&quot;)
+End Property &apos; AllowAdditions (get)
+
+Property Let AllowAdditions(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AllowAdditions&quot;, pvValue)
+End Property &apos; AllowAdditions (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AllowDeletions() As Variant
+ AllowDeletions = _PropertyGet(&quot;AllowDeletions&quot;)
+End Property &apos; AllowDeletions (get)
+
+Property Let AllowDeletions(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AllowDeletions&quot;, pvValue)
+End Property &apos; AllowDeletions (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get AllowEdits() As Variant
+ AllowEdits = _PropertyGet(&quot;AllowEdits&quot;)
+End Property &apos; AllowEdits (get)
+
+Property Let AllowEdits(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;AllowEdits&quot;, pvValue)
+End Property &apos; AllowEdits (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get CurrentRecord() As Variant
+ CurrentRecord = _PropertyGet(&quot;CurrentRecord&quot;)
+End Property &apos; CurrentRecord (get)
+
+Property Let CurrentRecord(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;CurrentRecord&quot;, pvValue)
+End Property &apos; CurrentRecord (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Filter() As Variant
+ Filter = _PropertyGet(&quot;Filter&quot;)
+End Property &apos; Filter (get)
+
+Property Let Filter(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Filter&quot;, pvValue)
+End Property &apos; Filter (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get FilterOn() As Variant
+ FilterOn = _PropertyGet(&quot;FilterOn&quot;)
+End Property &apos; FilterOn (get)
+
+Property Let FilterOn(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;FilterOn&quot;, pvValue)
+End Property &apos; FilterOn (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get LinkChildFields(ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvIndex) Then LinkChildFields = _PropertyGet(&quot;LinkChildFields&quot;) Else LinkChildFields = _PropertyGet(&quot;LinkChildFields&quot;, pvIndex)
+End Property &apos; LinkChildFields (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get LinkMasterFields(ByVal Optional pvIndex As Variant) As Variant
+ If IsMissing(pvIndex) Then LinkMasterFields = _PropertyGet(&quot;LinkMasterFields&quot;) Else LinkMasterFields = _PropertyGet(&quot;LinkMasterFields&quot;, pvIndex)
+End Property &apos; LinkMasterFields (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+Public Function pName() As String &apos; For compatibility with &lt; V0.9.0
+ pName = _PropertyGet(&quot;Name&quot;)
+End Function &apos; pName (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveCursorMove() As Variant
+ OnApproveCursorMove = _PropertyGet(&quot;OnApproveCursorMove&quot;)
+End Property &apos; OnApproveCursorMove (get)
+
+Property Let OnApproveCursorMove(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveCursorMove&quot;, pvValue)
+End Property &apos; OnApproveCursorMove (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveParameter() As Variant
+ OnApproveParameter = _PropertyGet(&quot;OnApproveParameter&quot;)
+End Property &apos; OnApproveParameter (get)
+
+Property Let OnApproveParameter(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveParameter&quot;, pvValue)
+End Property &apos; OnApproveParameter (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveReset() As Variant
+ OnApproveReset = _PropertyGet(&quot;OnApproveReset&quot;)
+End Property &apos; OnApproveReset (get)
+
+Property Let OnApproveReset(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveReset&quot;, pvValue)
+End Property &apos; OnApproveReset (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveRowChange() As Variant
+ OnApproveRowChange = _PropertyGet(&quot;OnApproveRowChange&quot;)
+End Property &apos; OnApproveRowChange (get)
+
+Property Let OnApproveRowChange(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveRowChange&quot;, pvValue)
+End Property &apos; OnApproveRowChange (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnApproveSubmit() As Variant
+ OnApproveSubmit = _PropertyGet(&quot;OnApproveSubmit&quot;)
+End Property &apos; OnApproveSubmit (get)
+
+Property Let OnApproveSubmit(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnApproveSubmit&quot;, pvValue)
+End Property &apos; OnApproveSubmit (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnConfirmDelete() As Variant
+ OnConfirmDelete = _PropertyGet(&quot;OnConfirmDelete&quot;)
+End Property &apos; OnConfirmDelete (get)
+
+Property Let OnConfirmDelete(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnConfirmDelete&quot;, pvValue)
+End Property &apos; OnConfirmDelete (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnCursorMoved() As Variant
+ OnCursorMoved = _PropertyGet(&quot;OnCursorMoved&quot;)
+End Property &apos; OnCursorMoved (get)
+
+Property Let OnCursorMoved(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnCursorMoved&quot;, pvValue)
+End Property &apos; OnCursorMoved (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnErrorOccurred() As Variant
+ OnErrorOccurred = _PropertyGet(&quot;OnErrorOccurred&quot;)
+End Property &apos; OnErrorOccurred (get)
+
+Property Let OnErrorOccurred(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnErrorOccurred&quot;, pvValue)
+End Property &apos; OnErrorOccurred (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnLoaded() As Variant
+ OnLoaded = _PropertyGet(&quot;OnLoaded&quot;)
+End Property &apos; OnLoaded (get)
+
+Property Let OnLoaded(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnLoaded&quot;, pvValue)
+End Property &apos; OnLoaded (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnReloaded() As Variant
+ OnReloaded = _PropertyGet(&quot;OnReloaded&quot;)
+End Property &apos; OnReloaded (get)
+
+Property Let OnReloaded(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnReloaded&quot;, pvValue)
+End Property &apos; OnReloaded (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnReloading() As Variant
+ OnReloading = _PropertyGet(&quot;OnReloading&quot;)
+End Property &apos; OnReloading (get)
+
+Property Let OnReloading(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnReloading&quot;, pvValue)
+End Property &apos; OnReloading (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnResetted() As Variant
+ OnResetted = _PropertyGet(&quot;OnResetted&quot;)
+End Property &apos; OnResetted (get)
+
+Property Let OnResetted(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnResetted&quot;, pvValue)
+End Property &apos; OnResetted (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnRowChanged() As Variant
+ OnRowChanged = _PropertyGet(&quot;OnRowChanged&quot;)
+End Property &apos; OnRowChanged (get)
+
+Property Let OnRowChanged(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnRowChanged&quot;, pvValue)
+End Property &apos; OnRowChanged (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUnloaded() As Variant
+ OnUnloaded = _PropertyGet(&quot;OnUnloaded&quot;)
+End Property &apos; OnUnloaded (get)
+
+Property Let OnUnloaded(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnUnloaded&quot;, pvValue)
+End Property &apos; OnUnloaded (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OnUnloading() As Variant
+ OnUnloading = _PropertyGet(&quot;OnUnloading&quot;)
+End Property &apos; OnUnloading (get)
+
+Property Let OnUnloading(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OnUnloading&quot;, pvValue)
+End Property &apos; OnUnloading (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function OptionGroup(ByVal Optional pvGroupName As Variant) As Variant
+&apos; Return either an error or an object of type OPTIONGROUP based on its name
+
+Const cstThisSub = &quot;SubForm.OptionGroup&quot;
+Dim ogGroup As Object
+ Utils._SetCalledSub(cstThisSub)
+ If IsMissing(pvGroupName) Then Call _TraceArguments()
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ Set ogGroup = _OptionGroup(pvGroupName, CTLPARENTISSUBFORM, ParentComponent, DatabaseForm)
+ If Not IsNull(ogGroup) Then
+ ogGroup._DocEntry = _DocEntry
+ ogGroup._DbEntry = _DbEntry
+ End If
+ Set OptionGroup = ogGroup
+
+Exit_Function:
+ Utils._ResetCalledSub(cstThisSub)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, cstThisSub, Erl)
+ GoTo Exit_Function
+End Function &apos; OptionGroup V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OrderBy() As Variant
+ OrderBy = _PropertyGet(&quot;OrderBy&quot;)
+End Property &apos; OrderBy (get) V1.2.0
+
+Property Let OrderBy(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OrderBy&quot;, pvValue)
+End Property &apos; OrderBy (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get OrderByOn() As Variant
+ OrderByOn = _PropertyGet(&quot;OrderByOn&quot;)
+End Property &apos; OrderByOn (get) V1.2.0
+
+Property Let OrderByOn(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;OrderByOn&quot;, pvValue)
+End Property &apos; OrderByOn (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Parent() As Object
+
+ Utils._SetCalledSub(&quot;SubForm.getParent&quot;)
+ On Error Goto Error_Function
+
+ Set Parent = _Parent
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SubForm.getParent&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm.getParent&quot;, Erl)
+ Set Parent = Nothing
+ GoTo Exit_Function
+End Function &apos; Parent
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Recordset() As Object
+ Recordset = _PropertyGet(&quot;Recordset&quot;)
+End Property &apos; Recordset (get) V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get RecordSource() As Variant
+ RecordSource = _PropertyGet(&quot;RecordSource&quot;)
+End Property &apos; RecordSource (get)
+
+Property Let RecordSource(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;RecordSource&quot;, pvValue)
+End Property &apos; RecordSource (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Controls(Optional ByVal pvIndex As Variant) As Variant
+&apos; Return a Control object with name or index = pvIndex
+
+If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;SubForm.Controls&quot;)
+
+Dim ocControl As Variant, sParentShortcut As String, iControlCount As Integer
+Dim oCounter As Variant, sControls() As Variant, i As Integer, bFound As Boolean, sIndex As String
+Dim j As Integer
+
+ Set ocControl = Nothing
+ iControlCount = DatabaseForm.getCount()
+
+ If IsMissing(pvIndex) Then &apos; No argument, return Collection pseudo-object
+ Set oCounter = New Collect
+ Set oCounter._This = oCounter
+ oCounter._CollType = COLLCONTROLS
+ oCounter._Parent = _This
+ oCounter._Count = iControlCount
+ Set Controls = oCounter
+ Goto Exit_Function
+ End If
+
+ If Not Utils._CheckArgument(pvIndex, 1, Utils._AddNumeric(vbString)) Then Goto Exit_Function
+
+ &apos; Start building the ocControl object
+ &apos; Determine exact name
+ Set ocControl = New Control
+ Set ocControl._This = ocControl
+ Set ocControl._Parent = _This
+ ocControl._ParentType = CTLPARENTISSUBFORM
+ sParentShortcut = _Shortcut
+ sControls() = DatabaseForm.getElementNames()
+
+ Select Case VarType(pvIndex)
+ Case vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal
+ If pvIndex &lt; 0 Or pvIndex &gt; iControlCount - 1 Then Goto Trace_Error_Index
+ ocControl._Name = sControls(pvIndex)
+ Case vbString &apos; Check control name validity (non case sensitive)
+ bFound = False
+ sIndex = UCase(Utils._Trim(pvIndex))
+ For i = 0 To iControlCount - 1
+ If UCase(sControls(i)) = sIndex Then
+ bFound = True
+ Exit For
+ End If
+ Next i
+ If bFound Then ocControl._Name = sControls(i) Else Goto Trace_NotFound
+ End Select
+
+ With ocControl
+ ._Shortcut = sParentShortcut &amp; &quot;!&quot; &amp; Utils._Surround(._Name)
+ Set .ControlModel = DatabaseForm.getByName(._Name)
+ ._ImplementationName = .ControlModel.getImplementationName()
+ ._FormComponent = ParentComponent
+ If Utils._hasUNOProperty(.ControlModel, &quot;ClassId&quot;) Then ._ClassId = .ControlModel.ClassId
+ If ._ClassId &gt; 0 And ._ClassId &lt;&gt; acHiddenControl Then
+ Set .ControlView = ParentComponent.CurrentController.getControl(.ControlModel)
+ End If
+
+ ._Initialize()
+ ._DocEntry = _DocEntry
+ ._DbEntry = _DbEntry
+ End With
+ Set Controls = ocControl
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SubForm.Controls&quot;)
+ Exit Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRCOLLECTION, Utils._CalledSub(), 0, 1)
+ Set Controls = Nothing
+ Goto Exit_Function
+Trace_NotFound:
+ TraceError(TRACEFATAL, ERRCONTROLNOTFOUND, Utils._CalledSub(), 0, , Array(pvIndex, _Name))
+ Set Controls = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm.Controls&quot;, Erl)
+ Set Controls = Nothing
+ GoTo Exit_Function
+End Function &apos; Controls V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;SubForm.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;SubForm.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Refresh() As Boolean
+&apos; Refresh data with its most recent value in the database in a form or subform
+ Utils._SetCalledSub(&quot;SubForm.Refresh&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Refresh = False
+
+Dim oSet As Object
+ Set oSet = DatabaseForm.createResultSet()
+ If Not IsNull(oSet) Then
+ oSet.refreshRow()
+ Refresh = True
+ End If
+
+Exit_Function:
+ Set oSet = Nothing
+ Utils._ResetCalledSub(&quot;SubForm.Refresh&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm.Refresh&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Refresh
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Requery() As Boolean
+&apos; Refresh data displayed in a form, subform, combobox or listbox
+ Utils._SetCalledSub(&quot;SubForm.Requery&quot;)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Requery = False
+
+ DatabaseForm.reload()
+ Requery = True
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SubForm.Requery&quot;)
+ Exit Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm.Requery&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; Requery
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;SubForm.setProperty&quot;)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(&quot;SubForm.setProperty&quot;)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private Function _GetListener(ByVal psProperty As String) As String
+&apos; Return the X...Listener corresponding with the property in argument
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;OnApproveCursorMove&quot;)
+ _GetListener = &quot;XRowSetApproveListener&quot;
+ Case UCase(&quot;OnApproveParameter&quot;)
+ _GetListener = &quot;XDatabaseParameterListener&quot;
+ Case UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnResetted&quot;)
+ _GetListener = &quot;XResetListener&quot;
+ Case UCase(&quot;OnApproveRowChange&quot;)
+ _GetListener = &quot;XRowSetApproveListener&quot;
+ Case UCase(&quot;OnApproveSubmit&quot;)
+ _GetListener = &quot;XSubmitListener&quot;
+ Case UCase(&quot;OnConfirmDelete&quot;)
+ _GetListener = &quot;XConfirmDeleteListener&quot;
+ Case UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnRowChanged&quot;)
+ _GetListener = &quot;XRowSetListener&quot;
+ Case UCase(&quot;OnErrorOccurred&quot;)
+ _GetListener = &quot;XSQLErrorListener&quot;
+ Case UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ _GetListener = &quot;XLoadListener&quot;
+ End Select
+
+End Function &apos; _GetListener V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+
+ _PropertiesList = Array(&quot;AllowAdditions&quot;, &quot;AllowDeletions&quot;, &quot;AllowEdits&quot;, &quot;CurrentRecord&quot; _
+ , &quot;Filter&quot;, &quot;FilterOn&quot;, &quot;LinkChildFields&quot;, &quot;LinkMasterFields&quot;, &quot;Name&quot; _
+ , &quot;ObjectType&quot;, &quot;OnApproveCursorMove&quot;, &quot;OnApproveParameter&quot; _
+ , &quot;OnApproveReset&quot;, &quot;OnApproveRowChange&quot;, &quot;OnApproveSubmit&quot;, &quot;OnConfirmDelete&quot; _
+ , &quot;OnCursorMoved&quot;, &quot;OnErrorOccurred&quot;, &quot;OnLoaded&quot;, &quot;OnReloaded&quot;, &quot;OnReloading&quot; _
+ , &quot;OnResetted&quot;, &quot;OnRowChanged&quot;, &quot;OnUnloaded&quot;, &quot;OnUnloading&quot;, &quot;OrderBy&quot; _
+ , &quot;OrderByOn&quot;, &quot;Parent&quot;, &quot;RecordSource&quot; _
+ ) &apos; Recordset removed
+
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String, ByVal Optional pvIndex As Variant) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;SubForm.get&quot; &amp; psProperty)
+Dim iArgNr As Integer
+ If Not IsMissing(pvIndex) Then
+ Select Case UCase(_A2B_.CalledSub)
+ Case UCase(&quot;getProperty&quot;) : iArgNr = 3
+ Case UCase(&quot;SubForm.getProperty&quot;) : iArgNr = 2
+ Case UCase(&quot;SubForm.get&quot; &amp; psProperty) : iArgNr = 1
+ End Select
+ If Not Utils._CheckArgument(pvIndex, iArgNr, Utils._AddNumeric()) Then Goto Exit_Function
+ End If
+
+&apos;Execute
+Dim oDatabase As Object, vBookmark As Variant, oObject As Object
+ _PropertyGet = EMPTY
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AllowAdditions&quot;)
+ _PropertyGet = DatabaseForm.AllowInserts
+ Case UCase(&quot;AllowDeletions&quot;)
+ _PropertyGet = DatabaseForm.AllowDeletes
+ Case UCase(&quot;AllowEdits&quot;)
+ _PropertyGet = DatabaseForm.AllowUpdates
+ Case UCase(&quot;CurrentRecord&quot;)
+ _PropertyGet = DatabaseForm.Row
+ Case UCase(&quot;Filter&quot;)
+ _PropertyGet = DatabaseForm.Filter
+ Case UCase(&quot;FilterOn&quot;)
+ _PropertyGet = DatabaseForm.ApplyFilter
+ Case UCase(&quot;LinkChildFields&quot;)
+ If Utils._hasUNOProperty(DatabaseForm, &quot;DetailFields&quot;) Then
+ If IsMissing(pvIndex) Then
+ _PropertyGet = DatabaseForm.DetailFields
+ Else
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(DatabaseForm.DetailFields) Then Goto trace_Error_Index
+ _PropertyGet = DatabaseForm.DetailFields(pvIndex)
+ End If
+ End If
+ Case UCase(&quot;LinkMasterFields&quot;)
+ If Utils._hasUNOProperty(DatabaseForm, &quot;MasterFields&quot;) Then
+ If IsMissing(pvIndex) Then
+ _PropertyGet = DatabaseForm.MasterFields
+ Else
+ If pvIndex &lt; 0 Or pvIndex &gt; UBound(DatabaseForm.MasterFields) Then Goto trace_Error_Index
+ _PropertyGet = DatabaseForm.MasterFields(pvIndex)
+ End If
+ End If
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;OnApproveCursorMove&quot;), UCase(&quot;OnApproveParameter&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveRowChange&quot;) _
+ , UCase(&quot;OnApproveSubmit&quot;), UCase(&quot;OnConfirmDelete&quot;), UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnErrorOccurred&quot;) _
+ , UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnRowChanged&quot;) _
+ , UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ _PropertyGet = Utils._GetEventScriptCode(DatabaseForm, psProperty, _Name)
+ Case UCase(&quot;OrderBy&quot;)
+ _PropertyGet = _OrderBy
+ Case UCase(&quot;OrderByOn&quot;)
+ If DatabaseForm.Order = &quot;&quot; Then _PropertyGet = False Else _PropertyGet = True
+ Case UCase(&quot;Parent&quot;) &apos; Only for indirect access from property object
+ _PropertyGet = Parent
+ Case UCase(&quot;Recordset&quot;)
+ If DatabaseForm.Command = &quot;&quot; Then Goto Trace_Error &apos; No underlying data ??
+ Set oObject = New Recordset
+ With DatabaseForm
+ Set oObject._This = oObject
+ oObject._CommandType = .CommandType
+ oObject._Command = .Command
+ oObject._ParentName = _Name
+ oObject._ParentType = _Type
+ Set oDatabase = Application._CurrentDb(_DocEntry, _DbEntry)
+ Set oObject._ParentDatabase = oDatabase
+ Set oObject._ParentDatabase.Connection = .ActiveConnection
+ oObject._ForwardOnly = ( .ResultSetType = com.sun.star.sdbc.ResultSetType.FORWARD_ONLY )
+ oObject._PassThrough = ( .EscapeProcessing = False )
+ oObject._ReadOnly = ( .ResultSetConcurrency = com.sun.star.sdbc.ResultSetConcurrency.READ_ONLY )
+ Call oObject._Initialize()
+ End With
+ With oDatabase
+ .RecordsetMax = .RecordsetMax + 1
+ oObject._Name = Format(.RecordsetMax, &quot;0000000&quot;)
+ .RecordsetsColl.Add(oObject, UCase(oObject._Name))
+ End With
+ Set _PropertyGet = oObject
+ Case UCase(&quot;RecordSource&quot;)
+ _PropertyGet = DatabaseForm.Command
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SubForm.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEWARNING, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Trace_Error_Index:
+ TraceError(TRACEFATAL, ERRINDEXVALUE, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = EMPTY
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm._PropertyGet&quot;, Erl)
+ _PropertyGet = EMPTY
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+
+ Utils._SetCalledSub(&quot;SubForm.set&quot; &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _PropertySet = True
+
+&apos;Execute
+Dim iArgNr As Integer
+
+ If _IsLeft(_A2B_.CalledSub, &quot;SubForm.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AllowAdditions&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ DatabaseForm.AllowInserts = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;AllowDeletions&quot;)
+ If Not Utils._CheckArgument(pvValue,iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ DatabaseForm.AllowDeletes = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;AllowEdits&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ DatabaseForm.AllowUpdates = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;CurrentRecord&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, Utils._AddNumeric(), , False) Then Goto Trace_Error_Value
+ DatabaseForm.absolute(pvValue)
+ Case UCase(&quot;Filter&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ DatabaseForm.Filter = Application._CurrentDb(_DocEntry, _DbEntry)._ReplaceSquareBrackets(pvValue)
+ Case UCase(&quot;FilterOn&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ DatabaseForm.ApplyFilter = pvValue
+ DatabaseForm.reload()
+ Case UCase(&quot;OnApproveCursorMove&quot;), UCase(&quot;OnApproveParameter&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveRowChange&quot;) _
+ , UCase(&quot;OnApproveSubmit&quot;), UCase(&quot;OnConfirmDelete&quot;), UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnErrorOccurred&quot;) _
+ , UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnRowChanged&quot;) _
+ , UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ If Not Utils._RegisterEventScript(DatabaseForm _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue, _Name _
+ ) Then GoTo Trace_Error
+ Case UCase(&quot;OrderBy&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ _OrderBy = Application._CurrentDb(_DocEntry, _DbEntry)._ReplaceSquareBrackets(pvValue)
+ Case UCase(&quot;OrderByOn&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbBoolean, , False) Then Goto Trace_Error_Value
+ If pvValue Then DatabaseForm.Order = _OrderBy Else DatabaseForm.Order = &quot;&quot;
+ DatabaseForm.reload()
+ Case UCase(&quot;RecordSource&quot;)
+ If Not Utils._CheckArgument(pvValue, iArgNr, vbString, , False) Then Goto Trace_Error_Value
+ DatabaseForm.Command = Application._CurrentDb(_DocEntry, _DbEntry)._ReplaceSquareBrackets(pvValue)
+ DatabaseForm.CommandType = com.sun.star.sdb.CommandType.COMMAND
+ DatabaseForm.Filter = &quot;&quot;
+ DatabaseForm.reload()
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;SubForm.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;SubForm._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/TempVar.xba b/wizards/source/access2base/TempVar.xba
new file mode 100644
index 000000000..d600de3b2
--- /dev/null
+++ b/wizards/source/access2base/TempVar.xba
@@ -0,0 +1,195 @@
+<?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="TempVar" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS ROOT FIELDS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private _Type As String &apos; Must be TEMPVAR
+Private _This As Object &apos; Workaround for absence of This builtin function
+Private _Parent As Object
+Private _Name As String
+Private _Value As Variant
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CONSTRUCTORS / DESTRUCTORS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ _Type = OBJTEMPVAR
+ Set _This = Nothing
+ Set _Parent = Nothing
+ _Name = &quot;&quot;
+ _Value = Null
+End Sub &apos; Constructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ On Local Error Resume Next
+ Call Class_Initialize()
+End Sub &apos; Destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub Dispose()
+ Call Class_Terminate()
+End Sub &apos; Explicit destructor
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS GET/LET/SET PROPERTIES ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Property Get Name() As String
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; Name (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get ObjectType() As String
+ ObjectType = _PropertyGet(&quot;ObjectType&quot;)
+End Property &apos; ObjectType (get)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Property Get Value() As Variant
+ Value = _PropertyGet(&quot;Value&quot;)
+End Property &apos; Value (get)
+
+Property Let Value(ByVal pvValue As Variant)
+ Call _PropertySet(&quot;Value&quot;, pvValue)
+End Property &apos; Value (set)
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- CLASS METHODS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function getProperty(Optional ByVal pvProperty As Variant) As Variant
+&apos; Return property value of psProperty property name
+
+ Utils._SetCalledSub(&quot;TempVar.getProperty&quot;)
+ If IsMissing(pvProperty) Then Call _TraceArguments()
+ getProperty = _PropertyGet(pvProperty)
+ Utils._ResetCalledSub(&quot;TempVar.getProperty&quot;)
+
+End Function &apos; getProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function hasProperty(ByVal Optional pvProperty As Variant) As Boolean
+&apos; Return True if object has a valid property called pvProperty (case-insensitive comparison !)
+
+ If IsMissing(pvProperty) Then hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList()) Else hasProperty = PropertiesGet._hasProperty(_Type, _PropertiesList(), pvProperty)
+ Exit Function
+
+End Function &apos; hasProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function Properties(ByVal Optional pvIndex As Variant) As Variant
+&apos; Return
+&apos; a Collection object if pvIndex absent
+&apos; a Property object otherwise
+
+Dim vProperty As Variant, vPropertiesList() As Variant, sObject As String
+ vPropertiesList = _PropertiesList()
+ sObject = Utils._PCase(_Type)
+ If IsMissing(pvIndex) Then
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList)
+ Else
+ vProperty = PropertiesGet._Properties(sObject, _This, vPropertiesList, pvIndex)
+ vProperty._Value = _PropertyGet(vPropertiesList(pvIndex))
+ End If
+
+Exit_Function:
+ Set Properties = vProperty
+ Exit Function
+End Function &apos; Properties
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function setProperty(ByVal Optional psProperty As String, ByVal Optional pvValue As Variant) As Boolean
+&apos; Return True if property setting OK
+ Utils._SetCalledSub(&quot;TempVar.getProperty&quot;)
+ setProperty = _PropertySet(psProperty, pvValue)
+ Utils._ResetCalledSub(&quot;TempVar.getProperty&quot;)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertiesList() As Variant
+ _PropertiesList = Array(&quot;Name&quot;, &quot;ObjectType&quot;, &quot;Value&quot;)
+End Function &apos; _PropertiesList
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertyGet(ByVal psProperty As String) As Variant
+&apos; Return property value of the psProperty property name
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ Utils._SetCalledSub(&quot;TempVar.get&quot; &amp; psProperty)
+ _PropertyGet = Nothing
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;ObjectType&quot;)
+ _PropertyGet = _Type
+ Case UCase(&quot;Value&quot;)
+ _PropertyGet = _Value
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;TempVar.get&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertyGet = Nothing
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;TempVar._PropertyGet&quot;, Erl)
+ _PropertyGet = Nothing
+ GoTo Exit_Function
+End Function &apos; _PropertyGet
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PropertySet(ByVal psProperty As String, ByVal pvValue As Variant) As Boolean
+
+ Utils._SetCalledSub(&quot;TempVar.set&quot; &amp; psProperty)
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+ _PropertySet = True
+
+&apos;Execute
+Dim iArgNr As Integer
+
+ If _IsLeft(_A2B_.CalledSub, &quot;TempVar.&quot;) Then iArgNr = 1 Else iArgNr = 2
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Value&quot;)
+ _Value = pvValue
+ _A2B_.TempVars.Item(UCase(_Name)).Value = pvValue
+ Case Else
+ Goto Trace_Error
+ End Select
+
+Exit_Function:
+ Utils._ResetCalledSub(&quot;TempVar.set&quot; &amp; psProperty)
+ Exit Function
+Trace_Error:
+ TraceError(TRACEFATAL, ERRPROPERTY, Utils._CalledSub(), 0, 1, psProperty)
+ _PropertySet = False
+ Goto Exit_Function
+Trace_Error_Value:
+ TraceError(TRACEFATAL, ERRPROPERTYVALUE, Utils._CalledSub(), 0, 1, Array(pvValue, psProperty))
+ _PropertySet = False
+ Goto Exit_Function
+Error_Function:
+ TraceError(TRACEABORT, Err, &quot;TempVar._PropertySet&quot;, Erl)
+ _PropertySet = False
+ GoTo Exit_Function
+End Function &apos; _PropertySet
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Test.xba b/wizards/source/access2base/Test.xba
new file mode 100644
index 000000000..7ad95904e
--- /dev/null
+++ b/wizards/source/access2base/Test.xba
@@ -0,0 +1,14 @@
+<?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="Test" script:language="StarBasic">Option Explicit
+&apos;Option Compatible
+
+Sub Main
+Dim a, b()
+ _ErrorHandler(False)
+&apos; DebugPrint vbLF
+&apos; TraceConsole()
+ exit sub
+End Sub
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Trace.xba b/wizards/source/access2base/Trace.xba
new file mode 100644
index 000000000..041bea532
--- /dev/null
+++ b/wizards/source/access2base/Trace.xba
@@ -0,0 +1,438 @@
+<?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="Trace" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+Public Const cstLogMaxEntries = 99
+
+REM Typical Usage
+REM TraceLog(&quot;INFO&quot;, &quot;The OK button was pressed&quot;)
+REM
+REM Typical Usage for error logging
+REM Sub MySub()
+REM On Local Error GoTo Error_Sub
+REM ...
+REM Exit_Sub:
+REM Exit Sub
+REM Error_Sub:
+REM TraceError(&quot;ERROR&quot;, Err, &quot;MySub&quot;, Erl)
+REM GoTo Exit_Sub
+REM End Sub
+REM
+REM To display the current logged traces and/or to set parameters
+REM TraceConsole()
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub TraceConsole()
+&apos; Display the Trace dialog with current trace log values and parameter choices
+ If _ErrorHandler() Then On Local Error Goto Error_Sub
+
+Dim sLineBreak As String, oTraceDialog As Object
+ sLineBreak = vbNewLine
+
+ Set oTraceDialog = CreateUnoDialog(Utils._GetDialogLib().dlgTrace)
+ oTraceDialog.Title = _GetLabel(&quot;DLGTRACE_TITLE&quot;)
+ oTraceDialog.Model.HelpText = _GetLabel(&quot;DLGTRACE_HELP&quot;)
+
+Dim oEntries As Object, oTraceLog As Object, oClear As Object, oMinLevel As Object, oNbEntries As Object, oDump As Object
+Dim oControl As Object
+Dim i As Integer, sText As String, iOKCancel As Integer
+
+ Set oNbEntries = oTraceDialog.Model.getByName(&quot;numNbEntries&quot;)
+ oNbEntries.Value = _A2B_.TraceLogCount
+ oNbEntries.HelpText = _GetLabel(&quot;DLGTRACE_LBLNBENTRIES_HELP&quot;)
+
+ Set oControl = oTraceDialog.Model.getByName(&quot;lblNbEntries&quot;)
+ oControl.Label = _GetLabel(&quot;DLGTRACE_LBLNBENTRIES_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGTRACE_LBLNBENTRIES_HELP&quot;)
+
+ Set oEntries = oTraceDialog.Model.getByName(&quot;numEntries&quot;)
+ If _A2B_.TraceLogMaxEntries = 0 Then _A2B_.TraceLogMaxEntries = cstLogMaxEntries
+ oEntries.Value = _A2B_.TraceLogMaxEntries
+ oEntries.HelpText = _GetLabel(&quot;DLGTRACE_LBLENTRIES_HELP&quot;)
+
+ Set oControl = oTraceDialog.Model.getByName(&quot;lblEntries&quot;)
+ oControl.Label = _GetLabel(&quot;DLGTRACE_LBLENTRIES_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGTRACE_LBLENTRIES_HELP&quot;)
+
+ Set oDump = oTraceDialog.Model.getByName(&quot;cmdDump&quot;)
+ oDump.Enabled = 0
+ oDump.Label = _GetLabel(&quot;DLGTRACE_CMDDUMP_LABEL&quot;)
+ oDump.HelpText = _GetLabel(&quot;DLGTRACE_CMDDUMP_HELP&quot;)
+
+ Set oTraceLog = oTraceDialog.Model.getByName(&quot;txtTraceLog&quot;)
+ oTraceLog.HelpText = _GetLabel(&quot;DLGTRACE_TXTTRACELOG_HELP&quot;)
+ If UBound(_A2B_.TraceLogs) &gt;= 0 Then &apos; Array yet initialized
+ oTraceLog.HardLineBreaks = True
+ sText = &quot;&quot;
+ If _A2B_.TraceLogCount &gt; 0 Then
+ If _A2B_.TraceLogCount &lt; _A2B_.TraceLogMaxEntries Then i = -1 Else i = _A2B_.TraceLogLast
+ Do
+ If i &lt; _A2B_.TraceLogMaxEntries - 1 Then i = i + 1 Else i = 0
+ If Len(_A2B_.TraceLogs(i)) &gt; 11 Then
+ sText = sText &amp; Right(_A2B_.TraceLogs(i), Len(_A2B_.TraceLogs(i)) - 11) &amp; sLineBreak &apos; Skip date in display
+ End If
+ Loop While i &lt;&gt; _A2B_.TraceLogLast
+ oDump.Enabled = 1 &apos; Enable DumpToFile only if there is something to dump
+ End If
+ If Len(sText) &gt; 0 Then sText = Left(sText, Len(sText) - Len(sLineBreak)) &apos; Skip last linefeed
+ oTraceLog.Text = sText
+ Else
+ oTraceLog.Text = _GetLabel(&quot;DLGTRACE_TXTTRACELOG_TEXT&quot;)
+ End If
+
+ Set oClear = oTraceDialog.Model.getByName(&quot;chkClear&quot;)
+ oClear.State = 0 &apos; Unchecked
+ oClear.HelpText = _GetLabel(&quot;DLGTRACE_LBLCLEAR_HELP&quot;)
+
+ Set oControl = oTraceDialog.Model.getByName(&quot;lblClear&quot;)
+ oControl.Label = _GetLabel(&quot;DLGTRACE_LBLCLEAR_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGTRACE_LBLCLEAR_HELP&quot;)
+
+ Set oMinLevel = oTraceDialog.Model.getByName(&quot;cboMinLevel&quot;)
+ If _A2B_.MinimalTraceLevel = 0 Then _A2B_.MinimalTraceLevel = _TraceLevel(TRACEERRORS)
+ oMinLevel.Text = _TraceLevel(_A2B_.MinimalTraceLevel)
+ oMinLevel.HelpText = _GetLabel(&quot;DLGTRACE_LBLMINLEVEL_HELP&quot;)
+
+ Set oControl = oTraceDialog.Model.getByName(&quot;lblMinLevel&quot;)
+ oControl.Label = _GetLabel(&quot;DLGTRACE_LBLMINLEVEL_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGTRACE_LBLMINLEVEL_HELP&quot;)
+
+ Set oControl = oTraceDialog.Model.getByName(&quot;cmdOK&quot;)
+ oControl.Label = _GetLabel(&quot;DLGTRACE_CMDOK_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGTRACE_CMDOK_HELP&quot;)
+
+ Set oControl = oTraceDialog.Model.getByName(&quot;cmdCancel&quot;)
+ oControl.Label = _GetLabel(&quot;DLGTRACE_CMDCANCEL_LABEL&quot;)
+ oControl.HelpText = _GetLabel(&quot;DLGTRACE_CMDCANCEL_HELP&quot;)
+
+ iOKCancel = oTraceDialog.Execute()
+
+ Select Case iOKCancel
+ Case 1 &apos; OK
+ If oClear.State = 1 Then
+ _A2B_.TraceLogs() = Array() &apos; Erase logged traces
+ _A2B_.TraceLogCount = 0
+ End If
+ If oMinLevel.Text &lt;&gt; &quot;&quot; Then _A2B_.MinimalTraceLevel = _TraceLevel(oMinLevel.Text)
+ If oEntries.Value &lt;&gt; 0 And oEntries.Value &lt;&gt; _A2B_.TraceLogMaxEntries Then
+ _A2B_.TraceLogs() = Array()
+ _A2B_.TraceLogMaxEntries = oEntries.Value
+ End If
+ Case 0 &apos; Cancel
+ Case Else
+ End Select
+
+Exit_Sub:
+ If Not IsNull(oTraceDialog) Then oTraceDialog.Dispose()
+ Exit Sub
+Error_Sub:
+ With _A2B_
+ .TraceLogs() = Array()
+ .TraceLogCount = 0
+ .TraceLogLast = 0
+ End With
+ GoTo Exit_Sub
+End Sub &apos; TraceConsole V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub TraceError(ByVal psErrorLevel As String _
+ , ByVal piErrorCode As Integer _
+ , ByVal psErrorProc As String _
+ , ByVal piErrorLine As Integer _
+ , ByVal Optional pvMsgBox As Variant _
+ , ByVal Optional pvArgs As Variant _
+ )
+&apos; Store error code and description in trace rolling buffer
+&apos; Display error message if errorlevel &gt;= ERROR
+&apos; Stop program execution if errorlevel = FATAL or ABORT
+
+ On Local Error Resume Next
+ If IsEmpty(_A2B_) Then Call Application._RootInit() &apos; First use of Access2Base in current LibO/AOO session
+
+Dim sErrorText As String, sErrorDesc As String, oDb As Object, bMsgBox As Boolean
+ sErrorDesc = _ErrorMessage(piErrorCode, pvArgs)
+ sErrorText = _GetLabel(&quot;ERR#&quot;) &amp; CStr(piErrorCode) _
+ &amp; &quot; (&quot; &amp; sErrorDesc &amp; &quot;) &quot; &amp; _GetLabel(&quot;ERROCCUR&quot;) _
+ &amp; Iif(piErrorLine &gt; 0, &quot; &quot; &amp; _GetLabel(&quot;ERRLINE&quot;) &amp; &quot; &quot; &amp; CStr(piErrorLine), &quot;&quot;) _
+ &amp; Iif(psErrorProc &lt;&gt; &quot;&quot;, &quot; &quot; &amp; _GetLabel(&quot;ERRIN&quot;) &amp; &quot; &quot; &amp; psErrorProc, Iif(_A2B_.CalledSub = &quot;&quot;, &quot;&quot;, &quot; &quot; &amp; _Getlabel(&quot;ERRIN&quot;) &amp; &quot; &quot; &amp; _A2B_.CalledSub))
+ With _A2B_
+ .LastErrorCode = piErrorCode
+ .LastErrorLevel = psErrorLevel
+ .ErrorText = sErrorDesc
+ .ErrorLongText = sErrorText
+ .CalledSub = &quot;&quot;
+ End With
+ If VarType(pvMsgBox) = vbError Then
+ bMsgBox = ( psErrorLevel = TRACEERRORS Or psErrorLevel = TRACEFATAL Or psErrorLevel = TRACEABORT )
+ ElseIf IsMissing(pvMsgBox) Then
+ bMsgBox = ( psErrorLevel = TRACEERRORS Or psErrorLevel = TRACEFATAL Or psErrorLevel = TRACEABORT )
+ Else
+ bMsgBox = pvMsgBox
+ End If
+ TraceLog(psErrorLevel, sErrorText, bMsgBox)
+
+ &apos; Unexpected error detected in user program or in Access2Base
+ If psErrorLevel = TRACEFATAL Or psErrorLevel = TRACEABORT Then
+ If psErrorLevel = TRACEFATAL Then
+ Set oDb = _A2B_.CurrentDb()
+ If Not IsNull(oDb) Then oDb.CloseAllrecordsets()
+ End If
+ Stop
+ End If
+
+End Sub &apos; TraceError V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function TraceErrorCode() As Variant
+&apos; Return the last encountered error code, level, description in an array
+&apos; UNPUBLISHED
+
+Dim vError As Variant
+
+ With _A2B_
+ vError = Array( _
+ .LastErrorCode _
+ , .LastErrorLevel _
+ , .ErrorText _
+ , .ErrorLongText _
+ )
+ End With
+ TraceErrorCode = vError
+
+End Function &apos; TraceErrorCode V6.3
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub TraceLevel(ByVal Optional psTraceLevel As String)
+&apos; Set trace level to argument
+
+ If _ErrorHandler() Then On Local Error Goto Error_Sub
+ Select Case True
+ Case IsMissing(psTraceLevel) : psTraceLevel = &quot;ERROR&quot;
+ Case psTraceLevel = &quot;&quot; : psTraceLevel = &quot;ERROR&quot;
+ Case Utils._InList(UCase(psTraceLevel), Array( _
+ TRACEDEBUG, TRACEINFO, TRACEWARNING, TRACEERRORS, TRACEFATAL, TRACEABORT _
+ ))
+ Case Else : Goto Exit_Sub
+ End Select
+ _A2B_.MinimalTraceLevel = _TraceLevel(psTraceLevel)
+
+Exit_Sub:
+ Exit Sub
+Error_Sub:
+ With _A2B_
+ .TraceLogs() = Array()
+ .TraceLogCount = 0
+ .TraceLogLast = 0
+ End With
+ GoTo Exit_Sub
+End Sub &apos; TraceLevel V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub TraceLog(ByVal psTraceLevel As String _
+ , ByVal psText As String _
+ , ByVal Optional pbMsgBox As Boolean _
+ )
+&apos; Store Text in trace log (circular buffer)
+
+ If _ErrorHandler() Then On Local Error Goto Error_Sub
+Dim vTraceLogs() As String, sTraceLevel As String
+
+ With _A2B_
+ If .MinimalTraceLevel = 0 Then .MinimalTraceLevel = _TraceLevel(TRACEERRORS)
+ If _TraceLevel(psTraceLevel) &lt; .MinimalTraceLevel Then Exit Sub
+
+ If UBound(.TraceLogs) = -1 Then &apos; Initialize TraceLog
+ If .TraceLogMaxEntries = 0 Then .TraceLogMaxEntries = cstLogMaxEntries
+
+ Redim vTraceLogs(0 To .TraceLogMaxEntries - 1)
+ .TraceLogs = vTraceLogs
+ .TraceLogCount = 0
+ .TraceLogLast = -1
+ If .MinimalTraceLevel = 0 Then .MinimalTraceLevel = _TraceLevel(TRACEERRORS) &apos; Set default value
+ End If
+
+ .TraceLogLast = .TraceLogLast + 1
+ If .TraceLogLast &gt; UBound(.TraceLogs) Then .TraceLogLast = LBound(.TraceLogs) &apos; Circular buffer
+ If Len(psTraceLevel) &gt; 7 Then sTraceLevel = Left(psTraceLevel, 7) Else sTraceLevel = psTraceLevel &amp; Spc(8 - Len(psTraceLevel))
+ .TraceLogs(.TraceLogLast) = Format(Now(), &quot;YYYY-MM-DD hh:mm:ss&quot;) &amp; &quot; &quot; &amp; sTraceLevel &amp; psText
+ If .TraceLogCount &lt;= UBound(.TraceLogs) Then .TraceLogCount = .TraceLogCount + 1 &apos; # of active entries
+ End With
+
+ If IsMissing(pbMsgBox) Then pbMsgBox = True
+Dim iMsgBox As Integer
+ If pbMsgBox Then
+ Select Case psTraceLevel
+ Case TRACEINFO: iMsgBox = vbInformation
+ Case TRACEERRORS, TRACEWARNING: iMsgBox = vbExclamation
+ Case TRACEFATAL, TRACEABORT: iMsgBox = vbCritical
+ Case Else: iMsgBox = vbInformation
+ End Select
+ MsgBox psText, vbOKOnly + iMsgBox, psTraceLevel
+ End If
+
+Exit_Sub:
+ Exit Sub
+Error_Sub:
+ With _A2B_
+ .TraceLogs() = Array()
+ .TraceLogCount = 0
+ .TraceLogLast = 0
+ End With
+ GoTo Exit_Sub
+End Sub &apos; TraceLog V0.9.5
+
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Private Sub _DumpToFile(oEvent As Object)
+&apos; Execute the Dump To File command from the Trace dialog
+&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming §10.4
+
+
+ If _ErrorHandler() Then On Local Error GoTo Error_Sub
+
+Dim sPath as String, iFileNumber As Integer, i As Integer
+
+ sPath = _PromptFilePicker(&quot;txt&quot;)
+ If sPath &lt;&gt; &quot;&quot; Then &apos; Save button pressed
+ If UBound(_A2B_.TraceLogs) &gt;= 0 Then &apos; Array yet initialized
+ iFileNumber = FreeFile()
+ Open sPath For Append Access Write Lock Read As iFileNumber
+ If _A2B_.TraceLogCount &gt; 0 Then
+ If _A2B_.TraceLogCount &lt; _A2B_.TraceLogMaxEntries Then i = -1 Else i = _A2B_.TraceLogLast
+ Do
+ If i &lt; _A2B_.TraceLogMaxEntries - 1 Then i = i + 1 Else i = 0
+ Print #iFileNumber _A2B_.TraceLogs(i)
+ Loop While i &lt;&gt; _A2B_.TraceLogLast
+ End If
+ Close iFileNumber
+ MsgBox _GetLabel(&quot;SAVECONSOLEENTRIES&quot;), vbOK + vbInformation, _GetLabel(&quot;SAVECONSOLE&quot;)
+ End If
+ End If
+
+Exit_Sub:
+ Exit Sub
+Error_Sub:
+ TraceError(&quot;ERROR&quot;, Err, &quot;DumpToFile&quot;, Erl)
+ GoTo Exit_Sub
+End Sub &apos; DumpToFile V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _ErrorHandler(Optional ByVal pbCheck As Boolean) As Boolean
+&apos; Indicate if error handler is activated or not
+&apos; When argument present set error handler
+ If IsEmpty(_A2B_) Then Call Application._RootInit() &apos; First use of Access2Base in current LibO/AOO session
+ If Not IsMissing(pbCheck) Then _A2B_.ErrorHandler = pbCheck
+ _ErrorHandler = _A2B_.ErrorHandler
+ Exit Function
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _ErrorMessage(ByVal piErrorNumber As Integer, Optional ByVal pvArgs As Variant) As String
+&apos; Return error message corresponding to ErrorNumber (standard or not)
+&apos; and replaces %0, %1, ... , %9 by psArgs(0), psArgs(1), ...
+
+Dim sErrorMessage As String, i As Integer, sErrLabel
+ _ErrorMessage = &quot;&quot;
+ If piErrorNumber &gt; ERRINIT Then
+ sErrLabel = &quot;ERR&quot; &amp; piErrorNumber
+ sErrorMessage = _Getlabel(sErrLabel)
+ If Not IsMissing(pvArgs) Then
+ If Not IsArray(pvArgs) Then
+ sErrorMessage = Join(Split(sErrorMessage, &quot;%0&quot;), Utils._CStr(pvArgs, False))
+ Else
+ For i = LBound(pvArgs) To UBound(pvArgs)
+ sErrorMessage = Join(Split(sErrorMessage, &quot;%&quot; &amp; i), Utils._CStr(pvArgs(i), False))
+ Next i
+ End If
+ End If
+ Else
+ sErrorMessage = Error(piErrorNumber)
+ &apos; Most (or all?) error messages terminate with a &quot;.&quot;
+ If Len(sErrorMessage) &gt; 1 And Right(sErrorMessage, 1) = &quot;.&quot; Then sErrorMessage = Left(sErrorMessage, Len(sErrorMessage)-1)
+ End If
+
+ _ErrorMessage = sErrorMessage
+ Exit Function
+
+End Function &apos; ErrorMessage V0.8.9
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _PromptFilePicker(ByVal psSuffix As String) As String
+&apos; Prompt for output file name
+&apos; Return &quot;&quot; if Cancel
+&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming §10.4
+
+ If _ErrorHandler() Then On Local Error GoTo Error_Function
+
+Dim oFileDialog as Object, oUcb as object, oPath As Object
+Dim iAccept as Integer, sInitPath as String
+
+ Set oFileDialog = CreateUnoService(&quot;com.sun.star.ui.dialogs.FilePicker&quot;)
+ oFileDialog.Initialize(Array(com.sun.star.ui.dialogs.TemplateDescription.FILESAVE_AUTOEXTENSION))
+ Set oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+
+ oFileDialog.appendFilter(&quot;*.&quot; &amp; psSuffix, &quot;*.&quot; &amp; psSuffix)
+ oFileDialog.appendFilter(&quot;*.*&quot;, &quot;*.*&quot;)
+ oFileDialog.setCurrentFilter(&quot;*.&quot; &amp; psSuffix)
+ Set oPath = createUnoService(&quot;com.sun.star.util.PathSettings&quot;)
+ sInitPath = oPath.Work &apos; Probably My Documents
+ If oUcb.Exists(sInitPath) Then oFileDialog.SetDisplayDirectory(sInitPath)
+
+ iAccept = oFileDialog.Execute()
+
+ _PromptFilePicker = &quot;&quot;
+ If iAccept = 1 Then &apos; Save button pressed
+ _PromptFilePicker = oFileDialog.Files(0)
+ End If
+
+Exit_Function:
+ If Not IsEmpty(oFileDialog) And Not IsNull(oFileDialog) Then oFileDialog.Dispose()
+ Exit Function
+Error_Function:
+ TraceError(&quot;ERROR&quot;, Err, &quot;PromptFilePicker&quot;, Erl)
+ GoTo Exit_Function
+End Function &apos; PromptFilePicker V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _TraceArguments(Optional psCall As String)
+&apos; Process the ERRMISSINGARGUMENTS error
+&apos; psCall is present if error detected before call to _SetCalledSub
+
+ If Not IsMissing(psCall) Then Utils._SetCalledSub(psCall)
+ TraceError(TRACEFATAL, ERRMISSINGARGUMENTS, Utils._CalledSub(), 0)
+ Exit Sub
+
+End Sub &apos; TraceArguments
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _TraceLevel(ByVal pvTraceLevel As Variant) As Variant
+&apos; Convert string trace level to numeric value or the opposite
+
+Dim vTraces As Variant, i As Integer
+ vTraces = Array(TRACEDEBUG, TRACEINFO, TRACEWARNING, TRACEERRORS, TRACEFATAL, TRACEABORT, TRACEANY)
+
+ Select Case VarType(pvTraceLevel)
+ Case vbString
+ _TraceLevel = 4 &apos; 4 = Default
+ For i = 0 To UBound(vTraces)
+ If UCase(pvTraceLevel) = UCase(vTraces(i)) Then
+ _TraceLevel = i + 1
+ Exit For
+ End If
+ Next i
+ Case vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal
+ If pvTraceLevel &lt; 1 Or pvTraceLevel &gt; UBound(vTraces) + 1 Then _TraceLevel = TRACEERRORS Else _TraceLevel = vTraces(pvTraceLevel - 1)
+ End Select
+
+End Function &apos; TraceLevel
+
+</script:module>
diff --git a/wizards/source/access2base/UtilProperty.xba b/wizards/source/access2base/UtilProperty.xba
new file mode 100644
index 000000000..9f7ee4821
--- /dev/null
+++ b/wizards/source/access2base/UtilProperty.xba
@@ -0,0 +1,331 @@
+<?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="UtilProperty" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+&apos;**********************************************************************
+&apos; UtilProperty module
+&apos;
+&apos; Module of utilities to manipulate arrays of PropertyValue&apos;s.
+&apos;**********************************************************************
+
+&apos;**********************************************************************
+&apos; Copyright (c) 2003-2004 Danny Brewer
+&apos; d29583@groovegarden.com
+&apos;**********************************************************************
+
+&apos;**********************************************************************
+&apos; If you make changes, please append to the change log below.
+&apos;
+&apos; Change Log
+&apos; Danny Brewer Revised 2004-02-25-01
+&apos; Jean-Pierre Ledure Adapted to Access2Base coding conventions
+&apos; PropValuesToStr rewritten and addition of StrToPropValues
+&apos; Bug corrected on date values
+&apos; Addition of support of 2-dimensional arrays
+&apos; Support of empty arrays to allow JSON conversions
+&apos;**********************************************************************
+
+Option Explicit
+
+Private Const cstHEADER = &quot;### PROPERTYVALUES ###&quot;
+Private Const cstEMPTYARRAY = &quot;### EMPTY ARRAY ###&quot;
+
+REM =======================================================================================================================
+Public Function _MakePropertyValue(ByVal Optional psName As String, Optional pvValue As Variant) As com.sun.star.beans.PropertyValue
+&apos; Create and return a new com.sun.star.beans.PropertyValue.
+
+Dim oPropertyValue As New com.sun.star.beans.PropertyValue
+
+ If Not IsMissing(psName) Then oPropertyValue.Name = psName
+ If Not IsMissing(pvValue) Then oPropertyValue.Value = _CheckPropertyValue(pvValue)
+ _MakePropertyValue() = oPropertyValue
+
+End Function &apos; _MakePropertyValue V1.3.0
+
+REM =======================================================================================================================
+Public Function _CheckPropertyValue(ByRef pvValue As Variant) As Variant
+&apos; Date BASIC variables give error. Change them to strings
+&apos; Empty arrays should be replaced by cstEMPTYARRAY
+
+ If VarType(pvValue) = vbDate Then
+ _CheckPropertyValue = Utils._CStr(pvValue, False)
+ ElseIf IsArray(pvValue) Then
+ If UBound(pvValue, 1) &lt; LBound(pvValue, 1) Then _CheckPropertyValue = cstEMPTYARRAY Else _CheckPropertyValue = pvValue
+ Else
+ _CheckPropertyValue = pvValue
+ End If
+
+End Function &apos; _CheckPropertyValue
+
+REM =======================================================================================================================
+Public Function _NumPropertyValues(ByRef pvPropertyValuesArray As Variant) As Integer
+&apos; Return the number of PropertyValue&apos;s in an array.
+&apos; Parameters:
+&apos; pvPropertyValuesArray - an array of PropertyValue&apos;s, that is an array of com.sun.star.beans.PropertyValue.
+&apos; Returns zero if the array contains no elements.
+
+Dim iNumProperties As Integer
+ If Not IsArray(pvPropertyValuesArray) Then iNumProperties = 0 Else iNumProperties = UBound(pvPropertyValuesArray) + 1
+ _NumPropertyValues() = iNumProperties
+
+End Function &apos; _NumPropertyValues V1.3.0
+
+REM =======================================================================================================================
+Public Function _FindPropertyIndex(ByRef pvPropertyValuesArray As Variant, ByVal psPropName As String ) As Integer
+&apos; Find a particular named property from an array of PropertyValue&apos;s.
+&apos; Finds the index in the array of PropertyValue&apos;s and returns it, or returns -1 if it was not found.
+
+Dim iNumProperties As Integer, i As Integer, vProp As Variant
+ iNumProperties = _NumPropertyValues(pvPropertyValuesArray)
+ For i = 0 To iNumProperties - 1
+ vProp = pvPropertyValuesArray(i)
+ If UCase(vProp.Name) = UCase(psPropName) Then
+ _FindPropertyIndex() = i
+ Exit Function
+ EndIf
+ Next i
+ _FindPropertyIndex() = -1
+
+End Function &apos; _FindPropertyIndex V1.3.0
+
+REM =======================================================================================================================
+Public Function _FindProperty(ByRef pvPropertyValuesArray As Variant, ByVal psPropName As String) As com.sun.star.beans.PropertyValue
+&apos; Find a particular named property from an array of PropertyValue&apos;s.
+&apos; Finds the PropertyValue and returns it, or returns Null if not found.
+
+Dim iPropIndex As Integer, vProp As Variant
+ iPropIndex = _FindPropertyIndex(pvPropertyValuesArray, psPropName)
+ If iPropIndex &gt;= 0 Then
+ vProp = pvPropertyValuesArray(iPropIndex) &apos; access array subscript
+ _FindProperty() = vProp
+ EndIf
+
+End Function &apos; _FindProperty V1.3.0
+
+REM =======================================================================================================================
+Public Function _GetPropertyValue(ByRef pvPropertyValuesArray As Variant, ByVal psPropName As String, Optional pvDefaultValue) As Variant
+&apos; Get the value of a particular named property from an array of PropertyValue&apos;s.
+&apos; vDefaultValue - This value is returned if the property is not found in the array.
+
+Dim iPropIndex As Integer, vProp As Variant, vValue As Variant, vMatrix As Variant, i As Integer, j As Integer
+ iPropIndex = _FindPropertyIndex(pvPropertyValuesArray, psPropName)
+ If iPropIndex &gt;= 0 Then
+ vProp = pvPropertyValuesArray(iPropIndex) &apos; access array subscript
+ vValue = vProp.Value &apos; get the value from the PropertyValue
+ If VarType(vValue) = vbString Then
+ If vValue = cstEMPTYARRAY Then _GetPropertyValue() = Array() Else _GetPropertyValue() = vValue
+ ElseIf IsArray(vValue) Then
+ If IsArray(vValue(0)) Then &apos; Array of arrays
+ vMatrix = Array()
+ ReDim vMatrix(0 To UBound(vValue), 0 To UBound(vValue(0)))
+ For i = 0 To UBound(vValue)
+ For j = 0 To UBound(vValue(0))
+ vMatrix(i, j) = vValue(i)(j)
+ Next j
+ Next i
+ _GetPropertyValue() = vMatrix
+ Else
+ _GetPropertyValue() = vValue &apos; Simple vector OK
+ End If
+ Else
+ _GetPropertyValue() = vValue
+ End If
+ Else
+ If IsMissing(pvDefaultValue) Then pvDefaultValue = Null
+ _GetPropertyValue() = pvDefaultValue
+ EndIf
+
+End Function &apos; _GetPropertyValue V1.3.0
+
+REM =======================================================================================================================
+Public Sub _SetPropertyValue(ByRef pvPropertyValuesArray As Variant, ByVal psPropName As String, ByVal pvValue As Variant)
+&apos; Set the value of a particular named property from an array of PropertyValue&apos;s.
+
+Dim iPropIndex As Integer, vProp As Variant, iNumProperties As Integer
+
+ iPropIndex = _FindPropertyIndex(pvPropertyValuesArray, psPropName)
+ If iPropIndex &gt;= 0 Then
+ &apos; Found, the PropertyValue is already in the array. Just modify its value.
+ vProp = pvPropertyValuesArray(iPropIndex) &apos; access array subscript
+ vProp.Value = _CheckPropertyValue(pvValue) &apos; set the property value.
+ pvPropertyValuesArray(iPropIndex) = vProp &apos; put it back into array
+ Else
+ &apos; Not found, the array contains no PropertyValue with this name. Append new element to array.
+ iNumProperties = _NumPropertyValues(pvPropertyValuesArray)
+ If iNumProperties = 0 Then
+ pvPropertyValuesArray = Array(_MakePropertyValue(psPropName, pvValue))
+ Else
+ &apos; Make array larger.
+ Redim Preserve pvPropertyValuesArray(iNumProperties)
+ &apos; Assign new PropertyValue
+ pvPropertyValuesArray(iNumProperties) = _MakePropertyValue(psPropName, pvValue)
+ EndIf
+ EndIf
+
+End Sub &apos; _SetPropertyValue V1.3.0
+
+REM =======================================================================================================================
+Public Sub _DeleteProperty(ByRef pvPropertyValuesArray As Variant, ByVal psPropName As String)
+&apos; Delete a particular named property from an array of PropertyValue&apos;s.
+
+Dim iPropIndex As Integer
+ iPropIndex = _FindPropertyIndex(pvPropertyValuesArray, psPropName)
+ If iPropIndex &gt;= 0 Then _DeleteIndexedProperty(pvPropertyValuesArray, iPropIndex)
+
+End Sub &apos; _DeletePropertyValue V1.3.0
+
+REM =======================================================================================================================
+Public Sub _DeleteIndexedProperty(ByRef pvPropertyValuesArray As Variant, ByVal piPropIndex As Integer)
+&apos; Delete a particular indexed property from an array of PropertyValue&apos;s.
+
+Dim iNumProperties As Integer, i As Integer
+ iNumProperties = _NumPropertyValues(pvPropertyValuesArray)
+
+ &apos; Did we find it?
+ If piPropIndex &lt; 0 Then
+ &apos; Do nothing
+ ElseIf iNumProperties = 1 Then
+ &apos; Just return a new empty array
+ pvPropertyValuesArray = Array()
+ Else
+ &apos; If it is NOT the last item in the array, then shift other elements down into it&apos;s position.
+ If piPropIndex &lt; iNumProperties - 1 Then
+ &apos; Bump items down lower in the array.
+ For i = piPropIndex To iNumProperties - 2
+ pvPropertyValuesArray(i) = pvPropertyValuesArray(i + 1)
+ Next i
+ EndIf
+ &apos; Redimension the array to have one fewer element.
+ Redim Preserve pvPropertyValuesArray(iNumProperties - 2)
+ EndIf
+
+End Sub &apos; _DeleteIndexedProperty V1.3.0
+
+REM =======================================================================================================================
+Public Function _PropValuesToStr(ByRef pvPropertyValuesArray As Variant) As String
+&apos; Return a string with dumped content of the array of PropertyValue&apos;s.
+&apos; SYNTAX:
+&apos; NameOfProperty = This is a string (or 12 or 2016-12-31 12:05 or 123.45 or -0.12E-05 ...)
+&apos; NameOfArray = (10)
+&apos; 1;2;3;4;5;6;7;8;9;10
+&apos; NameOfMatrix = (2,10)
+&apos; 1;2;3;4;5;6;7;8;9;10
+&apos; A;B;C;D;E;F;G;H;I;J
+&apos; Semicolons and backslashes are escaped with a backslash (see _CStr and _CVar functions)
+
+Dim iNumProperties As Integer, sResult As String, i As Integer, j As Integer, vProp As Variant
+Dim sName As String, vValue As Variant, iType As Integer
+Dim cstLF As String
+
+ cstLF = vbLf()
+ iNumProperties = _NumPropertyValues(pvPropertyValuesArray)
+
+ sResult = cstHEADER &amp; cstLF
+ For i = 0 To iNumProperties - 1
+ vProp = pvPropertyValuesArray(i)
+ sName = vProp.Name
+ vValue = vProp.Value
+ iType = VarType(vValue)
+ Select Case iType
+ Case &lt; vbArray &apos; Scalar
+ sResult = sResult &amp; sName &amp; &quot; = &quot; &amp; Utils._CStr(vValue, False) &amp; cstLF
+ Case Else &apos; Vector or matrix
+ If uBound(vValue, 1) &lt; 0 Then
+ sResult = sResult &amp; sName &amp; &quot; = (0)&quot; &amp; cstLF
+ &apos; 1-dimension but vector of vectors must also be considered
+ ElseIf VarType(vValue(0)) &gt;= vbArray Then
+ sResult = sResult &amp; sName &amp; &quot; = (&quot; &amp; UBound(vValue) + 1 &amp; &quot;,&quot; &amp; UBound(vValue(0)) + 1 &amp; &quot;)&quot; &amp; cstLF
+ For j = 0 To UBound(vValue)
+ sResult = sResult &amp; Utils._CStr(vValue(j), False) &amp; cstLF
+ Next j
+ Else
+ sResult = sResult &amp; sName &amp; &quot; = (&quot; &amp; UBound(vValue, 1) + 1 &amp; &quot;)&quot; &amp; cstLF
+ sResult = sResult &amp; Utils._CStr(vValue, False) &amp; cstLF
+ End If
+ End Select
+ Next i
+
+ _PropValuesToStr() = Left(sResult, Len(sResult) - 1) &apos; Remove last LF
+
+End Function &apos; _PropValuesToStr V1.3.0
+
+REM =======================================================================================================================
+Public Function _StrToPropValues(psString) As Variant
+&apos; Return an array of PropertyValue&apos;s rebuilt from the string parameter
+
+Dim vString() As Variant, i As Integer,iArray As Integer, iRows As Integer, iCols As Integer
+Dim lPosition As Long, sName As String, vValue As Variant, vResult As Variant, sDim As String
+Dim lSearch As Long
+Dim cstLF As String
+Const cstEqualArray = &quot; = (&quot;, cstEqual = &quot; = &quot;
+
+ cstLF = Chr(10)
+ _StrToPropValues = Array()
+ vResult = Array()
+
+ If psString = &quot;&quot; Then Exit Function
+ vString = Split(psString, cstLF)
+ If UBound(vString) &lt;= 0 Then Exit Function &apos; There must be at least one name-value pair
+ If vString(0) &lt;&gt; cstHEADER Then Exit Function &apos; Check origin
+
+ iArray = -1
+ For i = 1 To UBound(vString)
+ If vString(i) &lt;&gt; &quot;&quot; Then &apos; Skip empty lines
+ If iArray &lt; 0 Then &apos; Not busy with array row
+ lPosition = 1
+ sName = Utils._RegexSearch(vString(i), &quot;^\b\w+\b&quot;, lPosition) &apos; Identifier
+ If sName = &quot;&quot; Then Exit Function
+ If InStr(vString(i), cstEqualArray) = lPosition + Len(sName) Then &apos; Start array processing
+ lSearch = lPosition + Len(sName) + Len(cstEqualArray) - 1
+ sDim = Utils._RegexSearch(vString(i), &quot;\([0-9]+\)&quot;, lSearch) &apos; e.g. (10)
+ If sDim = &quot;(0)&quot; Then &apos; Empty array
+ iRows = -1
+ vValue = Array()
+ _SetPropertyValue(vResult, sName, vValue)
+ ElseIf sDim &lt;&gt; &quot;&quot; Then &apos; Vector with content
+ iCols = CInt(Mid(sDim, 2, Len(sDim) - 2))
+ iRows = 0
+ ReDim vValue(0 To iCols - 1)
+ iArray = 0
+ Else &apos; Matrix with content
+ lSearch = lPosition + Len(sName) + Len(cstEqualArray) - 1
+ sDim = Utils._RegexSearch(vString(i), &quot;\([0-9]+,&quot;, lSearch) &apos; e.g. (10,
+ iRows = CInt(Mid(sDim, 2, Len(sDim) - 2))
+ sDim = Utils._RegexSearch(vString(i), &quot;,[0-9]+\)&quot;, lSearch) &apos; e.g. ,20)
+ iCols = CInt(Mid(sDim, 2, Len(sDim) - 2))
+ ReDim vValue(0 To iRows - 1)
+ iArray = 0
+ End If
+ ElseIf InStr(vString(i), cstEqual) = lPosition + Len(sName) Then
+ vValue = Utils._CVar(Mid(vString(i), Len(sName) + Len(cstEqual) + 1))
+ _SetPropertyValue(vResult, sName, vValue)
+ Else
+ Exit Function
+ End If
+ Else &apos; Line is an array row
+ If iRows = 0 Then
+ vValue = Utils._CVar(vString(i), True) &apos; Keep dates as strings
+ iArray = -1
+ _SetPropertyValue(vResult, sName, vValue)
+ Else
+ vValue(iArray) = Utils._CVar(vString(i), True)
+ If iArray &lt; iRows - 1 Then
+ iArray = iArray + 1
+ Else
+ iArray = -1
+ _SetPropertyValue(vResult, sName, vValue)
+ End If
+ End If
+ End If
+ End If
+ Next i
+
+ _StrToPropValues = vResult
+
+End Function
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/Utils.xba b/wizards/source/access2base/Utils.xba
new file mode 100644
index 000000000..7242c605b
--- /dev/null
+++ b/wizards/source/access2base/Utils.xba
@@ -0,0 +1,1308 @@
+<?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="Utils" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+Global _A2B_ As Variant
+
+REM -----------------------------------------------------------------------------------------------------------------------
+REM --- PRIVATE FUNCTIONS ---
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function _AddArray(ByVal pvArray As Variant, pvItem As Variant) As Variant
+&apos;Add the item at the end of the array
+
+Dim vArray() As Variant
+ If IsArray(pvArray) Then vArray = pvArray Else vArray = Array()
+ ReDim Preserve vArray(LBound(vArray) To UBound(vArray) + 1)
+ vArray(UBound(vArray)) = pvItem
+ _AddArray() = vArray()
+
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _AddNumeric(ByVal Optional pvTypes As Variant) As Variant
+&apos;Return on top of argument the list of all numeric types
+&apos;Facilitates the entry of the list of allowed types in _CheckArgument calls
+
+Dim i As Integer, vNewList() As Variant, vNumeric() As Variant, iSize As Integer
+ If IsMissing(pvTypes) Then
+ vNewList = Array()
+ ElseIf IsArray(pvTypes) Then
+ vNewList = pvTypes
+ Else
+ vNewList = Array(pvTypes)
+ End If
+
+ vNumeric = Array(vbInteger, vbLong, vbSingle, vbDouble, vbCurrency, vbBigint, vbDecimal, vbBoolean)
+
+ iSize = UBound(vNewlist)
+ ReDim Preserve vNewList(iSize + UBound(vNumeric) + 1)
+ For i = 0 To UBound(vNumeric)
+ vNewList(iSize + i + 1) = vNumeric(i)
+ Next i
+
+ _AddNumeric = vNewList
+
+End Function &apos; _AddNumeric V0.8.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+
+Public Function _BitShift(piValue As Integer, piConstant As Integer) As Boolean
+
+ _BitShift = False
+ If piValue = 0 Then Exit Function
+ Select Case piConstant
+ Case 1
+ Select Case piValue
+ Case 1, 3, 5, 7, 9, 11, 13, 15: _BitShift = True
+ Case Else
+ End Select
+ Case 2
+ Select Case piValue
+ Case 2, 3, 6, 7, 10, 11, 14, 15: _BitShift = True
+ Case Else
+ End Select
+ Case 4
+ Select Case piValue
+ Case 4, 5, 6, 7, 12, 13, 14, 15: _BitShift = True
+ Case Else
+ End Select
+ Case 8
+ Select Case piValue
+ Case 8, 9, 10, 11, 12, 13, 14, 15: _BitShift = True
+ Case Else
+ End Select
+ End Select
+
+End Function &apos; BitShift
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CalledSub() As String
+ _CalledSub = Iif(_A2B_.CalledSub = &quot;&quot;, &quot;&quot;, _GetLabel(&quot;CALLTO&quot;) &amp; &quot; &apos;&quot; &amp; _A2B_.CalledSub &amp; &quot;&apos;&quot;)
+End Function &apos; CalledSub V0.8.9
+
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CheckArgument(pvItem As Variant _
+ , ByVal piArgNr As Integer _
+ , ByVal pvType As Variant _
+ , ByVal Optional pvValid As Variant _
+ , ByVal Optional pvError As Boolean _
+ ) As Variant
+&apos; Called by public functions to check the validity of their arguments
+&apos; pvItem Argument to be checked
+&apos; piArgNr Argument sequence number
+&apos; pvType Single value or array of allowed variable types
+&apos; If of string type must contain one or more valid pseudo-object types
+&apos; pvValid Single value or array of allowed values - comparison for strings is case-insensitive
+&apos; pvError If True (default), error handling in this routine. False in _setProperty methods in class modules.
+
+ _CheckArgument = False
+
+Dim iVarType As Integer, bValidIsMissing As Boolean
+ If IsArray(pvType) Then iVarType = VarType(pvType(LBound(pvType))) Else iVarType = VarType(pvType)
+ If iVarType = vbString Then &apos; pvType is a pseudo-type string
+ _CheckArgument = Utils._IsPseudo(pvItem, pvType)
+ Else
+ bValidIsMissing = ( VarType(pvValid) = vbError )
+ If Not bValidIsMissing Then bValidIsMissing = IsMissing(pvValid)
+ If bValidIsMissing Then _CheckArgument = Utils._IsScalar(pvItem, pvType) Else _CheckArgument = Utils._IsScalar(pvItem, pvType, pvValid)
+ End If
+
+ If VarType(pvItem) = vbCurrency Or VarType(pvItem) = vbDecimal Or VarType(pvItem) = vbBigint Then pvItem = CDbl(pvItem)
+
+Exit_Function:
+ If Not _CheckArgument Then
+ If IsMissing(pvError) Then pvError = True
+ If pvError Then
+ TraceError(TRACEFATAL, ERRWRONGARGUMENT, Utils._CalledSub(), 0, 1, Array(piArgNr, pvItem))
+ End If
+ End If
+ Exit Function
+End Function &apos; CheckArgument V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CStr(ByVal pvArg As Variant, ByVal Optional pbShort As Boolean) As String
+&apos; Convert pvArg into a readable string (truncated if too long and pbShort = True or missing)
+&apos; pvArg may be a byte-array. Other arrays are processed recursively into a semicolon separated string
+
+Dim sArg As String, sObject As String, oArg As Object, sLength As String, i As Long, iMax As Long
+Const cstLength = 50
+Const cstByteLength = 25
+
+ If IsMissing(pbShort) Then pbShort = True
+ If IsArray(pvArg) Then
+ sArg = &quot;&quot;
+ If VarType(pvArg) = vbByte Or VarType(pvArg) = vbArray + vbByte Then
+ If pbShort And UBound(pvArg) &gt; cstByteLength Then iMax = cstByteLength Else iMax = UBound(pvArg)
+ For i = 0 To iMax
+ sArg = sArg &amp; Right(&quot;00&quot; &amp; Hex(pvArg(i)), 2)
+ Next i
+ Else
+ If pbShort Then
+ sArg = &quot;[ARRAY]&quot;
+ Else &apos; One-dimension arrays only
+ For i = LBound(pvArg) To UBound(pvArg)
+ sArg = sArg &amp; Utils._CStr(pvArg(i), pbShort) &amp; &quot;;&quot; &apos; Recursive call
+ Next i
+ If Len(sArg) &gt; 1 Then sArg = Left(sArg, Len(sArg) - 1)
+ End If
+ End If
+ Else
+ Select Case VarType(pvArg)
+ Case vbEmpty : sArg = &quot;[EMPTY]&quot;
+ Case vbNull : sArg = &quot;[NULL]&quot;
+ Case vbObject
+ If IsNull(pvArg) Then
+ sArg = &quot;[NULL]&quot;
+ Else
+ sObject = Utils._ImplementationName(pvArg)
+ If Utils._IsPseudo(pvArg, Array(OBJDATABASE, OBJCOLLECTION, OBJPROPERTY, OBJFORM, OBJSUBFORM, OBJCONTROL, OBJOPTIONGROUP _
+ , OBJEVENT, OBJFIELD, OBJTABLEDEF, OBJQUERYDEF, OBJRECORDSET, OBJTEMPVAR, OBJCOMMANDBAR, OBJCOMMANDBARCONTROL _
+ , OBJDIALOG _
+ )) Then
+ Set oArg = pvArg &apos; To avoid &quot;Object variable not set&quot; error message
+ sArg = &quot;[&quot; &amp; oArg._Type &amp; &quot;] &quot; &amp; oArg._Name
+ ElseIf sObject &lt;&gt; &quot;&quot; Then
+ sArg = &quot;[&quot; &amp; sObject &amp; &quot;]&quot;
+ Else
+ sArg = &quot;[OBJECT]&quot;
+ End If
+ End If
+ Case vbVariant : sArg = &quot;[VARIANT]&quot;
+ Case vbString
+ &apos; Replace CR + LF by \n and HT by \t
+ &apos; Replace semicolon by \; to allow semicolon separated rows
+ sArg = Replace( _
+ Replace( _
+ Replace( _
+ Replace( _
+ Replace(pvArg, &quot;\&quot;, &quot;\\&quot;) _
+ , Chr(13), &quot;&quot;) _
+ , Chr(10), &quot;\n&quot;) _
+ , Chr(9), &quot;\t&quot;) _
+ , &quot;;&quot;, &quot;\;&quot;)
+ Case vbBoolean : sArg = Iif(pvArg, &quot;[TRUE]&quot;, &quot;[FALSE]&quot;)
+ Case vbByte : sArg = Right(&quot;00&quot; &amp; Hex(pvArg), 2)
+ Case vbSingle, vbDouble, vbCurrency
+ sArg = Format(pvArg)
+ If InStr(UCase(sArg), &quot;E&quot;) = 0 Then sArg = Format(pvArg, &quot;##0.0##&quot;)
+ sArg = Replace(sArg, &quot;,&quot;, &quot;.&quot;)
+ Case vbBigint : sArg = CStr(CLng(pvArg))
+ Case vbDate : sArg = Year(pvArg) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvArg), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvArg), 2) _
+ &amp; &quot; &quot; &amp; Right(&quot;0&quot; &amp; Hour(pvArg), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvArg), 2) _
+ &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvArg), 2)
+ Case Else : sArg = CStr(pvArg)
+ End Select
+ End If
+ If pbShort And Len(sArg) &gt; cstLength Then
+ sLength = &quot;(&quot; &amp; Len(sArg) &amp; &quot;)&quot;
+ sArg = Left(sArg, cstLength - 5 - Len(slength)) &amp; &quot; ... &quot; &amp; sLength
+ End If
+ _CStr = sArg
+
+End Function &apos; CStr V0.9.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _CVar(ByRef psArg As String, ByVal Optional pbStrDate As Boolean) As Variant
+&apos; psArg is presumed an output of _CStr (stored in the meantime in a text file f.i.)
+&apos; _CVar returns the corresponding original Variant variable or Null/Nothing if not possible
+&apos; Return values may of types Array, Long, Double, Date, Boolean, String, Null or Empty
+&apos; pbStrDate = True keeps dates as strings
+
+Dim cstEscape1 As String, cstEscape2 As String
+ cstEscape1 = Chr(14) &apos; Form feed used as temporary escape character for \\
+ cstEscape2 = Chr(27) &apos; ESC used as temporary escape character for \;
+
+ _CVar = &quot;&quot;
+ If Len(psArg) = 0 Then Exit Function
+
+Dim sArg As String, vArgs() As Variant, vVars() As Variant, i As Integer
+ If IsMissing(pbStrDate) Then pbStrDate = False
+ sArg = Replace( _
+ Replace( _
+ Replace( _
+ Replace(psArg, &quot;\\&quot;, cstEscape1) _
+ , &quot;\;&quot;, cstEscape2) _
+ , &quot;\n&quot;, Chr(10)) _
+ , &quot;\t&quot;, Chr(9))
+
+ &apos; Semicolon separated string
+ vArgs = Split(sArg, &quot;;&quot;)
+ If UBound(vArgs) &gt; LBound(vArgs) Then &apos; Process each item recursively
+ vVars = Array()
+ Redim vVars(LBound(vArgs) To UBound(vArgs))
+ For i = LBound(vVars) To UBound(vVars)
+ vVars(i) = _CVar(vArgs(i), pbStrDate)
+ Next i
+ _CVar = vVars
+ Exit Function
+ End If
+
+ &apos; Usual case
+ Select Case True
+ Case sArg = &quot;[EMPTY]&quot; : _CVar = EMPTY
+ Case sArg = &quot;[NULL]&quot; Or sArg = &quot;[VARIANT]&quot; : _CVar = Null
+ Case sArg = &quot;[OBJECT]&quot; : _CVar = Nothing
+ Case sArg = &quot;[TRUE]&quot; : _CVar = True
+ Case sArg = &quot;[FALSE]&quot; : _CVar = False
+ Case IsDate(sArg)
+ If pbStrDate Then _CVar = sArg Else _CVar = CDate(sArg)
+ Case IsNumeric(sArg)
+ If InStr(sArg, &quot;.&quot;) &gt; 0 Then
+ _CVar = Val(sArg)
+ Else
+ _CVar = CLng(Val(sArg)) &apos; Val always returns a double
+ End If
+ Case _RegexSearch(sArg, &quot;^[-+]?[0-9]*\.?[0-9]+(e[-+]?[0-9]+)?$&quot;) &lt;&gt; &quot;&quot;
+ _CVar = Val(sArg) &apos; Scientific notation
+ Case Else : _CVar = Replace(Replace(sArg, cstEscape1, &quot;\&quot;), cstEscape2, &quot;;&quot;)
+ End Select
+
+End Function &apos; CVar V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _DecimalPoint() As String
+&apos;Return locale decimal point
+ _DecimalPoint = Mid(Format(0, &quot;0.0&quot;), 2, 1)
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _ExtensionLocation() As String
+&apos; Return the URL pointing to the location where OO installed the Access2Base extension
+&apos; Adapted from https://wiki.documentfoundation.org/Documentation/DevGuide/Extensions#Location_of_Installed_Extensions
+
+Dim oPip As Object, sLocation As String
+ Set oPip = GetDefaultContext.getByName(&quot;/singletons/com.sun.star.deployment.PackageInformationProvider&quot;)
+ _ExtensionLocation = oPip.getPackageLocation(&quot;Access2Base&quot;)
+
+End Function &apos; ExtensionLocation
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetDialogLib() As Object
+&apos; Return actual Access2Base dialogs library
+
+Dim oDialogLib As Object
+
+ Set oDialogLib = DialogLibraries
+ If oDialogLib.hasByName(&quot;Access2BaseDev&quot;) Then
+ If Not oDialogLib.IsLibraryLoaded(&quot;Access2BaseDev&quot;) Then oDialogLib.loadLibrary(&quot;Access2BaseDev&quot;)
+ Set _GetDialogLib = DialogLibraries.Access2BaseDev
+ ElseIf oDialogLib.hasByName(&quot;Access2Base&quot;) Then
+ If Not oDialogLib.IsLibraryLoaded(&quot;Access2Base&quot;) Then oDialogLib.loadLibrary(&quot;Access2Base&quot;)
+ Set _GetDialogLib = DialogLibraries.Access2Base
+ Else
+ Set _GetDialogLib = Nothing
+ EndIf
+
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetEventName(ByVal psProperty As String) As String
+&apos; Return the LO internal event name
+&apos; Corrects the typo on ErrorOccur(r?)ed
+
+ _GetEventName = Replace(LCase(Mid(psProperty, 3, 1)) &amp; Right(psProperty, Len(psProperty) - 3), &quot;errorOccurred&quot;, &quot;errorOccured&quot;)
+
+End Function &apos; _GetEventName V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetEventScriptCode(poObject As Object _
+ , ByVal psEvent As String _
+ , ByVal psName As String _
+ , Optional ByVal pbExtendName As Boolean _
+ ) As String
+&apos; Extract from the parent of poObject the macro linked to psEvent.
+&apos; psName is the name of the object
+
+Dim i As Integer, vEvents As Variant, sEvent As String, oParent As Object, iIndex As Integer, sName As String
+
+ _GetEventScriptCode = &quot;&quot;
+ If Not Utils._hasUNOMethod(poObject, &quot;getParent&quot;) Then Exit Function
+
+ &apos; Find form index i.e. find control via getByIndex()
+ If IsMissing(pbExtendName) Then pbExtendName = False
+ Set oParent = poObject.getParent()
+ iIndex = -1
+ For i = 0 To oParent.getCount() - 1
+ sName = oParent.getByIndex(i).Name
+ If (sName = psName) Or (pbExtendName And (sName = &quot;MainForm&quot; Or sName = &quot;Form&quot;)) Then
+ iIndex = i
+ Exit For
+ End If
+ Next i
+ If iIndex &lt; 0 Then Exit Function
+
+ &apos; Find script event
+ vEvents = oParent.getScriptEvents(iIndex) &apos; Returns an array
+ sEvent = Utils._GetEventName(psEvent) &apos; Targeted event method
+ For i = 0 To UBound(vEvents)
+ If vEvents(i).EventMethod = sEvent Then
+ _GetEventScriptCode = vEvents(i).ScriptCode
+ Exit For
+ End If
+ Next i
+
+End Function &apos; _GetEventScriptCode V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _GetResultSetColumnValue(poResultSet As Object _
+ , ByVal piColIndex As Integer _
+ , Optional ByVal pbReturnBinary As Boolean _
+ ) As Variant
+REM Modified from Roberto Benitez&apos;s BaseTools
+REM get the data for the column specified by ColIndex
+REM If pbReturnBinary = False (default) then return length of binary field
+REM get type name from metadata
+
+Dim vValue As Variant, iType As Integer, vDateTime As Variant, oValue As Object
+Dim bNullable As Boolean, lSize As Long
+Const cstMaxTextLength = 65535
+Const cstMaxBinlength = 2 * 65535
+
+ On Local Error Goto 0 &apos; Disable error handler
+ vValue = Null &apos; Default value if error
+ If IsMissing(pbReturnBinary) Then pbReturnBinary = False
+ With com.sun.star.sdbc.DataType
+ iType = poResultSet.MetaData.getColumnType(piColIndex)
+ bNullable = ( poResultSet.MetaData.IsNullable(piColIndex) = com.sun.star.sdbc.ColumnValue.NULLABLE )
+ Select Case iType
+ Case .ARRAY : vValue = poResultSet.getArray(piColIndex)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ Set oValue = poResultSet.getBinaryStream(piColIndex)
+ If bNullable Then
+ If Not poResultSet.wasNull() Then
+ If Not _hasUNOMethod(oValue, &quot;getLength&quot;) Then &apos; When no recordset
+ lSize = cstMaxBinLength
+ Else
+ lSize = CLng(oValue.getLength())
+ End If
+ If lSize &lt;= cstMaxBinLength And pbReturnBinary Then
+ vValue = Array()
+ oValue.readBytes(vValue, lSize)
+ Else &apos; Return length of field, not content
+ vValue = lSize
+ End If
+ End If
+ End If
+ oValue.closeInput()
+ Case .BIT, .BOOLEAN : vValue = poResultSet.getBoolean(piColIndex)
+ Case .DATE : vDateTime = poResultSet.getDate(piColIndex)
+ If Not poResultSet.wasNull() Then vValue = DateSerial(CInt(vDateTime.Year), CInt(vDateTime.Month), CInt(vDateTime.Day))
+ Case .DISTINCT, .OBJECT, .OTHER, .STRUCT
+ vValue = Null
+ Case .DOUBLE, .REAL : vValue = poResultSet.getDouble(piColIndex)
+ Case .FLOAT : vValue = poResultSet.getFloat(piColIndex)
+ Case .INTEGER, .SMALLINT : vValue = poResultSet.getInt(piColIndex)
+ Case .BIGINT : vValue = poResultSet.getLong(piColIndex)
+ Case .DECIMAL, .NUMERIC : vValue = poResultSet.getDouble(piColIndex)
+ Case .SQLNULL : vValue = poResultSet.getNull(piColIndex)
+ Case .OBJECT, .OTHER, .STRUCT : vValue = Null
+ Case .REF : vValue = poResultSet.getRef(piColIndex)
+ Case .TINYINT : vValue = poResultSet.getShort(piColIndex)
+ Case .CHAR, .VARCHAR : vValue = poResultSet.getString(piColIndex)
+ Case .LONGVARCHAR, .CLOB
+ Set oValue = poResultSet.getCharacterStream(piColIndex)
+ If bNullable Then
+ If Not poResultSet.wasNull() Then
+ If Not _hasUNOMethod(oValue, &quot;getLength&quot;) Then &apos; When no recordset
+ lSize = cstMaxTextLength
+ Else
+ lSize = CLng(oValue.getLength())
+ End If
+ oValue.closeInput()
+ vValue = poResultSet.getString(piColIndex)
+ End If
+ Else
+ oValue.closeInput()
+ End If
+ Case .TIME : vDateTime = poResultSet.getTime(piColIndex)
+ If Not poResultSet.wasNull() Then vValue = TimeSerial(vDateTime.Hours, vDateTime.Minutes, vDateTime.Seconds)&apos;, vDateTime.HundredthSeconds)
+ Case .TIMESTAMP : vDateTime = poResultSet.getTimeStamp(piColIndex)
+ If Not poResultSet.wasNull() Then vValue = DateSerial(CInt(vDateTime.Year), CInt(vDateTime.Month), CInt(vDateTime.Day)) _
+ + TimeSerial(vDateTime.Hours, vDateTime.Minutes, vDateTime.Seconds)&apos;, vDateTime.HundredthSeconds)
+ Case Else
+ vValue = poResultSet.getString(piColIndex) &apos;GIVE STRING A TRY
+ If IsNumeric(vValue) Then vValue = Val(vValue) &apos;Required when type = &quot;&quot;, sometimes numeric fields are returned as strings (query/MSAccess)
+ End Select
+ If bNullable Then
+ If poResultSet.wasNull() Then vValue = Null
+ End If
+ End With
+
+ _GetResultSetColumnValue = vValue
+
+End Function &apos; GetResultSetColumnValue V 1.5.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _FinalProperty(psShortcut As String) As String
+&apos; Return the final property of a shortcut
+
+Const cstEXCLAMATION = &quot;!&quot;
+Const cstDOT = &quot;.&quot;
+
+Dim iCurrentIndex As Integer, vCurrentObject As Variant, sCurrentProperty As String
+Dim sComponents() As String, sSubComponents() As String
+ _FinalProperty = &quot;&quot;
+ sComponents = Split(Trim(psShortcut), cstEXCLAMATION)
+ If UBound(sComponents) = 0 Then Exit Function
+ sSubComponents = Split(sComponents(UBound(sComponents)), cstDOT)
+ Select Case UBound(sSubComponents)
+ Case 1
+ _FinalProperty = sSubComponents(1)
+ Case Else
+ Exit Function
+ End Select
+
+End Function &apos; FinalProperty
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetProductName(ByVal Optional psFlag As String) as String
+&apos;Return OO product (&quot;PRODUCT&quot;) and version numbers (&quot;VERSION&quot;)
+&apos;Derived from Tools library
+
+Dim oProdNameAccess as Object
+Dim sVersion as String
+Dim sProdName as String
+ If IsMissing(psFlag) Then psFlag = &quot;ALL&quot;
+ oProdNameAccess = _GetRegistryKeyContent(&quot;org.openoffice.Setup/Product&quot;)
+ sProdName = oProdNameAccess.getByName(&quot;ooName&quot;)
+ sVersion = oProdNameAccess.getByName(&quot;ooSetupVersionAboutBox&quot;)
+ Select Case psFlag
+ Case &quot;ALL&quot; : _GetProductName = sProdName &amp; &quot; &quot; &amp; sVersion
+ Case &quot;PRODUCT&quot; : _GetProductName = sProdName
+ Case &quot;VERSION&quot; : _GetProductName = sVersion
+ End Select
+End Function &apos; GetProductName V1.0.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetRandomFileName(ByVal psName As String) As String
+&apos; Return the full name of a random temporary file suffixed by psName
+
+Dim sRandom As String
+ sRandom = Right(&quot;000000&quot; &amp; Int(999999 * Rnd), 6)
+ _GetRandomFileName = Utils._getTempDirectoryURL() &amp; &quot;/&quot; &amp; &quot;A2B_TEMP_&quot; &amp; psName &amp; &quot;_&quot; &amp; sRandom
+
+End Function &apos; GetRandomFileName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _GetRegistryKeyContent(sKeyName as string, Optional bforUpdate as Boolean) As Variant
+&apos;Implement ConfigurationProvider service
+&apos;Derived from Tools library
+
+Dim oConfigProvider as Object
+Dim aNodePath(0) as new com.sun.star.beans.PropertyValue
+ oConfigProvider = createUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
+ aNodePath(0).Name = &quot;nodepath&quot;
+ aNodePath(0).Value = sKeyName
+ If IsMissing(bForUpdate) Then bForUpdate = False
+ If bForUpdate Then
+ _GetRegistryKeyContent() = oConfigProvider.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationUpdateAccess&quot;, aNodePath())
+ Else
+ _GetRegistryKeyContent() = oConfigProvider.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationAccess&quot;, aNodePath())
+ End If
+End Function &apos; GetRegistryKeyContent V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _getTempDirectoryURL() As String
+&apos; Return the temporary directory defined in the OO Options (Paths)
+Dim sDirectory As String, oSettings As Object, oPathSettings As Object
+
+ If _ErrorHandler() Then On Local Error Goto Error_Function
+
+ _getTempDirectoryURL = &quot;&quot;
+ oPathSettings = createUnoService( &quot;com.sun.star.util.PathSettings&quot; )
+ sDirectory = oPathSettings.GetPropertyValue( &quot;Temp&quot; )
+
+ _getTempDirectoryURL = sDirectory
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ TraceError(&quot;ERROR&quot;, Err, &quot;_getTempDirectoryURL&quot;, Erl)
+ _getTempDirectoryURL = &quot;&quot;
+ Goto Exit_Function
+End Function &apos; _getTempDirectoryURL V0.8.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _getUNOTypeName(pvObject As Variant) As String
+&apos; Return the symbolic name of the pvObject (UNO-object) type
+&apos; Code-snippet from XRAY
+
+Dim oService As Object, vClass as Variant
+ _getUNOTypeName = &quot;&quot;
+ On Local Error Resume Next
+ oService = CreateUnoService(&quot;com.sun.star.reflection.CoreReflection&quot;)
+ vClass = oService.getType(pvObject)
+ If vClass.TypeClass = com.sun.star.uno.TypeClass.STRUCT Then
+ _getUNOTypeName = vClass.Name
+ End If
+ oService.Dispose()
+
+End Function &apos; getUNOTypeName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _hasUNOMethod(pvObject As Variant, psMethod As String) As Boolean
+&apos; Return true if pvObject has the (UNO) method psMethod
+&apos; Code-snippet found in Bernard Marcelly&apos;s XRAY
+
+Dim vInspect as Variant
+ _hasUNOMethod = False
+ If IsNull(pvObject) Then Exit Function
+ On Local Error Resume Next
+ vInspect = _A2B_.Introspection.Inspect(pvObject)
+ _hasUNOMethod = vInspect.hasMethod(psMethod, com.sun.star.beans.MethodConcept.ALL)
+
+End Function &apos; hasUNOMethod V0.8.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _hasUNOProperty(pvObject As Variant, psProperty As String) As Boolean
+&apos; Return true if pvObject has the (UNO) property psProperty
+&apos; Code-snippet found in Bernard Marcelly&apos;s XRAY
+
+Dim vInspect as Variant
+ _hasUNOProperty = False
+ If IsNull(pvObject) Then Exit Function
+ On Local Error Resume Next
+ vInspect = _A2B_.Introspection.Inspect(pvObject)
+ _hasUNOProperty = vInspect.hasProperty(psProperty, com.sun.star.beans.PropertyConcept.ALL)
+
+End Function &apos; hasUNOProperty V0.8.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _ImplementationName(pvObject As Variant) As String
+&apos; Use getImplementationName method or _getUNOTypeName function
+
+Dim sObjectType As String
+ On Local Error Resume Next
+ sObjectType = pvObject.getImplementationName()
+ If sObjectType = &quot;&quot; Then sObjectType = _getUNOTypeName(pvObject)
+
+ _ImplementationName = sObjectType
+
+End Function &apos; ImplementationName
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _InList(ByVal pvItem As Variant, pvList As Variant, ByVal Optional pvReturnValue As Variant, Optional ByVal pbBinarySearch As Boolean) As Variant
+&apos; Return True if pvItem is present in the pvList array (case insensitive comparison)
+&apos; Return the value in pvList if pvReturnValue = True
+
+Dim i As Integer, bFound As Boolean, iListVarType As Integer, iItemVarType As Integer
+Dim iTop As Integer, iBottom As Integer, iFound As Integer
+ iItemVarType = VarType(pvItem)
+ If IsMissing(pvReturnValue) Then pvReturnValue = False
+ If iItemVarType = vbNull Or IsNull(pvList) Then
+ _InList = False
+ ElseIf Not IsArray(pvList) Then
+ If iItemVarType = vbString Then bFound = ( UCase(pvItem) = UCase(pvList) ) Else bFound = ( pvItem = pvList )
+ If Not pvReturnValue Then
+ _InList = bFound
+ Else
+ If bFound Then _InList = pvList Else _InList = False
+ End If
+ ElseIf UBound(pvList) &lt; LBound(pvList) Then &apos; Array not initialized
+ _InList = False
+ Else
+ bFound = False
+ _InList = False
+ iListVarType = VarType(pvList(LBound(pvList)))
+ If iListVarType = iItemVarType _
+ Or ( (iListVarType = vbInteger Or iListVarType = vbLong Or iListVarType = vbSingle Or iListVarType = vbDouble _
+ Or iListVarType = vbCurrency Or iListVarType = vbBigint Or iListVarType = vbDecimal) _
+ And (iItemVarType = vbInteger Or iItemVarType = vbLong Or iItemVarType = vbSingle Or iItemVarType = vbDouble _
+ Or iItemVarType = vbCurrency Or iItemVarType = vbBigint Or iItemVarType = vbDecimal) _
+ ) Then
+ If IsMissing(pbBinarySearch) Then pbBinarySearch = False
+ If Not pbBinarySearch Then &apos; Linear search
+ For i = LBound(pvList) To UBound(pvList)
+ If iItemVarType = vbString Then bFound = ( UCase(pvItem) = UCase(pvList(i)) ) Else bFound = ( pvItem = pvList(i) )
+ If bFound Then
+ iFound = i
+ Exit For
+ End If
+ Next i
+ Else &apos; Binary search =&gt; array must be sorted
+ iTop = UBound(pvList)
+ iBottom = lBound(pvList)
+ Do
+ iFound = (iTop + iBottom) / 2
+ If ( iItemVarType = vbString And UCase(pvItem) &gt; UCase(pvList(iFound)) ) Or ( iItemVarType &lt;&gt; vbString And pvItem &gt; pvList(iFound) ) Then
+ iBottom = iFound + 1
+ Else
+ iTop = iFound - 1
+ End If
+ If iItemVarType = vbString Then bFound = ( UCase(pvItem) = UCase(pvList(iFound)) ) Else bFound = ( pvItem = pvList(iFound) )
+ Loop Until ( bFound ) Or ( iBottom &gt; iTop )
+ End If
+ If bFound Then
+ If Not pvReturnValue Then _InList = True Else _InList = pvList(iFound)
+ End If
+ End If
+ End If
+
+ Exit Function
+
+End Function &apos; InList V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _InspectPropertyType(poObject As Object, psProperty As String) As String
+&apos;Return type of property EVEN WHEN EMPTY ! (Used in date and time controls)
+
+Dim oInspect1 As Object, oInspect2 As Object, oInspect3 As Object
+&apos; On Local Error Resume Next
+ _InspectPropertyType = &quot;&quot;
+ Set oInspect1 = CreateUnoService(&quot;com.sun.star.script.Invocation&quot;)
+ Set oInspect2 = oInspect1.createInstanceWithArguments(Array(poObject)).IntroSpection
+ If Not IsNull(oInspect2) Then
+ Set oInspect3 = oInspect2.getProperty(psProperty, com.sun.star.beans.PropertyConcept.ALL)
+ If Not IsNull(oInspect3) Then _InspectPropertyType = oInspect3.Type.Name
+ End If
+ Set oInspect1 = Nothing : Set oInspect2 = Nothing : Set oInspect3 = Nothing
+
+End Function &apos; InspectPropertyType V1.0.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _IsLeft(psString As String, psLeft As String) As Boolean
+&apos; Return True if left part of psString = psLeft
+
+Dim iLength As Integer
+ iLength = Len(psLeft)
+ _IsLeft = False
+ If Len(psString) &gt;= iLength Then
+ If Left(psString, iLength) = psLeft Then _IsLeft = True
+ End If
+
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _IsBinaryType(ByVal lType As Long) As Boolean
+
+ With com.sun.star.sdbc.DataType
+ Select Case lType
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ _IsBinaryType = True
+ Case Else
+ _IsBinaryType = False
+ End Select
+ End With
+
+End Function &apos; IsBinaryType V1.6.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _IsPseudo(pvObject As Variant, ByVal pvType As Variant) As Boolean
+&apos; Test pvObject: does it exist ?
+&apos; is the _Type item = one of the proposed pvTypes ?
+&apos; does the pseudo-object refer to an existing object (e.g. does the form really exist in the db) ?
+
+Dim bIsPseudo As Boolean, bPseudoExists As Boolean, vObject As Variant
+
+ If _ErrorHandler() Then On Local Error Goto Exit_False
+
+ _IsPseudo = False
+ bIsPseudo = False
+ vObject = pvObject &apos; To avoid &quot;Object variable not set&quot; error message
+ Select Case True
+ Case IsEmpty(vObject)
+ Case IsNull(vObject)
+ Case VarType(vObject) &lt;&gt; vbObject
+ Case Else
+ With vObject
+ Select Case True
+ Case IsEmpty(._Type)
+ Case IsNull(._Type)
+ Case ._Type = &quot;&quot;
+ Case Else
+ bIsPseudo = _InList(._Type, pvType)
+ If Not bIsPseudo Then &apos; If primary type did not succeed, give the subtype a chance
+ If ._Type = OBJCONTROL Then bIsPseudo = _InList(._SubType, pvType)
+ End If
+ End Select
+ End With
+ End Select
+
+ If Not bIsPseudo Then Goto Exit_Function
+
+Dim oDoc As Object, oForms As Variant
+Const cstSeparator = &quot;\;&quot;
+
+ bPseudoExists = False
+ With vObject
+ Select Case ._Type
+ Case OBJFORM
+ If ._Name &lt;&gt; &quot;&quot; Then &apos; Check validity of form name
+ Set oDoc = _A2B_.CurrentDocument()
+ If oDoc.DbConnect = DBCONNECTFORM Then bPseudoExists = True Else bPseudoExists = _InList(._Name, Application._GetAllHierarchicalNames())
+ End If
+ Case OBJDATABASE
+ If ._DbConnect = DBCONNECTFORM Then bPseudoExists = True Else bPseudoExists = Not IsNull(.Connection)
+ Case OBJDIALOG
+ If ._Name &lt;&gt; &quot;&quot; Then &apos; Check validity of dialog name
+ bPseudoExists = ( _A2B_.hasItem(COLLALLDIALOGS, ._Name) )
+ End If
+ Case OBJCOLLECTION
+ bPseudoExists = True
+ Case OBJCONTROL
+ If Not IsNull(.ControlModel) And ._Name &lt;&gt; &quot;&quot; Then &apos; Check validity of control
+ Set oForms = .ControlModel.Parent
+ bPseudoExists = ( oForms.hasByName(._Name) )
+ End If
+ Case OBJSUBFORM
+ If Not IsNull(.DatabaseForm) And ._Name &lt;&gt; &quot;&quot; Then &apos; Check validity of subform
+ If .DatabaseForm.ImplementationName = &quot;com.sun.star.comp.forms.ODatabaseForm&quot; Then
+ Set oForms = .DatabaseForm.Parent
+ bPseudoExists = ( oForms.hasByName(._Name) )
+ End If
+ End If
+ Case OBJOPTIONGROUP
+ bPseudoExists = ( .Count &gt; 0 )
+ Case OBJCOMMANDBAR
+ bPseudoExists = ( Not IsNull(._Window) )
+ Case OBJCOMMANDBARCONTROL
+ bPseudoExists = ( Not IsNull(._ParentCommandBar) )
+ Case OBJEVENT
+ bPseudoExists = ( Not IsNull(._EventSource) )
+ Case OBJPROPERTY
+ bPseudoExists = ( ._Name &lt;&gt; &quot;&quot; )
+ Case OBJTABLEDEF
+ bPseudoExists = ( ._Name &lt;&gt; &quot;&quot; And Not IsNull(.Table) )
+ Case OBJQUERYDEF
+ bPseudoExists = ( ._Name &lt;&gt; &quot;&quot; And Not IsNull(.Query) )
+ Case OBJRECORDSET
+ bPseudoExists = ( Not IsNull(.RowSet) )
+ Case OBJFIELD
+ bPseudoExists = ( ._Name &lt;&gt; &quot;&quot; And Not IsNull(.Column) )
+ Case OBJTEMPVAR
+ If ._Name &lt;&gt; &quot;&quot; Then &apos; Check validity of tempvar name
+ bPseudoExists = ( _A2B_.hasItem(COLLTEMPVARS, ._Name) )
+ End If
+ Case Else
+ End Select
+ End With
+
+ _IsPseudo = ( bIsPseudo And bPseudoExists )
+
+Exit_Function:
+ Exit Function
+Exit_False:
+ _IsPseudo = False
+ Goto Exit_Function
+End Function &apos; IsPseudo V1.1.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _IsScalar(ByVal pvArg As Variant, ByVal pvType As Variant, ByVal Optional pvValid As Variant) As Boolean
+&apos; Check type of pvArg and value in allowed pvValid list
+
+ _IsScalar = False
+
+ If IsArray(pvType) Then
+ If Not _InList(VarType(pvArg), pvType) Then Exit Function
+ ElseIf VarType(pvArg) &lt;&gt; pvType Then
+ If pvType = vbBoolean And VarType(pvArg) = vbLong Then
+ If pvArg &lt; -1 And pvArg &gt; 0 Then Exit Function &apos; Special boolean processing because the Not function returns a Long
+ Else
+ Exit Function
+ End If
+ End If
+ If Not IsMissing(pvValid) Then
+ If Not _InList(pvArg, pvValid) Then Exit Function
+ End If
+
+ _IsScalar = True
+
+Exit_Function:
+ Exit Function
+End Function &apos; IsScalar V0.7.5
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _PCase(ByVal psString As String) As String
+&apos; Return the proper case representation of argument
+
+Dim vSubStrings() As Variant, i As Integer, iLen As Integer
+ vSubStrings = Split(psString, &quot; &quot;)
+ For i = 0 To UBound(vSubStrings)
+ iLen = Len(vSubStrings(i))
+ If iLen &gt; 1 Then
+ vSubStrings(i) = UCase(Left(vSubStrings(i), 1)) &amp; LCase(Right(vSubStrings(i), iLen - 1))
+ ElseIf iLen = 1 Then
+ vSubStrings(i) = UCase(vSubStrings(i))
+ End If
+ Next i
+ _PCase = Join(vSubStrings, &quot; &quot;)
+
+End Function &apos; PCase V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _PercentEncode(ByVal psChar As String) As String
+&apos; Percent encoding of single psChar character
+&apos; https://en.wikipedia.org/wiki/UTF-8
+
+Dim lChar As Long, sByte1 As String, sByte2 As String, sByte3 As String
+ lChar = Asc(psChar)
+
+ Select Case lChar
+ Case 48 To 57, 65 To 90, 97 To 122 &apos; 0-9, A-Z, a-z
+ _PercentEncode = psChar
+ Case Asc(&quot;-&quot;), Asc(&quot;.&quot;), Asc(&quot;_&quot;), Asc(&quot;~&quot;)
+ _PercentEncode = psChar
+ Case Asc(&quot;!&quot;), Asc(&quot;$&quot;), Asc(&quot;&amp;&quot;), Asc(&quot;&apos;&quot;), Asc(&quot;(&quot;), Asc(&quot;)&quot;), Asc(&quot;*&quot;), Asc(&quot;+&quot;), Asc(&quot;,&quot;), Asc(&quot;;&quot;), Asc(&quot;=&quot;) &apos; Reserved characters used as delimiters in query strings
+ _PercentEncode = psChar
+ Case Asc(&quot; &quot;), Asc(&quot;%&quot;)
+ _PercentEncode = &quot;%&quot; &amp; Right(&quot;00&quot; &amp; Hex(lChar), 2)
+ Case 0 To 127
+ _PercentEncode = psChar
+ Case 128 To 2047
+ sByte1 = &quot;%&quot; &amp; Right(&quot;00&quot; &amp; Hex(Int(lChar / 64) + 192), 2)
+ sByte2 = &quot;%&quot; &amp; Right(&quot;00&quot; &amp; Hex((lChar Mod 64) + 128), 2)
+ _PercentEncode = sByte1 &amp; sByte2
+ Case 2048 To 65535
+ sByte1 = &quot;%&quot; &amp; Right(&quot;00&quot; &amp; Hex(Int(lChar / 4096) + 224), 2)
+ sByte2 = &quot;%&quot; &amp; Right(&quot;00&quot; &amp; Hex(Int(lChar - (4096 * Int(lChar / 4096))) /64 + 128), 2)
+ sByte3 = &quot;%&quot; &amp; Right(&quot;00&quot; &amp; Hex((lChar Mod 64) + 128), 2)
+ _PercentEncode = sByte1 &amp; sByte2 &amp; sByte3
+ Case Else &apos; Not supported
+ _PercentEncode = psChar
+ End Select
+
+ Exit Function
+
+End Function &apos; _PercentEncode V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _ReadFileIntoArray(ByVal psFileName) As Variant
+&apos; Loads all lines of a text file into a Variant array
+&apos; Any error reduces output to an empty array
+&apos; Input file name presumed in URL form
+
+Dim vLines() As Variant, iFile As Integer, sLine As String, iCount1 As Integer, iCount2 As Integer
+Const cstMaxLines = 16000 &apos; +/- the limit of array sizes in Basic
+ On Local Error GoTo Error_Function
+ vLines = Array()
+ _ReadFileIntoArray = Array()
+ If psFileName = &quot;&quot; Then Exit Function
+
+ iFile = FreeFile()
+ Open psFileName For Input Access Read Shared As #iFile
+ iCount1 = 0
+ Do While Not Eof(iFile) And iCount1 &lt; cstMaxLines
+ Line Input #iFile, sLine
+ iCount1 = iCount1 + 1
+ Loop
+ Close #iFile
+
+ ReDim vLines(0 To iCount1 - 1) &apos; Reading file twice preferred to ReDim Preserve for performance reasons
+ iFile = FreeFile()
+ Open psFileName For Input Access Read Shared As #iFile
+ iCount2 = 0
+ Do While Not Eof(iFile) And iCount2 &lt; iCount1
+ Line Input #iFile, vLines(iCount2)
+ iCount2 = iCount2 + 1
+ Loop
+ Close #iFile
+
+Exit_Function:
+ _ReadFileIntoArray() = vLines()
+ Exit Function
+Error_Function:
+ vLines = Array()
+ Resume Exit_Function
+End Function &apos; _ReadFileIntoArray V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _RegexSearch(ByRef psString As String _
+ , ByVal psRegex As String _
+ , Optional ByRef plStart As Long _
+ , Optional ByVal bForward As Boolean _
+ ) As String
+&apos; Search is not case-sensitive
+&apos; Return &quot;&quot; if regex not found, otherwise returns the matching string
+&apos; plStart = start position of psString to search (starts at 1)
+&apos; In output plStart contains the first position of the matching string
+&apos; To search again the same or another pattern =&gt; plStart = plStart + Len(matching string)
+
+Dim oTextSearch As Object
+Dim vOptions As Variant &apos;com.sun.star.util.SearchOptions
+Dim lEnd As Long, vResult As Object
+
+ _RegexSearch = &quot;&quot;
+ Set oTextSearch = _A2B_.TextSearch &apos; UNO XTextSearch service
+ vOptions = _A2B_.SearchOptions
+ vOptions.searchString = psRegex &apos; Pattern to be searched
+ oTextSearch.setOptions(vOptions)
+ If IsMissing(plStart) Then plStart = 1
+ If plStart &lt;= 0 Or plStart &gt; Len(psString) Then Exit Function
+ If IsMissing(bForWard) Then bForward = True
+ If bForward Then
+ lEnd = Len(psString)
+ vResult = oTextSearch.searchForward(psString, plStart - 1, lEnd)
+ Else
+ lEnd = 1
+ vResult = oTextSearch.searchForward(psString, plStart, lEnd - 1)
+ End If
+ With vResult
+ If .subRegExpressions &gt;= 1 Then
+ &apos; http://www.openoffice.org/api/docs/common/ref/com/sun/star/util/SearchResult.html
+ Select Case bForward
+ Case True
+ plStart = .startOffset(0) + 1
+ lEnd = .endOffset(0) + 1
+ Case False
+ plStart = .endOffset(0) + 1
+ lEnd = .startOffset(0)
+ End Select
+ _RegexSearch = Mid(psString, plStart, lEnd - plStart)
+ Else
+ plStart = 0
+ End If
+ End With
+
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _RegisterDialogEventScript(poObject As Object _
+ , ByVal psEvent As String _
+ , ByVal psListener As String _
+ , ByVal psScriptCode As String _
+ ) As Boolean
+&apos; Register a script event (psEvent) to poObject (Dialog or dialog Control)
+
+Dim oEvents As Object, sEvent As String, sEventName As String, oEvent As Object
+
+ _RegisterDialogEventScript = False
+ If Not _hasUNOMethod(poObject, &quot;getEvents&quot;) Then Exit Function
+
+&apos; Remove existing event, if any, then store new script code
+ Set oEvents = poObject.getEvents()
+ sEvent = Utils._GetEventName(psEvent)
+ sEventName = &quot;com.sun.star.awt.&quot; &amp; psListener &amp; &quot;::&quot; &amp; sEvent
+ If oEvents.hasByName(sEventName) Then oEvents.removeByName(sEventName)
+ Set oEvent = CreateUnoStruct(&quot;com.sun.star.script.ScriptEventDescriptor&quot;)
+ With oEvent
+ .ListenerType = psListener
+ .EventMethod = sEvent
+ .ScriptType = &quot;Script&quot; &apos; Better than &quot;Basic&quot;
+ .ScriptCode = psScriptCode
+ End With
+ oEvents.insertByName(sEventName, oEvent)
+
+ _RegisterDialogEventScript = True
+
+End Function &apos; _RegisterDialogEventScript V1.8.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _RegisterEventScript(poObject As Object _
+ , ByVal psEvent As String _
+ , ByVal psListener As String _
+ , ByVal psScriptCode As String _
+ , ByVal psName As String _
+ , Optional ByVal pbExtendName As Boolean _
+ ) As Boolean
+&apos; Register a script event (psEvent) to poObject (Form, SubForm or Control)
+
+Dim i As Integer, oEvent As Object, sEvent As String, oParent As Object, iIndex As Integer, sName As String
+
+ _RegisterEventScript = False
+ If Not _hasUNOMethod(poObject, &quot;getParent&quot;) Then Exit Function
+
+ &apos; Find object internal index i.e. how to reach it via getByIndex()
+ If IsMissing(pbExtendName) Then pbExtendName = False
+ Set oParent = poObject.getParent()
+ iIndex = -1
+ For i = 0 To oParent.getCount() - 1
+ sName = oParent.getByIndex(i).Name
+ If (sName = psName) Or (pbExtendName And (sName = &quot;MainForm&quot; Or sName = &quot;Form&quot;)) Then
+ iIndex = i
+ Exit For
+ End If
+ Next i
+ If iIndex &lt; 0 Then Exit Function
+
+ sEvent = Utils._GetEventName(psEvent) &apos; Targeted event method
+ If psScriptCode = &quot;&quot; Then
+ oParent.revokeScriptEvent(iIndex, psListener, sEvent, &quot;&quot;)
+ Else
+ Set oEvent = CreateUnoStruct(&quot;com.sun.star.script.ScriptEventDescriptor&quot;)
+ With oEvent
+ .ListenerType = psListener
+ .EventMethod = sEvent
+ .ScriptType = &quot;Script&quot; &apos; Better than &quot;Basic&quot;
+ .ScriptCode = psScriptCode
+ End With
+ oParent.registerScriptEvent(iIndex, oEvent)
+ End If
+ _RegisterEventScript = True
+
+End Function &apos; _RegisterEventScript V1.7.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _ResetCalledSub(ByVal psSub As String)
+&apos; Called in bottom of each public function. _A2B_.CalledSub variable is used for error handling
+&apos; Used to trace routine in/outs and to clarify error messages
+ If IsEmpty(_A2B_) Then Call Application._RootInit() &apos; Only when Utils module recompiled
+ With _A2B_
+ If .CalledSub = psSub Then .CalledSub = &quot;&quot;
+ If .MinimalTraceLevel = 1 Then TraceLog(TRACEDEBUG, _GetLabel(&quot;Exiting&quot;) &amp; &quot; &quot; &amp; psSub &amp; &quot; ...&quot;, False)
+ End With
+End Sub &apos; ResetCalledSub
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _RunScript(ByVal psScript As String, Optional pvArgs() As Variant) As Boolean
+&apos; Execute a given script with pvArgs() array of arguments
+
+ On Local Error Goto Error_Function
+ _RunScript = False
+ If IsNull(ThisComponent) Then Goto Exit_Function
+
+Dim oSCriptProvider As Object, oScript As Object, vResult As Variant
+
+ Set oScriptProvider = ThisComponent.ScriptProvider()
+ Set oScript = oScriptProvider.getScript(psScript)
+ If IsMissing(pvArgs()) Then pvArgs() = Array()
+ vResult = oScript.Invoke(pvArgs(), Array(), Array())
+ _RunScript = True
+
+Exit_Function:
+ Exit Function
+Error_Function:
+ _RunScript = False
+ Goto Exit_Function
+End Function
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Sub _SetCalledSub(ByVal psSub As String)
+&apos; Called in top of each public function.
+&apos; Used to trace routine in/outs and to clarify error messages
+ If IsEmpty(_A2B_) Then Call Application._RootInit() &apos; First use of Access2Base in current LibO/AOO session
+ With _A2B_
+ If .CalledSub = &quot;&quot; Then
+ .CalledSub = psSub
+ .LastErrorCode = 0
+ .LastErrorLevel = &quot;&quot;
+ .ErrorText = &quot;&quot;
+ .ErrorLongText = &quot;&quot;
+ End If
+ If .MinimalTraceLevel = 1 Then TraceLog(TRACEDEBUG, _GetLabel(&quot;Entering&quot;) &amp; &quot; &quot; &amp; psSub &amp; &quot; ...&quot;, False)
+ End With
+End Sub &apos; SetCalledSub
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _Surround(ByVal psName As String) As String
+&apos; Return [Name] if Name contains spaces
+&apos; Return [Name1].[Name2].[Name3] if Name1.Name2.Name3 contains dots
+
+Const cstSquareOpen = &quot;[&quot;
+Const cstSquareClose = &quot;]&quot;
+Const cstDot = &quot;.&quot;
+Dim sName As String
+
+ If InStr(psName, &quot;.&quot;) &gt; 0 Then
+ sName = Join(Split(psName, cstDot), cstSquareClose &amp; cstDot &amp; cstSquareOpen)
+ _Surround = cstSquareOpen &amp; sName &amp; cstSquareClose
+ ElseIf InStr(psName, &quot; &quot;) &gt; 0 Then
+ _Surround = cstSquareOpen &amp; psName &amp; cstSquareClose
+ Else
+ _Surround = psName
+ End If
+
+End Function &apos; Surround
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _Trim(ByVal psString As String) As String
+&apos; Remove leading and trailing spaces, remove surrounding square brackets, replace tabs by spaces
+Const cstSquareOpen = &quot;[&quot;
+Const cstSquareClose = &quot;]&quot;
+Dim sTrim As String
+
+ sTrim = Trim(Replace(psString, vbTab, &quot; &quot;))
+ _Trim = sTrim
+ If Len(sTrim) &lt;= 2 Then Exit Function
+
+ If Left(sTrim, 1) = cstSquareOpen Then
+ If Right(sTrim, 1) = cstSquareClose Then
+ _Trim = Mid(sTrim, 2, Len(sTrim) - 2)
+ End If
+ End If
+End Function &apos; Trim V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Public Function _TrimArray(pvArray As Variant) As Variant
+&apos; Remove empty strings from strings array
+
+Dim sTrim As String, vTrim() As Variant, i As Integer, j As Integer, iCount As Integer
+ vTrim = Null
+ If Not IsArray(pvArray) Then
+ If Len(Trim(pvArray)) &gt; 0 Then vTrim = Array(pvArray) Else vTrim = Array()
+ ElseIf UBound(pvArray) &lt; LBound(pvArray) Then &apos; Array empty
+ vTrim = Array()
+ Else
+ iCount = 0
+ For i = LBound(pvArray) To UBound(pvArray)
+ If Len(Trim(pvArray(i))) = 0 Then iCount = iCount + 1
+ Next i
+ If iCount = 0 Then
+ vTrim() = pvArray()
+ ElseIf iCount = UBound(pvArray) - LBound(pvArray) + 1 Then &apos; Array empty or all blanks
+ vTrim() = Array()
+ Else
+ ReDim vTrim(LBound(pvArray) To UBound(pvArray) - iCount)
+ j = 0
+ For i = LBound(pvArray) To UBound(pvArray)
+ If Len(Trim(pvArray(i))) &gt; 0 Then
+ vTrim(j) = pvArray(i)
+ j = j + 1
+ End If
+ Next i
+ End If
+ End If
+
+ _TrimArray() = vTrim()
+
+End Function &apos; TrimArray V0.9.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _UpdateResultSetColumnValue(piRDBMS As Integer _
+ , poResultSet As Object _
+ , ByVal piColIndex As Integer _
+ , ByVal pvValue As Variant _
+ ) As Boolean
+REM store the pvValue for the column specified by ColIndex
+REM get type name from metadata
+
+Dim iType As Integer, vDateTime As Variant, oValue As Object
+Dim bNullable As Boolean, lSize As Long, iValueType As Integer, sValueTypeName As String
+Const cstMaxTextLength = 65535
+Const cstMaxBinlength = 2 * 65535
+
+ On Local Error Goto 0 &apos; Disable error handler
+ _UpdateResultSetColumnValue = False
+ With com.sun.star.sdbc.DataType
+ iType = poResultSet.MetaData.getColumnType(piColIndex)
+ iValueType = VarType(pvValue)
+ sValueTypeName = UCase(poResultSet.MetaData.getColumnTypeName(piColIndex))
+ bNullable = ( poResultSet.MetaData.IsNullable(piColIndex) = com.sun.star.sdbc.ColumnValue.NULLABLE )
+
+ If bNullable And IsNull(pvValue) Then
+ poResultSet.updateNull(piColIndex)
+ Else
+ Select Case iType
+ Case .ARRAY, .DISTINCT, .OBJECT, .OTHER, .REF, .SQLNULL, .STRUCT
+ poResultSet.updateNull(piColIndex)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ poResultSet.updateBytes(piColIndex, pvValue)
+ Case .BIT, .BOOLEAN : poResultSet.updateBoolean(piColIndex, pvValue)
+ Case .DATE : vDateTime = CreateUnoStruct(&quot;com.sun.star.util.Date&quot;)
+ vDateTime.Year = Year(pvValue)
+ vDateTime.Month = Month(pvValue)
+ vDateTime.Day = Day(pvValue)
+ poResultSet.updateDate(piColIndex, vDateTime)
+ Case .DECIMAL, .NUMERIC : poResultSet.updateDouble(piColIndex, pvValue)
+ Case .DOUBLE, .REAL : poResultSet.updateDouble(piColIndex, pvValue)
+ Case .FLOAT : poResultSet.updateFloat(piColIndex, pvValue)
+ Case .INTEGER, .SMALLINT : poResultSet.updateInt(piColIndex, pvValue)
+ Case .BIGINT : poResultSet.updateLong(piColIndex, pvValue)
+ Case .DECIMAL, .NUMERIC : poResultSet.updateDouble(piColIndex, pvValue)
+ Case .TINYINT : poResultSet.updateShort(piColIndex, pvValue)
+ Case .CHAR, .VARCHAR, .LONGVARCHAR, .CLOB
+ If piRDBMS = DBMS_SQLITE And InStr(sValueTypeName, &quot;BINARY&quot;) &gt; 0 Then &apos; Sqlite exception ... !
+ poResultSet.updateBytes(piColIndex, pvValue)
+ Else
+ poResultSet.updateString(piColIndex, pvValue)
+ End If
+ Case .TIME : vDateTime = CreateUnoStruct(&quot;com.sun.star.util.Time&quot;)
+ vDateTime.Hours = Hour(pvValue)
+ vDateTime.Minutes = Minute(pvValue)
+ vDateTime.Seconds = Second(pvValue)
+ &apos;vDateTime.HundredthSeconds = 0
+ poResultSet.updateTime(piColIndex, vDateTime)
+ Case .TIMESTAMP : vDateTime = CreateUnoStruct(&quot;com.sun.star.util.DateTime&quot;)
+ vDateTime.Year = Year(pvValue)
+ vDateTime.Month = Month(pvValue)
+ vDateTime.Day = Day(pvValue)
+ vDateTime.Hours = Hour(pvValue)
+ vDateTime.Minutes = Minute(pvValue)
+ vDateTime.Seconds = Second(pvValue)
+ &apos;vDateTime.HundredthSeconds = 0
+ poResultSet.updateTimestamp(piColIndex, vDateTime)
+ Case Else
+ If bNullable Then poResultSet.updateNull(piColIndex)
+ End Select
+ End If
+
+ End With
+
+ _UpdateResultSetColumnValue = True
+
+End Function &apos; UpdateResultSetColumnValue V 1.6.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _URLEncode(ByVal psToEncode As String) As String
+&apos; http://www.w3schools.com/tags/ref_urlencode.asp
+&apos; http://xkr.us/articles/javascript/encode-compare/
+&apos; http://tools.ietf.org/html/rfc3986
+
+Dim sEncoded As String, sChar As String
+Dim lCurrentChar As Long, bQuestionMark As Boolean
+
+ sEncoded = &quot;&quot;
+ bQuestionMark = False
+ For lCurrentChar = 1 To Len(psToEncode)
+ sChar = Mid(psToEncode, lCurrentChar, 1)
+ Select Case sChar
+ Case &quot; &quot;, &quot;%&quot;
+ sEncoded = sEncoded &amp; _PercentEncode(sChar)
+ Case &quot;?&quot; &apos; Is it the first &quot;?&quot; ?
+ If bQuestionMark Then &apos; &quot;?&quot; introduces in a URL the arguments part
+ sEncoded = sEncoded &amp; _PercentEncode(sChar)
+ Else
+ sEncoded = sEncoded &amp; sChar
+ bQuestionMark = True
+ End If
+ Case &quot;\&quot;
+ If bQuestionMark Then
+ sEncoded = sEncoded &amp; _PercentEncode(sChar)
+ Else
+ sEncoded = sEncoded &amp; &quot;/&quot; &apos; If Windows file naming ...
+ End If
+ Case Else
+ If bQuestionMark Then
+ sEncoded = sEncoded &amp; _PercentEncode(sChar)
+ Else
+ sEncoded = sEncoded &amp; _UTF8Encode(sChar) &apos; Because IE does not support %encoding in first part of URL
+ End If
+ End Select
+ Next lCurrentChar
+
+ _URLEncode = sEncoded
+
+End Function &apos; _URLEncode V1.4.0
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _UTF8Encode(ByVal psChar As String) As String
+&apos; &amp;-encoding of single psChar character (e.g. &quot;é&quot; becomes &quot;&amp;eacute;&quot; or numeric equivalent
+&apos; http://www.w3schools.com/charsets/ref_html_utf8.asp
+
+ Select Case psChar
+ Case &quot;&quot;&quot;&quot; : _UTF8Encode = &quot;&amp;quot;&quot;
+ Case &quot;&amp;&quot; : _UTF8Encode = &quot;&amp;amp;&quot;
+ Case &quot;&lt;&quot; : _UTF8Encode = &quot;&amp;lt;&quot;
+ Case &quot;&gt;&quot; : _UTF8Encode = &quot;&amp;gt;&quot;
+ Case &quot;&apos;&quot; : _UTF8Encode = &quot;&amp;apos;&quot;
+ Case &quot;:&quot;, &quot;/&quot;, &quot;?&quot;, &quot;#&quot;, &quot;[&quot;, &quot;]&quot;, &quot;@&quot; &apos; Reserved characters
+ _UTF8Encode = psChar
+ Case Chr(13) : _UTF8Encode = &quot;&quot; &apos; Carriage return
+ Case Chr(10) : _UTF8Encode = &quot;&lt;br&gt;&quot; &apos; Line Feed
+ Case &lt; Chr(126) : _UTF8Encode = psChar
+ Case &quot;€&quot; : _UTF8Encode = &quot;&amp;euro;&quot;
+ Case Else : _UTF8Encode = &quot;&amp;#&quot; &amp; Asc(psChar) &amp; &quot;;&quot;
+ End Select
+
+ Exit Function
+
+End Function &apos; _UTF8Encode V1.4.0
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/_License.xba b/wizards/source/access2base/_License.xba
new file mode 100644
index 000000000..fa8a5743b
--- /dev/null
+++ b/wizards/source/access2base/_License.xba
@@ -0,0 +1,25 @@
+<?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">
+&apos; Copyright 2012-2017 Jean-Pierre LEDURE
+
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+&apos; Access2Base is distributed in the hope that it will be useful,
+&apos; but WITHOUT ANY WARRANTY; without even the implied warranty of
+&apos; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+&apos; Access2Base is free software; you can redistribute it and/or modify it under the terms of either (at your option):
+&apos;
+&apos; 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
+&apos; distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
+&apos;
+&apos; 2) The GNU Lesser General Public License as published by
+&apos; the Free Software Foundation, either version 3 of the License, or
+&apos; (at your option) any later version. If a copy of the LGPL was not
+&apos; distributed with this file, see http://www.gnu.org/licenses/ .
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/acConstants.xba b/wizards/source/access2base/acConstants.xba
new file mode 100644
index 000000000..85098c7f4
--- /dev/null
+++ b/wizards/source/access2base/acConstants.xba
@@ -0,0 +1,395 @@
+<?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="acConstants" script:language="StarBasic">
+REM =======================================================================================================================
+REM === The Access2Base library is a part of the LibreOffice project. ===
+REM === Full documentation is available on http://www.access2base.com ===
+REM =======================================================================================================================
+
+Option Explicit
+
+REM Access2Base -----------------------------------------------------
+Global Const Access2Base_Version = &quot;7.1.0&quot; &apos; Alignment on LibreOffice versions
+
+REM AcCloseSave
+REM -----------------------------------------------------------------
+Global Const acSaveNo = 2
+Global Const acSavePrompt = 0
+Global Const acSaveYes = 1
+
+REM AcFormView
+REM -----------------------------------------------------------------
+Global Const acDesign = 1
+Global Const acNormal = 0
+Global Const acPreview = 2
+
+REM AcFormOpenDataMode
+REM -----------------------------------------------------------------
+Global Const acFormAdd = 0
+Global Const acFormEdit = 1
+Global Const acFormPropertySettings = -1
+Global Const acFormReadOnly = 2
+
+REM acView
+REM -----------------------------------------------------------------
+Global Const acViewDesign = 1
+Global Const acViewNormal = 0
+Global Const acViewPreview = 2
+
+REM acOpenDataMode
+REM -----------------------------------------------------------------
+Global Const acAdd = 0
+Global Const acEdit = 1
+Global Const acReadOnly = 2
+
+REM AcObjectType
+REM -----------------------------------------------------------------
+Global Const acDefault = -1
+Global Const acDiagram = 8
+Global Const acForm = 2
+Global Const acQuery = 1
+Global Const acReport = 3
+Global Const acTable = 0
+&apos; Unexisting in MS/Access
+Global Const acBasicIDE = 101
+Global Const acDatabaseWindow = 102
+Global Const acDocument = 111
+Global Const acWelcome = 112
+&apos; Subtype if acDocument
+Global Const docWriter = &quot;Writer&quot;
+Global Const docCalc = &quot;Calc&quot;
+Global Const docImpress = &quot;Impress&quot;
+Global Const docDraw = &quot;Draw&quot;
+Global Const docMath = &quot;Math&quot;
+
+REM AcWindowMode
+REM -----------------------------------------------------------------
+Global Const acDialog = 3
+Global Const acHidden = 1
+Global Const acIcon = 2
+Global Const acWindowNormal = 0
+
+REM VarType constants
+REM -----------------------------------------------------------------
+Global Const vbEmpty = 0
+Global Const vbNull = 1
+Global Const vbInteger = 2
+Global Const vbLong = 3
+Global Const vbSingle = 4
+Global Const vbDouble = 5
+Global Const vbCurrency = 6
+Global Const vbDate = 7
+Global Const vbString = 8
+Global Const vbObject = 9
+Global Const vbError = 10
+Global Const vbBoolean = 11
+Global Const vbVariant = 12
+Global Const vbByte = 17
+Global Const vbUShort = 18
+Global Const vbULong = 19
+Global Const vbBigint = 35
+Global Const vbDecimal = 37
+Global Const vbArray = 8192
+
+REM MsgBox constants
+REM -----------------------------------------------------------------
+Global Const vbOKOnly = 0 &apos; OK button only (default)
+Global Const vbOKCancel = 1 &apos; OK and Cancel buttons
+Global Const vbAbortRetryIgnore = 2 &apos; Abort, Retry, and Ignore buttons
+Global Const vbYesNoCancel = 3 &apos; Yes, No, and Cancel buttons
+Global Const vbYesNo = 4 &apos; Yes and No buttons
+Global Const vbRetryCancel = 5 &apos; Retry and Cancel buttons
+Global Const vbCritical = 16 &apos; Critical message
+Global Const vbQuestion = 32 &apos; Warning query
+Global Const vbExclamation = 48 &apos; Warning message
+Global Const vbInformation = 64 &apos; Information message
+Global Const vbDefaultButton1 = 128 &apos; First button is default (default) (VBA: 0)
+Global Const vbDefaultButton2 = 256 &apos; Second button is default
+Global Const vbDefaultButton3 = 512 &apos; Third button is default
+Global Const vbApplicationModal = 0 &apos; Application modal message box (default)
+REM MsgBox Return Values
+REM -----------------------------------------------------------------
+Global Const vbOK = 1 &apos; OK button pressed
+Global Const vbCancel = 2 &apos; Cancel button pressed
+Global Const vbAbort = 3 &apos; Abort button pressed
+Global Const vbRetry = 4 &apos; Retry button pressed
+Global Const vbIgnore = 5 &apos; Ignore button pressed
+Global Const vbYes = 6 &apos; Yes button pressed
+Global Const vbNo = 7 &apos; No button pressed
+
+REM Dialogs Return Values
+REM ------------------------------------------------------------------
+Global Const dlgOK = 1 &apos; OK button pressed
+Global Const dlgCancel = 0 &apos; Cancel button pressed
+
+REM Control Types
+REM -----------------------------------------------------------------
+Global Const acCheckBox = 5
+Global Const acComboBox = 7
+Global Const acCommandButton = 2 : Global Const acToggleButton = 122
+Global Const acCurrencyField = 18
+Global Const acDateField = 15
+Global Const acFileControl = 12
+Global Const acFixedLine = 24 &apos; FREE ENTRY (USEFUL IN DIALOGS)
+Global Const acFixedText = 10 : Global Const acLabel = 10
+Global Const acFormattedField = 1 &apos; FREE ENTRY TAKEN TO NOT CONFUSE WITH acTextField
+Global Const acGridControl = 11
+Global Const acGroupBox = 8 : Global Const acOptionGroup = 8
+Global Const acHiddenControl = 13
+Global Const acImageButton = 4
+Global Const acImageControl = 14 : Global Const acImage = 14
+Global Const acListBox = 6
+Global Const acNavigationBar = 22
+Global Const acNumericField = 17
+Global Const acPatternField = 19
+Global Const acProgressBar = 23 &apos; FREE ENTRY (USEFUL IN DIALOGS)
+Global Const acRadioButton = 3 : Global Const acOptionButton = 3
+Global Const acScrollBar = 20
+Global Const acSpinButton = 21
+Global Const acSubform = 112
+Global Const acTextField = 9 : Global Const acTextBox = 9
+Global Const acTimeField = 16
+
+REM AcRecord
+REM -----------------------------------------------------------------
+Global Const acFirst = 2
+Global Const acGoTo = 4
+Global Const acLast = 3
+Global Const acNewRec = 5
+Global Const acNext = 1
+Global Const acPrevious = 0
+
+REM FindRecord
+REM -----------------------------------------------------------------
+Global Const acAnywhere = 0
+Global Const acEntire = 1
+Global Const acStart = 2
+Global Const acDown = 1
+Global Const acSearchAll = 2
+Global Const acUp = 0
+Global Const acAll = 0
+Global Const acCurrent = -1
+
+REM AcDataObjectType
+REM -----------------------------------------------------------------
+Global Const acActiveDataObject = -1
+Global Const acDataForm = 2
+Global Const acDataQuery = 1
+Global Const acDataServerView = 7
+Global Const acDataStoredProcedure = 9
+Global Const acDataTable = 0
+
+REM AcQuitOption
+REM -----------------------------------------------------------------
+Global Const acQuitPrompt = 0
+Global Const acQuitSaveAll = 1
+Global Const acQuitSaveNone = 2
+
+REM AcCommand
+REM -----------------------------------------------------------------
+Global Const acCmdAboutMicrosoftAccess = 35
+Global Const acCmdAboutOpenOffice = 35
+Global Const acCmdAboutLibreOffice = 35
+Global Const acCmdVisualBasicEditor = 525
+Global Const acCmdBringToFront = 52
+Global Const acCmdClose = 58
+Global Const acCmdToolbarsCustomize = 165
+Global Const acCmdChangeToCommandButton = 501
+Global Const acCmdChangeToCheckBox = 231
+Global Const acCmdChangeToComboBox = 230
+Global Const acCmdChangeToTextBox = 227
+Global Const acCmdChangeToLabel = 228
+Global Const acCmdChangeToImage = 234
+Global Const acCmdChangeToListBox = 229
+Global Const acCmdChangeToOptionButton = 233
+Global Const acCmdCopy = 190
+Global Const acCmdCut = 189
+Global Const acCmdCreateRelationship = 150
+Global Const acCmdDelete = 337
+Global Const acCmdDatabaseProperties = 256
+Global Const acCmdSQLView = 184
+Global Const acCmdRemove = 366
+Global Const acCmdDesignView = 183
+Global Const acCmdFormView = 281
+Global Const acCmdNewObjectForm = 136
+Global Const acCmdNewObjectTable = 134
+Global Const acCmdNewObjectView = 350
+Global Const acCmdOpenDatabase = 25
+Global Const acCmdNewObjectQuery = 135
+Global Const acCmdShowAllRelationships = 149
+Global Const acCmdNewObjectReport = 137
+Global Const acCmdSelectAll = 333
+Global Const acCmdRemoveTable = 84
+Global Const acCmdOpenTable = 221
+Global Const acCmdRename = 143
+Global Const acCmdDeleteRecord = 223
+Global Const acCmdApplyFilterSort = 93
+Global Const acCmdSnapToGrid = 62
+Global Const acCmdViewGrid = 63
+Global Const acCmdInsertHyperlink = 259
+Global Const acCmdMaximumRecords = 508
+Global Const acCmdObjectBrowser = 200
+Global Const acCmdPaste = 191
+Global Const acCmdPasteSpecial = 64
+Global Const acCmdPrint = 340
+Global Const acCmdPrintPreview = 54
+Global Const acCmdSaveRecord = 97
+Global Const acCmdFind = 30
+Global Const acCmdUndo = 292
+Global Const acCmdRefresh = 18
+Global Const acCmdRemoveFilterSort = 144
+Global Const acCmdRunMacro = 31
+Global Const acCmdSave = 20
+Global Const acCmdSaveAs = 21
+Global Const acCmdSelectAllRecords = 109
+Global Const acCmdSendToBack = 53
+Global Const acCmdSortDescending = 164
+Global Const acCmdSortAscending = 163
+Global Const acCmdTabOrder = 41
+Global Const acCmdDatasheetView = 282
+Global Const acCmdZoomSelection = 371
+
+REM AcSendObjectType
+REM -----------------------------------------------------------------
+Global Const acSendForm = 2
+Global Const acSendNoObject = -1
+Global Const acSendQuery = 1
+Global Const acSendReport = 3
+Global Const acSendTable = 0
+
+REM AcOutputObjectType
+REM -----------------------------------------------------------------
+Global Const acOutputTable = 0
+Global Const acOutputQuery = 1
+Global Const acOutputForm = 2
+Global Const acOutputArray = -1
+
+REM AcEncoding
+REM -----------------------------------------------------------------
+Global Const acUTF8Encoding = 76
+
+REM AcFormat
+REM -----------------------------------------------------------------
+Global Const acFormatPDF = &quot;writer_pdf_Export&quot;
+Global Const acFormatODT = &quot;writer8&quot;
+Global Const acFormatDOC = &quot;MS Word 97&quot;
+Global Const acFormatHTML = &quot;HTML&quot;
+Global Const acFormatODS = &quot;calc8&quot;
+Global Const acFormatXLS = &quot;MS Excel 97&quot;
+Global Const acFormatXLSX = &quot;Calc MS Excel 2007 XML&quot;
+Global Const acFormatTXT = &quot;Text - txt - csv (StarCalc)&quot;
+
+REM AcExportQuality
+REM -----------------------------------------------------------------
+Global Const acExportQualityPrint = 0
+Global Const acExportQualityScreen = 1
+
+REM AcSysCmdAction
+REM -----------------------------------------------------------------
+Global Const acSysCmdAccessDir = 9
+Global Const acSysCmdAccessVer = 7
+Global Const acSysCmdClearHelpTopic = 11
+Global Const acSysCmdClearStatus = 5
+Global Const acSysCmdGetObjectState = 10
+Global Const acSysCmdGetWorkgroupFile = 13
+Global Const acSysCmdIniFile = 8
+Global Const acSysCmdInitMeter = 1
+Global Const acSysCmdProfile = 12
+Global Const acSysCmdRemoveMeter = 3
+Global Const acSysCmdRuntime = 6
+Global Const acSysCmdSetStatus = 4
+Global Const acSysCmdUpdateMeter = 2
+
+REM Type property
+REM -----------------------------------------------------------------
+Global Const dbBigInt = 16
+Global Const dbBinary = 9
+Global Const dbBoolean = 1
+Global Const dbByte = 2
+Global Const dbChar = 18
+Global Const dbCurrency = 5
+Global Const dbDate = 8
+Global Const dbDecimal = 20
+Global Const dbDouble = 7
+Global Const dbFloat = 21
+Global Const dbGUID = 15
+Global Const dbInteger = 3
+Global Const dbLong = 4
+Global Const dbLongBinary = 11 &apos; (OLE Object)
+Global Const dbMemo= 12
+Global Const dbNumeric = 19
+Global Const dbSingle = 6
+Global Const dbText = 10
+Global Const dbTime = 22
+Global Const dbTimeStamp = 23
+Global Const dbVarBinary = 17
+Global Const dbUndefined = -1
+
+REM Attributes property
+REM -----------------------------------------------------------------
+Global Const dbAutoIncrField = 16
+Global Const dbDescending = 1
+Global Const dbFixedField = 1
+Global Const dbHyperlinkField = 32768
+Global Const dbSystemField = 8192
+Global Const dbUpdatableField = 32
+Global Const dbVariableField = 2
+
+REM OpenRecordset
+REM -----------------------------------------------------------------
+Global Const dbOpenForwardOnly = 8
+Global Const dbSQLPassThrough = 64
+Global Const dbReadOnly = 4
+
+REM Query types
+REM -----------------------------------------------------------------
+Global Const dbQAction = 240
+Global Const dbQAppend = 64
+Global Const dbQDDL = 4 &apos;96
+Global Const dbQDelete = 32
+Global Const dbQMakeTable = 128 &apos;80
+Global Const dbQSelect = 0
+Global Const dbQSetOperation = 8 &apos;128
+Global Const dbQSQLPassThrough = 1 &apos;112
+Global Const dbQUpdate = 16 &apos;48
+
+REM Edit mode
+REM -----------------------------------------------------------------
+Global Const dbEditNone = 0
+Global Const dbEditInProgress = 1
+Global Const dbEditAdd = 2
+
+REM Toolbars
+REM -----------------------------------------------------------------
+Global Const msoBarTypeNormal = 0 &apos; Usual toolbar
+Global Const msoBarTypeMenuBar = 1 &apos; Menu bar
+Global Const msoBarTypePopup = 2 &apos; Shortcut menu
+Global Const msoBarTypeStatusBar = 11 &apos; Status bar
+Global Const msoBarTypeFloater = 12 &apos; Floating window
+
+Global Const msoControlButton = 1 &apos; Command button
+Global Const msoControlPopup = 10 &apos; Popup, submenu
+
+REM New Lines
+REM -----------------------------------------------------------------
+Public Function vbCr() As String : vbCr = Chr(13) : End Function
+Public Function vbLf() As String : vbLf = Chr(10) : End Function
+Public Function vbNewLine() As String
+Const cstWindows = 1
+ If GetGuiType() = cstWindows Then vbNewLine = vbCR &amp; vbLF Else vbNewLine = vbLF
+End Function &apos; vbNewLine V1.4.0
+Public Function vbTab() As String : vbTab = Chr(9) : End Function
+
+REM Module types
+REM -----------------------------------------------------------------
+Global Const acClassModule = 1
+Global Const acStandardModule = 0
+
+REM (Module) procedure types
+REM -----------------------------------------------------------------
+Global Const vbext_pk_Get = 1 &apos; A Property Get procedure
+Global Const vbext_pk_Let = 2 &apos; A Property Let procedure
+Global Const vbext_pk_Proc = 0 &apos; A Sub or Function procedure
+Global Const vbext_pk_Set = 3 &apos; A Property Set procedure
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/access2base/access2base.py b/wizards/source/access2base/access2base.py
new file mode 100644
index 000000000..ff0a9fbaa
--- /dev/null
+++ b/wizards/source/access2base/access2base.py
@@ -0,0 +1,1473 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2012-2020 Jean-Pierre LEDURE
+
+# =====================================================================================================================
+# === The Access2Base library is a part of the LibreOffice project. ===
+# === Full documentation is available on http://www.access2base.com ===
+# =====================================================================================================================
+
+# Access2Base is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# Access2Base is free software; you can redistribute it and/or modify it under the terms of either (at your option):
+
+# 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
+# distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
+
+# 2) The GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version. If a copy of the LGPL was not
+# distributed with this file, see http://www.gnu.org/licenses/ .
+
+"""
+The access2base.py module implements an interface between Python (user) scripts and the Access2Base Basic library.
+
+Usage:
+ from access2base import *
+Additionally, if Python and LibreOffice are started in separate processes:
+ If LibreOffice started from console ... (example for Linux)
+ ./soffice --accept='socket,host=localhost,port=2019;urp;'
+ then insert next statement
+ A2BConnect(hostname = 'localhost', port = 2019)
+
+Specific documentation about Access2Base and Python:
+ http://www.access2base.com/access2base.html#%5B%5BAccess2Base%20and%20Python%5D%5D
+"""
+
+import uno
+XSCRIPTCONTEXT = uno
+
+from platform import system as _opsys
+import datetime, os, sys, traceback
+
+_LIBRARY = '' # Should be 'Access2Base' or 'Access2BaseDev'
+_VERSION = '7.4' # Actual version number
+_WRAPPERMODULE = 'Python' # Module name in the Access2Base library containing Python interfaces
+
+# CallByName types
+_vbGet, _vbLet, _vbMethod, _vbSet, _vbUNO = 2, 4, 1, 8, 16
+
+
+class _Singleton(type):
+ """
+ A Singleton design pattern
+ Credits: « Python in a Nutshell » by Alex Martelli, O'Reilly
+ """
+ instances = {}
+ def __call__(cls, *args, **kwargs):
+ if cls not in cls.instances:
+ cls.instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
+ return cls.instances[cls]
+
+
+class acConstants(object, metaclass = _Singleton):
+ """
+ VBA constants used in the Access2Base API.
+ Values derived from MSAccess, except when conflicts
+ """
+ # Python special constants (used in the protocol between Python and Basic)
+ # -----------------------------------------------------------------
+ Empty = '+++EMPTY+++'
+ Null = '+++NULL+++'
+ Missing = '+++MISSING+++'
+ FromIsoFormat = '%Y-%m-%d %H:%M:%S' # To be used with datetime.datetime.strptime()
+
+ # AcCloseSave
+ # -----------------------------------------------------------------
+ acSaveNo = 2
+ acSavePrompt = 0
+ acSaveYes = 1
+
+ # AcFormView
+ # -----------------------------------------------------------------
+ acDesign = 1
+ acNormal = 0
+ acPreview = 2
+
+ # AcFormOpenDataMode
+ # -----------------------------------------------------------------
+ acFormAdd = 0
+ acFormEdit = 1
+ acFormPropertySettings = -1
+ acFormReadOnly = 2
+
+ # acView
+ # -----------------------------------------------------------------
+ acViewDesign = 1
+ acViewNormal = 0
+ acViewPreview = 2
+
+ # acOpenDataMode
+ # -----------------------------------------------------------------
+ acAdd = 0
+ acEdit = 1
+ acReadOnly = 2
+
+ # AcObjectType
+ # -----------------------------------------------------------------
+ acDefault = -1
+ acDiagram = 8
+ acForm = 2
+ acQuery = 1
+ acReport = 3
+ acTable = 0
+ # Unexisting in MS/Access
+ acBasicIDE = 101
+ acDatabaseWindow = 102
+ acDocument = 111
+ acWelcome = 112
+ # Subtype if acDocument
+ docWriter = "Writer"
+ docCalc = "Calc"
+ docImpress = "Impress"
+ docDraw = "Draw"
+ docMath = "Math"
+
+ # AcWindowMode
+ # -----------------------------------------------------------------
+ acDialog = 3
+ acHidden = 1
+ acIcon = 2
+ acWindowNormal = 0
+
+ # VarType constants
+ # -----------------------------------------------------------------
+ vbEmpty = 0
+ vbNull = 1
+ vbInteger = 2
+ vbLong = 3
+ vbSingle = 4
+ vbDouble = 5
+ vbCurrency = 6
+ vbDate = 7
+ vbString = 8
+ vbObject = 9
+ vbBoolean = 11
+ vbVariant = 12
+ vbByte = 17
+ vbUShort = 18
+ vbULong = 19
+ vbBigint = 35
+ vbDecimal = 37
+ vbArray = 8192
+
+ # MsgBox constants
+ # -----------------------------------------------------------------
+ vbOKOnly = 0 # OK button only (default)
+ vbOKCancel = 1 # OK and Cancel buttons
+ vbAbortRetryIgnore = 2 # Abort, Retry, and Ignore buttons
+ vbYesNoCancel = 3 # Yes, No, and Cancel buttons
+ vbYesNo = 4 # Yes and No buttons
+ vbRetryCancel = 5 # Retry and Cancel buttons
+ vbCritical = 16 # Critical message
+ vbQuestion = 32 # Warning query
+ vbExclamation = 48 # Warning message
+ vbInformation = 64 # Information message
+ vbDefaultButton1 = 128 # First button is default (default) (VBA: 0)
+ vbDefaultButton2 = 256 # Second button is default
+ vbDefaultButton3 = 512 # Third button is default
+ vbApplicationModal = 0 # Application modal message box (default)
+ # MsgBox Return Values
+ # -----------------------------------------------------------------
+ vbOK = 1 # OK button pressed
+ vbCancel = 2 # Cancel button pressed
+ vbAbort = 3 # Abort button pressed
+ vbRetry = 4 # Retry button pressed
+ vbIgnore = 5 # Ignore button pressed
+ vbYes = 6 # Yes button pressed
+ vbNo = 7 # No button pressed
+
+ # Dialogs Return Values
+ # ------------------------------------------------------------------
+ dlgOK = 1 # OK button pressed
+ dlgCancel = 0 # Cancel button pressed
+
+ # Control Types
+ # -----------------------------------------------------------------
+ acCheckBox = 5
+ acComboBox = 7
+ acCommandButton = 2
+ acToggleButton = 122
+ acCurrencyField = 18
+ acDateField = 15
+ acFileControl = 12
+ acFixedLine = 24 # FREE ENTRY (USEFUL IN DIALOGS)
+ acFixedText = 10
+ acLabel = 10
+ acFormattedField = 1 # FREE ENTRY TAKEN TO NOT CONFUSE WITH acTextField
+ acGridControl = 11
+ acGroupBox = 8
+ acOptionGroup = 8
+ acHiddenControl = 13
+ acImageButton = 4
+ acImageControl = 14
+ acImage = 14
+ acListBox = 6
+ acNavigationBar = 22
+ acNumericField = 17
+ acPatternField = 19
+ acProgressBar = 23 # FREE ENTRY (USEFUL IN DIALOGS)
+ acRadioButton = 3
+ acOptionButton = 3
+ acScrollBar = 20
+ acSpinButton = 21
+ acSubform = 112
+ acTextField = 9
+ acTextBox = 9
+ acTimeField = 16
+
+ # AcRecord
+ # -----------------------------------------------------------------
+ acFirst = 2
+ acGoTo = 4
+ acLast = 3
+ acNewRec = 5
+ acNext = 1
+ acPrevious = 0
+
+ # FindRecord
+ # -----------------------------------------------------------------
+ acAnywhere = 0
+ acEntire = 1
+ acStart = 2
+ acDown = 1
+ acSearchAll = 2
+ acUp = 0
+ acAll = 0
+ acCurrent = -1
+
+ # AcDataObjectType
+ # -----------------------------------------------------------------
+ acActiveDataObject = -1
+ acDataForm = 2
+ acDataQuery = 1
+ acDataServerView = 7
+ acDataStoredProcedure = 9
+ acDataTable = 0
+
+ # AcQuitOption
+ # -----------------------------------------------------------------
+ acQuitPrompt = 0
+ acQuitSaveAll = 1
+ acQuitSaveNone = 2
+
+ # AcCommand
+ # -----------------------------------------------------------------
+ acCmdAboutMicrosoftAccess = 35
+ acCmdAboutOpenOffice = 35
+ acCmdAboutLibreOffice = 35
+ acCmdVisualBasicEditor = 525
+ acCmdBringToFront = 52
+ acCmdClose = 58
+ acCmdToolbarsCustomize = 165
+ acCmdChangeToCommandButton = 501
+ acCmdChangeToCheckBox = 231
+ acCmdChangeToComboBox = 230
+ acCmdChangeToTextBox = 227
+ acCmdChangeToLabel = 228
+ acCmdChangeToImage = 234
+ acCmdChangeToListBox = 229
+ acCmdChangeToOptionButton = 233
+ acCmdCopy = 190
+ acCmdCut = 189
+ acCmdCreateRelationship = 150
+ acCmdDelete = 337
+ acCmdDatabaseProperties = 256
+ acCmdSQLView = 184
+ acCmdRemove = 366
+ acCmdDesignView = 183
+ acCmdFormView = 281
+ acCmdNewObjectForm = 136
+ acCmdNewObjectTable = 134
+ acCmdNewObjectView = 350
+ acCmdOpenDatabase = 25
+ acCmdNewObjectQuery = 135
+ acCmdShowAllRelationships = 149
+ acCmdNewObjectReport = 137
+ acCmdSelectAll = 333
+ acCmdRemoveTable = 84
+ acCmdOpenTable = 221
+ acCmdRename = 143
+ acCmdDeleteRecord = 223
+ acCmdApplyFilterSort = 93
+ acCmdSnapToGrid = 62
+ acCmdViewGrid = 63
+ acCmdInsertHyperlink = 259
+ acCmdMaximumRecords = 508
+ acCmdObjectBrowser = 200
+ acCmdPaste = 191
+ acCmdPasteSpecial = 64
+ acCmdPrint = 340
+ acCmdPrintPreview = 54
+ acCmdSaveRecord = 97
+ acCmdFind = 30
+ acCmdUndo = 292
+ acCmdRefresh = 18
+ acCmdRemoveFilterSort = 144
+ acCmdRunMacro = 31
+ acCmdSave = 20
+ acCmdSaveAs = 21
+ acCmdSelectAllRecords = 109
+ acCmdSendToBack = 53
+ acCmdSortDescending = 164
+ acCmdSortAscending = 163
+ acCmdTabOrder = 41
+ acCmdDatasheetView = 282
+ acCmdZoomSelection = 371
+
+ # AcSendObjectType
+ # -----------------------------------------------------------------
+ acSendForm = 2
+ acSendNoObject = -1
+ acSendQuery = 1
+ acSendReport = 3
+ acSendTable = 0
+
+ # AcOutputObjectType
+ # -----------------------------------------------------------------
+ acOutputTable = 0
+ acOutputQuery = 1
+ acOutputForm = 2
+ acOutputArray = -1
+
+ # AcEncoding
+ # -----------------------------------------------------------------
+ acUTF8Encoding = 76
+
+ # AcFormat
+ # -----------------------------------------------------------------
+ acFormatPDF = "writer_pdf_Export"
+ acFormatODT = "writer8"
+ acFormatDOC = "MS Word 97"
+ acFormatHTML = "HTML"
+ acFormatODS = "calc8"
+ acFormatXLS = "MS Excel 97"
+ acFormatXLSX = "Calc MS Excel 2007 XML"
+ acFormatTXT = "Text - txt - csv (StarCalc)"
+
+ # AcExportQuality
+ # -----------------------------------------------------------------
+ acExportQualityPrint = 0
+ acExportQualityScreen = 1
+
+ # AcSysCmdAction
+ # -----------------------------------------------------------------
+ acSysCmdAccessDir = 9
+ acSysCmdAccessVer = 7
+ acSysCmdClearHelpTopic = 11
+ acSysCmdClearStatus = 5
+ acSysCmdGetObjectState = 10
+ acSysCmdGetWorkgroupFile = 13
+ acSysCmdIniFile = 8
+ acSysCmdInitMeter = 1
+ acSysCmdProfile = 12
+ acSysCmdRemoveMeter = 3
+ acSysCmdRuntime = 6
+ acSysCmdSetStatus = 4
+ acSysCmdUpdateMeter = 2
+
+ # Type property
+ # -----------------------------------------------------------------
+ dbBigInt = 16
+ dbBinary = 9
+ dbBoolean = 1
+ dbByte = 2
+ dbChar = 18
+ dbCurrency = 5
+ dbDate = 8
+ dbDecimal = 20
+ dbDouble = 7
+ dbFloat = 21
+ dbGUID = 15
+ dbInteger = 3
+ dbLong = 4
+ dbLongBinary = 11 # (OLE Object)
+ dbMemo = 12
+ dbNumeric = 19
+ dbSingle = 6
+ dbText = 10
+ dbTime = 22
+ dbTimeStamp = 23
+ dbVarBinary = 17
+ dbUndefined = -1
+
+ # Attributes property
+ # -----------------------------------------------------------------
+ dbAutoIncrField = 16
+ dbDescending = 1
+ dbFixedField = 1
+ dbHyperlinkField = 32768
+ dbSystemField = 8192
+ dbUpdatableField = 32
+ dbVariableField = 2
+
+ # OpenRecordset
+ # -----------------------------------------------------------------
+ dbOpenForwardOnly = 8
+ dbSQLPassThrough = 64
+ dbReadOnly = 4
+
+ # Query types
+ # -----------------------------------------------------------------
+ dbQAction = 240
+ dbQAppend = 64
+ dbQDDL = 4 # 96
+ dbQDelete = 32
+ dbQMakeTable = 128 # 80
+ dbQSelect = 0
+ dbQSetOperation = 8 # 128
+ dbQSQLPassThrough = 1 # 112
+ dbQUpdate = 16 # 48
+
+ # Edit mode
+ # -----------------------------------------------------------------
+ dbEditNone = 0
+ dbEditInProgress = 1
+ dbEditAdd = 2
+
+ # Toolbars
+ # -----------------------------------------------------------------
+ msoBarTypeNormal = 0 # Usual toolbar
+ msoBarTypeMenuBar = 1 # Menu bar
+ msoBarTypePopup = 2 # Shortcut menu
+ msoBarTypeStatusBar = 11 # Status bar
+ msoBarTypeFloater = 12 # Floating window
+
+ msoControlButton = 1 # Command button
+ msoControlPopup = 10 # Popup, submenu
+
+ # New Lines
+ # -----------------------------------------------------------------
+ vbCr = chr(13)
+ vbLf = chr(10)
+
+ def _NewLine():
+ if _opsys == 'Windows': return chr(13) + chr(10)
+ return chr(10)
+
+ vbNewLine = _NewLine()
+ vbTab = chr(9)
+
+ # Module types
+ # -----------------------------------------------------------------
+ acClassModule = 1
+ acStandardModule = 0
+
+ # (Module) procedure types
+ # -----------------------------------------------------------------
+ vbext_pk_Get = 1 # A Property Get procedure
+ vbext_pk_Let = 2 # A Property Let procedure
+ vbext_pk_Proc = 0 # A Sub or Function procedure
+ vbext_pk_Set = 3 # A Property Set procedure
+
+
+COMPONENTCONTEXT, DESKTOP, SCRIPTPROVIDER, THISDATABASEDOCUMENT = None, None, None, None
+
+def _ErrorHandler(type, value, tb):
+ '''
+ Is the function to be set as new sys.excepthook to bypass the standard error handler
+ Derived from https://stackoverflow.com/questions/31949760/how-to-limit-python-traceback-to-specific-files
+ Handler removes traces pointing to methods located in access2base.py when error is due to a user programming error
+ sys.excepthook = _ErrorHandler
+ NOT APPLIED YET
+ '''
+
+ def check_file(name):
+ return 'access2base.py' not in name
+
+ show = (fs for fs in traceback.extract_tb(tb) if check_file(fs.filename))
+ fmt = traceback.format_list(show) + traceback.format_exception_only(type, value)
+ print(''.join(fmt), end = '', file = sys.stderr)
+ # Reset to standard handler
+ sys.excepthook = sys.__excepthook__
+
+
+def A2BConnect(hostname = '', port = 0):
+ """
+ To be called explicitly by user scripts when Python process runs outside the LibreOffice process.
+ LibreOffice started as (Linux):
+ ./soffice --accept='socket,host=localhost,port=xxxx;urp;'
+ Otherwise called implicitly by the current module without arguments
+ Initializes COMPONENTCONTEXT, SCRIPTPROVIDER and DESKTOP
+ :param hostname: probably 'localhost' or ''
+ :param port: port number or 0
+ :return: None
+ """
+ global XSCRIPTCONTEXT, COMPONENTCONTEXT, DESKTOP, SCRIPTPROVIDER
+ # Determine COMPONENTCONTEXT, via socket or inside LibreOffice
+ if len(hostname) > 0 and port > 0: # Explicit connection request via socket
+ # Code derived from Bridge.py by Alain H. Romedenne
+ local_context = XSCRIPTCONTEXT.getComponentContext()
+ resolver = local_context.ServiceManager.createInstanceWithContext(
+ 'com.sun.star.bridge.UnoUrlResolver', local_context)
+ try:
+ conn = 'socket,host=%s,port=%d' % (hostname, port)
+ connection_url = 'uno:%s;urp;StarOffice.ComponentContext' % conn
+ established_context = resolver.resolve(connection_url)
+ except Exception: # thrown when LibreOffice specified instance isn't started
+ raise ConnectionError('Connection to LibreOffice failed (host = ' + hostname + ', port = ' + str(port) + ')')
+ COMPONENTCONTEXT = established_context
+ DESKTOP = None
+ elif len(hostname) == 0 and port == 0: # Usual interactive mode
+ COMPONENTCONTEXT = XSCRIPTCONTEXT.getComponentContext()
+ DESKTOP = COMPONENTCONTEXT.ServiceManager.createInstanceWithContext( 'com.sun.star.frame.Desktop', COMPONENTCONTEXT)
+ else:
+ raise SystemExit('The invocation of A2BConnect() has invalid arguments')
+ # Determine SCRIPTPROVIDER
+ servicemanager = COMPONENTCONTEXT.ServiceManager
+ masterscript = servicemanager.createInstanceWithContext("com.sun.star.script.provider.MasterScriptProviderFactory", COMPONENTCONTEXT)
+ SCRIPTPROVIDER = masterscript.createScriptProvider("")
+ Script = _A2B.xScript('TraceLog', 'Trace') # Don't use invokeMethod() to force reset of error stack
+ Script.invoke(('===>', 'Python wrapper loaded V.' + _VERSION, False), (), ())
+ return None
+
+
+class _A2B(object, metaclass = _Singleton):
+ """
+ Collection of helper functions implementing the protocol between Python and Basic
+ Read comments in PythonWrapper Basic function
+ """
+
+ @classmethod
+ def BasicObject(cls, objectname):
+ objs = {'COLLECTION': _Collection
+ , 'COMMANDBAR': _CommandBar
+ , 'COMMANDBARCONTROL': _CommandBarControl
+ , 'CONTROL': _Control
+ , 'DATABASE': _Database
+ , 'DIALOG': _Dialog
+ , 'EVENT': _Event
+ , 'FIELD': _Field
+ , 'FORM': _Form
+ , 'MODULE': _Module
+ , 'OPTIONGROUP': _OptionGroup
+ , 'PROPERTY': _Property
+ , 'QUERYDEF': _QueryDef
+ , 'RECORDSET': _Recordset
+ , 'SUBFORM': _SubForm
+ , 'TABLEDEF': _TableDef
+ , 'TEMPVAR': _TempVar
+ }
+ return objs[objectname]
+
+ @classmethod
+ def xScript(cls, script, module):
+ """
+ At first call checks the existence of the Access2Base library
+ Initializes _LIBRARY with the found library name
+ First and next calls execute the given script in the given module of the _LIBRARY library
+ The script and module are presumed to exist
+ :param script: name of script
+ :param module: name of module
+ :return: the script object. NB: the execution is done with the invoke() method applied on the returned object
+ """
+ global _LIBRARY
+ Script = None
+ def sScript(lib):
+ return 'vnd.sun.star.script:' + lib + '.' + module + '.' + script + '?language=Basic&location=application'
+ if _LIBRARY == '':
+ # Check the availability of the Access2Base library
+ for lib in ('Access2BaseDev', 'Access2Base'):
+ try:
+ if Script == None:
+ Script = SCRIPTPROVIDER.getScript(sScript(lib))
+ _LIBRARY = lib
+ except Exception:
+ pass
+ if Script == None:
+ raise SystemExit('Access2Base basic library not found')
+ else:
+ Script = SCRIPTPROVIDER.getScript(sScript(_LIBRARY))
+ return Script
+
+ @classmethod
+ def A2BErrorCode(cls):
+ """
+ Return the Access2Base error stack as a tuple
+ 0 => error code
+ 1 => severity level
+ 2 => short error message
+ 3 => long error message
+ """
+ Script = cls.xScript('TraceErrorCode', 'Trace')
+ return Script.invoke((), (), ())[0]
+
+ @classmethod
+ def invokeMethod(cls, script, module, *args):
+ """
+ Direct call to a named script/module pair with their arguments
+ If the arguments do not match their definition at the Basic side, a TypeError is raised
+ :param script: name of script
+ :param module: name of module
+ :param args: list of arguments to be passed to the script
+ :return: the value returned by the script execution
+ """
+ if COMPONENTCONTEXT == None: A2BConnect() # Connection from inside LibreOffice is done at first API invocation
+ Script = cls.xScript(script, module)
+ try:
+ Returned = Script.invoke((args), (), ())[0]
+ except Exception:
+ raise TypeError("Access2Base error: method '" + script + "' in Basic module '" + module + "' call error. Check its arguments.")
+ else:
+ if Returned == None:
+ if cls.VerifyNoError(): return None
+ return Returned
+
+ @classmethod
+ def invokeWrapper(cls, action, basic, script, *args):
+ """
+ Call the Basic wrapper to invite it to execute the proposed action on a Basic object
+ If the arguments do not match their definition at the Basic side, a TypeError is raised
+ After execution, a check is done if the execution has raised an error within Basic
+ If yes, a TypeError is raised
+ :param action: Property Get, Property Let, Property Set, invoke Method or return UNO object
+ :param basic: the reference of the Basic object, i.e. the index in the array caching the addresses of the objects
+ conventionally Application = -1 and DoCmd = -2
+ :param script: the property or method name
+ :param args: the arguments of the method, if any
+ :return: the value returned by the execution of the Basic routine
+ """
+ if COMPONENTCONTEXT == None: A2BConnect() # Connection from inside LibreOffice is done at first API invocation
+ # Intercept special call to Application.Events()
+ if basic == Application.basicmodule and script == 'Events':
+ Script = cls.xScript('PythonEventsWrapper', _WRAPPERMODULE)
+ Returned = Script.invoke((args[0],), (), ())
+ else:
+ Script = cls.xScript('PythonWrapper', _WRAPPERMODULE)
+ NoArgs = '+++NOARGS+++' # Conventional notation for properties/methods without arguments
+ if len(args) == 0:
+ args = (action,) + (basic,) + (script,) + (NoArgs,)
+ else:
+ args = (action,) + (basic,) + (script,) + args
+ try:
+ Returned = Script.invoke((args), (), ())
+ except Exception:
+ raise TypeError("Access2Base error: method '" + script + "' call error. Check its arguments.")
+
+ if isinstance(Returned[0], tuple):
+ # Is returned value a reference to a basic object, a scalar or a UNO object ?
+ if len(Returned[0]) in (3, 4):
+ if Returned[0][0] == 0: # scalar
+ return Returned[0][1]
+ elif Returned[0][0] == 1: # reference to objects cache
+ basicobject = cls.BasicObject(Returned[0][2])
+ if len(Returned[0]) == 3:
+ return basicobject(Returned[0][1], Returned[0][2])
+ else:
+ return basicobject(Returned[0][1], Returned[0][2], Returned[0][3])
+ elif Returned[0][0] == 2: # Null value
+ return None
+ else: # Should not happen
+ return None
+ else: # UNO object
+ return Returned[0]
+ elif Returned[0] == None:
+ if cls.VerifyNoError(): return None
+ else: # Should not happen
+ return Returned[0]
+
+ @classmethod
+ def VerifyNoError(cls):
+ # has Access2Base generated an error ?
+ errorstack = cls.A2BErrorCode() # 0 = code, 1 = severity, 2 = short text, 3 = long text
+ if errorstack[1] in ('ERROR', 'FATAL', 'ABORT'):
+ raise TypeError('Access2Base error: ' + errorstack[3])
+ return True
+
+
+class Application(object, metaclass = _Singleton):
+ """ Collection of methods located in the Application (Basic) module """
+ W = _A2B.invokeWrapper
+ basicmodule = -1
+
+ @classmethod
+ def AllDialogs(cls, dialog = acConstants.Missing):
+ return cls.W(_vbMethod, cls.basicmodule, 'AllDialogs', dialog)
+ @classmethod
+ def AllForms(cls, form = acConstants.Missing):
+ return cls.W(_vbMethod, cls.basicmodule, 'AllForms', form)
+ @classmethod
+ def AllModules(cls, module = acConstants.Missing):
+ return cls.W(_vbMethod, cls.basicmodule, 'AllModules', module)
+ @classmethod
+ def CloseConnection(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'CloseConnection')
+ @classmethod
+ def CommandBars(cls, bar = acConstants.Missing):
+ return cls.W(_vbMethod, cls.basicmodule, 'CommandBars', bar)
+ @classmethod
+ def CurrentDb(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'CurrentDb')
+ @classmethod
+ def CurrentUser(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'CurrentUser')
+ @classmethod
+ def DAvg(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DAvg', expression, domain, criteria)
+ @classmethod
+ def DCount(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DCount', expression, domain, criteria)
+ @classmethod
+ def DLookup(cls, expression, domain, criteria = '', orderclause = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DLookup', expression, domain, criteria, orderclause)
+ @classmethod
+ def DMax(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DMax', expression, domain, criteria)
+ @classmethod
+ def DMin(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DMin', expression, domain, criteria)
+ @classmethod
+ def DStDev(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DStDev', expression, domain, criteria)
+ @classmethod
+ def DStDevP(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DStDevP', expression, domain, criteria)
+ @classmethod
+ def DSum(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DSum', expression, domain, criteria)
+ @classmethod
+ def DVar(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DVar', expression, domain, criteria)
+ @classmethod
+ def DVarP(cls, expression, domain, criteria = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'DVarP', expression, domain, criteria)
+ @classmethod
+ def Events(cls, event):
+ return cls.W(_vbMethod, cls.basicmodule, 'Events', event)
+ @classmethod
+ def Forms(cls, form = acConstants.Missing):
+ return cls.W(_vbMethod, cls.basicmodule, 'Forms', form)
+ @classmethod
+ def getObject(cls, shortcut):
+ return cls.W(_vbMethod, cls.basicmodule, 'getObject', shortcut)
+ GetObject = getObject
+ @classmethod
+ def getValue(cls, shortcut):
+ return cls.W(_vbMethod, cls.basicmodule, 'getValue', shortcut)
+ GetValue = getValue
+ @classmethod
+ def HtmlEncode(cls, string, length = 0):
+ return cls.W(_vbMethod, cls.basicmodule, 'HtmlEncode', string, length)
+ @classmethod
+ def OpenConnection(cls, thisdatabasedocument = acConstants.Missing):
+ global THISDATABASEDOCUMENT
+ if COMPONENTCONTEXT == None: A2BConnect() # Connection from inside LibreOffice is done at first API invocation
+ if DESKTOP != None:
+ THISDATABASEDOCUMENT = DESKTOP.getCurrentComponent()
+ return _A2B.invokeMethod('OpenConnection', 'Application', THISDATABASEDOCUMENT)
+ @classmethod
+ def OpenDatabase(cls, connectionstring, username = '', password = '', readonly = False):
+ return cls.W(_vbMethod, cls.basicmodule, 'OpenDatabase', connectionstring, username
+ , password, readonly)
+ @classmethod
+ def ProductCode(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'ProductCode')
+ @classmethod
+ def setValue(cls, shortcut, value):
+ return cls.W(_vbMethod, cls.basicmodule, 'setValue', shortcut, value)
+ SetValue = setValue
+ @classmethod
+ def SysCmd(cls, action, text = '', value = -1):
+ return cls.W(_vbMethod, cls.basicmodule, 'SysCmd', action, text, value)
+ @classmethod
+ def TempVars(cls, var = acConstants.Missing):
+ return cls.W(_vbMethod, cls.basicmodule, 'TempVars', var)
+ @classmethod
+ def Version(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'Version')
+
+
+class DoCmd(object, metaclass = _Singleton):
+ """ Collection of methods located in the DoCmd (Basic) module """
+ W = _A2B.invokeWrapper
+ basicmodule = -2
+
+ @classmethod
+ def ApplyFilter(cls, filter = '', sqlwhere = '', controlname = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'ApplyFilter', filter, sqlwhere, controlname)
+ @classmethod
+ def Close(cls, objecttype, objectname, save = acConstants.acSavePrompt):
+ return cls.W(_vbMethod, cls.basicmodule, 'Close', objecttype, objectname, save)
+ @classmethod
+ def CopyObject(cls, sourcedatabase, newname, sourceobjecttype, sourceobjectname): # 1st argument must be set
+ return cls.W(_vbMethod, cls.basicmodule, 'CopyObject', sourcedatabase, newname, sourceobjecttype
+ , sourceobjectname)
+ @classmethod
+ def FindNext(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'FindNext')
+ @classmethod
+ def FindRecord(cls, findwhat, match = acConstants.acEntire, matchcase = False, search = acConstants.acSearchAll
+ , searchasformatted = False, onlycurrentfield = acConstants.acCurrent, findfirst = True):
+ return cls.W(_vbMethod, cls.basicmodule, 'FindRecord', findwhat, match, matchcase, search
+ , searchasformatted, onlycurrentfield, findfirst)
+ @classmethod
+ def GetHiddenAttribute(cls, objecttype, objectname = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'GetHiddenAttribute', objecttype, objectname)
+ @classmethod
+ def GoToControl(cls, controlname):
+ return cls.W(_vbMethod, cls.basicmodule, 'GoToControl', controlname)
+ @classmethod
+ def GoToRecord(cls, objecttype = acConstants.acActiveDataObject, objectname = '', record = acConstants.acNext
+ , offset = 1):
+ return cls.W(_vbMethod, cls.basicmodule, 'GoToRecord', objecttype, objectname, record, offset)
+ @classmethod
+ def Maximize(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'Maximize')
+ @classmethod
+ def Minimize(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'Minimize')
+ @classmethod
+ def MoveSize(cls, left = -1, top = -1, width = -1, height = -1):
+ return cls.W(_vbMethod, cls.basicmodule, 'MoveSize', left, top, width, height)
+ @classmethod
+ def OpenForm(cls, formname, view = acConstants.acNormal, filter = '', wherecondition = ''
+ , datamode = acConstants.acFormEdit, windowmode = acConstants.acWindowNormal, openargs = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'OpenForm', formname, view, filter, wherecondition
+ , datamode, windowmode, openargs)
+ @classmethod
+ def OpenQuery(cls, queryname, view = acConstants.acNormal, datamode = acConstants.acEdit):
+ return cls.W(_vbMethod, cls.basicmodule, 'OpenQuery', queryname, view, datamode)
+ @classmethod
+ def OpenReport(cls, queryname, view = acConstants.acNormal):
+ return cls.W(_vbMethod, cls.basicmodule, 'OpenReport', queryname, view)
+ @classmethod
+ def OpenSQL(cls, sql, option = -1):
+ return cls.W(_vbMethod, cls.basicmodule, 'OpenSQL', sql, option)
+ @classmethod
+ def OpenTable(cls, tablename, view = acConstants.acNormal, datamode = acConstants.acEdit):
+ return cls.W(_vbMethod, cls.basicmodule, 'OpenTable', tablename, view, datamode)
+ @classmethod
+ def OutputTo(cls, objecttype, objectname = '', outputformat = '', outputfile = '', autostart = False, templatefile = ''
+ , encoding = acConstants.acUTF8Encoding, quality = acConstants.acExportQualityPrint):
+ if objecttype == acConstants.acOutputForm: encoding = 0
+ return cls.W(_vbMethod, cls.basicmodule, 'OutputTo', objecttype, objectname, outputformat
+ , outputfile, autostart, templatefile, encoding, quality)
+ @classmethod
+ def Quit(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'Quit')
+ @classmethod
+ def RunApp(cls, commandline):
+ return cls.W(_vbMethod, cls.basicmodule, 'RunApp', commandline)
+ @classmethod
+ def RunCommand(cls, command):
+ return cls.W(_vbMethod, cls.basicmodule, 'RunCommand', command)
+ @classmethod
+ def RunSQL(cls, SQL, option = -1):
+ return cls.W(_vbMethod, cls.basicmodule, 'RunSQL', SQL, option)
+ @classmethod
+ def SelectObject(cls, objecttype, objectname = '', indatabasewindow = False):
+ return cls.W(_vbMethod, cls.basicmodule, 'SelectObject', objecttype, objectname, indatabasewindow)
+ @classmethod
+ def SendObject(cls, objecttype = acConstants.acSendNoObject, objectname = '', outputformat = '', to = '', cc = ''
+ , bcc = '', subject = '', messagetext = '', editmessage = True, templatefile = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'SendObject', objecttype, objectname, outputformat, to, cc
+ , bcc, subject, messagetext, editmessage, templatefile)
+ @classmethod
+ def SetHiddenAttribute(cls, objecttype, objectname = '', hidden = True):
+ return cls.W(_vbMethod, cls.basicmodule, 'SetHiddenAttribute', objecttype, objectname, hidden)
+ @classmethod
+ def SetOrderBy(cls, orderby = '', controlname = ''):
+ return cls.W(_vbMethod, cls.basicmodule, 'SetOrderBy', orderby, controlname)
+ @classmethod
+ def ShowAllRecords(cls):
+ return cls.W(_vbMethod, cls.basicmodule, 'ShowAllRecords')
+
+
+class Basic(object, metaclass = _Singleton):
+ """ Collection of helper functions having the same behaviour as their Basic counterparts """
+ M = _A2B.invokeMethod
+
+ @classmethod
+ def ConvertFromUrl(cls, url):
+ return cls.M('PyConvertFromUrl', _WRAPPERMODULE, url)
+
+ @classmethod
+ def ConvertToUrl(cls, file):
+ return cls.M('PyConvertToUrl', _WRAPPERMODULE, file)
+
+ @classmethod
+ def CreateUnoService(cls, servicename):
+ return cls.M('PyCreateUnoService', _WRAPPERMODULE, servicename)
+
+ @classmethod
+ def DateAdd(cls, add, count, datearg):
+ if isinstance(datearg, datetime.datetime): datearg = datearg.isoformat()
+ dateadd = cls.M('PyDateAdd', _WRAPPERMODULE, add, count, datearg)
+ return datetime.datetime.strptime(dateadd, acConstants.FromIsoFormat)
+
+ @classmethod
+ def DateDiff(cls, add, date1, date2, weekstart = 1, yearstart = 1):
+ if isinstance(date1, datetime.datetime): date1 = date1.isoformat()
+ if isinstance(date2, datetime.datetime): date2 = date2.isoformat()
+ return cls.M('PyDateDiff', _WRAPPERMODULE, add, date1, date2, weekstart, yearstart)
+
+ @classmethod
+ def DatePart(cls, add, datearg, weekstart = 1, yearstart = 1):
+ if isinstance(datearg, datetime.datetime): datearg = datearg.isoformat()
+ return cls.M('PyDatePart', _WRAPPERMODULE, add, datearg, weekstart, yearstart)
+
+ @classmethod
+ def DateValue(cls, datestring):
+ datevalue = cls.M('PyDateValue', _WRAPPERMODULE, datestring)
+ return datetime.datetime.strptime(datevalue, acConstants.FromIsoFormat)
+
+ @classmethod
+ def Format(cls, value, format = None):
+ if isinstance(value, (datetime.datetime, datetime.date, datetime.time, )):
+ value = value.isoformat()
+ return cls.M('PyFormat', _WRAPPERMODULE, value, format)
+
+ @classmethod
+ def GetGUIType(cls):
+ return cls.M('PyGetGUIType', _WRAPPERMODULE)
+
+ @staticmethod
+ def GetPathSeparator():
+ return os.sep
+
+ @classmethod
+ def GetSystemTicks(cls):
+ return cls.M('PyGetSystemTicks', _WRAPPERMODULE)
+
+ @classmethod
+ def MsgBox(cls, text, type = None, dialogtitle = None):
+ return cls.M('PyMsgBox', _WRAPPERMODULE, text, type, dialogtitle)
+
+ class GlobalScope(object, metaclass = _Singleton):
+ @classmethod
+ def BasicLibraries(cls):
+ return Basic.M('PyGlobalScope', _WRAPPERMODULE, 'Basic')
+ @classmethod
+ def DialogLibraries(self):
+ return Basic.M('PyGlobalScope', _WRAPPERMODULE, 'Dialog')
+
+ @classmethod
+ def InputBox(cls, text, title = None, default = None, xpos = None, ypos = None):
+ return cls.M('PyInputBox', _WRAPPERMODULE, text, title, default, xpos, ypos)
+
+ @staticmethod
+ def Now():
+ return datetime.datetime.now()
+
+ @staticmethod
+ def RGB(red, green, blue):
+ return int('%02x%02x%02x' % (red, green, blue), 16)
+
+ @classmethod
+ def Timer(cls):
+ return cls.M('PyTimer', _WRAPPERMODULE)
+
+ @staticmethod
+ def Xray(myObject):
+ xrayscript = 'vnd.sun.star.script:XrayTool._Main.Xray?language=Basic&location=application'
+ xScript = SCRIPTPROVIDER.getScript(xrayscript)
+ xScript.invoke((myObject,), (), ())
+ return
+
+
+class _BasicObject(object):
+ """
+ Parent class of Basic objects
+ Each subclass is identified by its classProperties:
+ dictionary with keys = allowed properties, value = True if editable or False
+ Each instance is identified by its
+ - reference in the cache managed by Basic
+ - type ('DATABASE', 'COLLECTION', ...)
+ - name (form, control, ... name) - may be blank
+ Properties are got and set following next strategy:
+ 1. Property names are controlled strictly ('Value' and not 'value')
+ 2. Getting a property value for the first time is always done via a Basic call
+ 3. Next occurrences are fetched from the Python dictionary of the instance if the property is read-only, otherwise via a Basic call
+ 4. Methods output might force the deletion of a property from the dictionary ('MoveNext' changes 'BOF' and 'EOF' properties)
+ 5. Setting a property value is done via a Basic call, except if self.internal == True
+ """
+ W = _A2B.invokeWrapper
+ internal_attributes = ('objectreference', 'objecttype', 'name', 'internal')
+
+ def __init__(self, reference = -1, objtype = None, name = ''):
+ self.objectreference = reference # reference in the cache managed by Basic
+ self.objecttype = objtype # ('DATABASE', 'COLLECTION', ...)
+ self.name = name # '' when no name
+ self.internal = False # True to exceptionally allow assigning a new value to a read-only property
+ self.localProperties = ()
+
+ def __getattr__(self, name):
+ if name in ('classProperties', 'localProperties'):
+ pass
+ elif name in self.classProperties:
+ # Get Property from Basic
+ return self.W(_vbGet, self.objectreference, name)
+ # Usual attributes getter
+ return super(_BasicObject, self).__getattribute__(name)
+
+ def __setattr__(self, name, value):
+ if name in ('classProperties', 'localProperties'):
+ pass
+ elif name in self.classProperties:
+ if self.internal: # internal = True forces property setting even if property is read-only
+ pass
+ elif self.classProperties[name] == True: # True == Editable
+ self.W(_vbLet, self.objectreference, name, value)
+ else:
+ raise AttributeError("type object '" + self.objecttype + "' has no editable attribute '" + name + "'")
+ elif name[0:2] == '__' or name in self.internal_attributes or name in self.localProperties:
+ pass
+ else:
+ raise AttributeError("type object '" + self.objecttype + "' has no attribute '" + name + "'")
+ object.__setattr__(self, name, value)
+ return
+
+ def __repr__(self):
+ repr = "Basic object (type='" + self.objecttype + "', index=" + str(self.objectreference)
+ if len(self.name) > 0: repr += ", name='" + self.name + "'"
+ return repr + ")"
+
+ def _Reset(self, propertyname, basicreturn = None):
+ """ force new value or erase properties from dictionary (done to optimize calls to Basic scripts) """
+ if propertyname in ('BOF', 'EOF'):
+ # After a Move method invocation on a Recordset object, BOF or EOF likely to be got soon
+ if isinstance(basicreturn, int):
+ self.internal = True
+ # f.i. basicreturn = 0b10 means: BOF = True, EOF = False
+ self.BOF = basicreturn in (2, 3, -2, -3)
+ self.EOF = basicreturn in (1, 3, -1, -3)
+ self.internal = False
+ return ( basicreturn >= 0 )
+ else:
+ # Suppress possibly invalid property values: e.g. RecordCount after Delete applied on Recordset object
+ if property in self.__dict__:
+ del(self.propertyname)
+ return basicreturn
+
+ @property
+ def Name(self): return self.name
+ @property
+ def ObjectType(self): return self.objecttype
+
+ def Dispose(self):
+ return self.W(_vbMethod, self.objectreference, 'Dispose')
+ def getProperty(self, propertyname, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'getProperty', propertyname, index)
+ GetProperty = getProperty
+ def hasProperty(self, propertyname):
+ return propertyname in tuple(self.classProperties.keys())
+ HasProperty = hasProperty
+ def Properties(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Properties', index)
+ def setProperty(self, propertyname, value, index = acConstants.Missing):
+ if self.hasProperty(propertyname):
+ if self.W(_vbMethod, self.objectreference, 'setProperty', propertyname, value, index):
+ return self.__setattr__(propertyname, value)
+ raise AttributeError("type object '" + self.objecttype + "' has no editable attribute '" + propertyname + "'")
+ SetProperty = setProperty
+
+
+class _Collection(_BasicObject):
+ """ Collection object built as a Python iterator """
+ classProperties = dict(Count = False)
+ def __init__(self, reference = -1, objtype = None):
+ super().__init__(reference, objtype)
+ self.localProperties = ('count', 'index')
+ self.count = self.Count
+ self.index = 0
+ def __iter__(self):
+ self.index = 0
+ return self
+ def __next__(self):
+ if self.index >= self.count:
+ raise StopIteration
+ next = self.Item(self.index)
+ self.index = self.index + 1
+ return next
+ def __len__(self):
+ return self.count
+
+ def Add(self, table, value = acConstants.Missing):
+ if isinstance(table, _BasicObject): # Add method applied to a TABLEDEFS collection
+ return self.W(_vbMethod, self.objectreference, 'Add', table.objectreference)
+ else: # Add method applied to a TEMPVARS collection
+ add = self.W(_vbMethod, self.objectreference, 'Add', table, value)
+ self.count = self.Count
+ return add
+ def Delete(self, name):
+ return self.W(_vbMethod, self.objectreference, 'Delete', name)
+ def Item(self, index):
+ return self.W(_vbMethod, self.objectreference, 'Item', index)
+ def Remove(self, tempvarname):
+ remove = self.W(_vbMethod, self.objectreference, 'Remove', tempvarname)
+ self.count = self.Count
+ return remove
+ def RemoveAll(self):
+ remove = self.W(_vbMethod, self.objectreference, 'RemoveAll')
+ self.count = self.Count
+ return remove
+
+
+class _CommandBar(_BasicObject):
+ classProperties = dict(BuiltIn = False, Parent = False, Visible = True)
+
+ def CommandBarControls(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'CommandBarControls', index)
+ def Reset(self):
+ return self.W(_vbMethod, self.objectreference, 'Reset')
+
+
+class _CommandBarControl(_BasicObject):
+ classProperties = dict(BeginGroup = False, BuiltIn = False, Caption = True, Index = False, OnAction = True
+ , Parent = False, TooltipText = True, Type = False, Visible = True)
+
+ def Execute(self):
+ return self.W(_vbMethod, self.objectreference, 'Execute')
+
+
+class _Control(_BasicObject):
+ classProperties = dict(BackColor = True, BorderColor = True, BorderStyle = True, Cancel = True, Caption = True
+ , ControlSource = False, ControlTipText = True, ControlType = False, Default = True
+ , DefaultValue = True, Enabled = True, FontBold = True, FontItalic = True, FontName = True
+ , FontSize = True, FontUnderline = True, FontWeight = True, ForeColor = True, Form = False
+ , Format = True, ItemData = False, ListCount = False, ListIndex = True, Locked = True, MultiSelect = True
+ , OnActionPerformed = True, OnAdjustmentValueChanged = True, OnApproveAction = True
+ , OnApproveReset = True, OnApproveUpdate = True, OnChanged = True, OnErrorOccurred = True
+ , OnFocusGained = True, OnFocusLost = True, OnItemStateChanged = True, OnKeyPressed = True
+ , OnKeyReleased = True, OnMouseDragged = True, OnMouseEntered = True, OnMouseExited = True
+ , OnMouseMoved = True, OnMousePressed = True, OnMouseReleased = True, OnResetted = True, OnTextChanged = True
+ , OnUpdated = True, OptionValue = False, Page = False, Parent = False, Picture = True, Required = True
+ , RowSource = True, RowSourceType = True, Selected = True, SelLength = True, SelStart = True, SelText = True
+ , SubType = False, TabIndex = True, TabStop = True, Tag = True, Text = False, TextAlign = True
+ , TripleState = True, Value = True, Visible = True
+ )
+
+ @property
+ def BoundField(self): return self.W(_vbUNO, self.objectreference, 'BoundField')
+ @property
+ def ControlModel(self): return self.W(_vbUNO, self.objectreference, 'ControlModel')
+ @property
+ def ControlView(self): return self.W(_vbUNO, self.objectreference, 'ControlView')
+ @property
+ def LabelControl(self): return self.W(_vbUNO, self.objectreference, 'LabelControl')
+
+ def AddItem(self, value, index = -1):
+ basicreturn = self.W(_vbMethod, self.objectreference, 'AddItem', value, index)
+ self._Reset('ItemData')
+ self._Reset('ListCount')
+ return basicreturn
+ def Controls(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Controls', index)
+ # Overrides method in parent class: list of properties is strongly control type dependent
+ def hasProperty(self, propertyname):
+ return self.W(_vbMethod, self.objectreference, 'hasProperty', propertyname)
+ HasProperty = hasProperty
+ def RemoveItem(self, index):
+ basicreturn = self.W(_vbMethod, self.objectreference, 'RemoveItem', index)
+ self._Reset('ItemData')
+ self._Reset('ListCount')
+ return basicreturn
+ def Requery(self):
+ return self.W(_vbMethod, self.objectreference, 'Requery')
+ def SetSelected(self, value, index):
+ return self.W(_vbMethod, self.objectreference, 'SetSelected', value, index)
+ def SetFocus(self):
+ return self.W(_vbMethod, self.objectreference, 'SetFocus')
+
+
+class _Database(_BasicObject):
+ classProperties = dict(Connect = False, OnCreate = True
+ , OnFocus = True, OnLoad = True, OnLoadFinished = True, OnModifyChanged = True, OnNew = True
+ , OnPrepareUnload = True, OnPrepareViewClosing = True, OnSave = True, OnSaveAs = True
+ , OnSaveAsDone = True, OnSaveAsFailed = True, OnSaveDone = True, OnSaveFailed = True
+ , OnSubComponentClosed = True, OnSubComponentOpened = True, OnTitleChanged = True, OnUnfocus = True
+ , OnUnload = True, OnViewClosed = True, OnViewCreated = True, Version = False
+ )
+
+ @property
+ def Connection(self): return self.W(_vbUNO, self.objectreference, 'Connection')
+ @property
+ def Document(self): return self.W(_vbUNO, self.objectreference, 'Document')
+ @property
+ def MetaData(self): return self.W(_vbUNO, self.objectreference, 'MetaData')
+
+ def Close(self):
+ return self.W(_vbMethod, self.objectreference, 'Close')
+ def CloseAllRecordsets(self):
+ return self.W(_vbMethod, self.objectreference, 'CloseAllRecordsets')
+ def CreateQueryDef(self, name, sqltext, option = -1):
+ return self.W(_vbMethod, self.objectreference, 'CreateQueryDef', name, sqltext, option)
+ def CreateTableDef(self, name):
+ return self.W(_vbMethod, self.objectreference, 'CreateTableDef', name)
+ def DAvg(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DAvg', expression, domain, criteria)
+ def DCount(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DCount', expression, domain, criteria)
+ def DLookup(self, expression, domain, criteria = '', orderclause = ''):
+ return self.W(_vbMethod, self.objectreference, 'DLookup', expression, domain, criteria, orderclause)
+ def DMax(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DMax', expression, domain, criteria)
+ def DMin(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DMin', expression, domain, criteria)
+ def DStDev(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DStDev', expression, domain, criteria)
+ def DStDevP(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DStDevP', expression, domain, criteria)
+ def DVar(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DVar', expression, domain, criteria)
+ def DVarP(self, expression, domain, criteria = ''):
+ return self.W(_vbMethod, self.objectreference, 'DVarP', expression, domain, criteria)
+ def OpenRecordset(self, source, type = -1, option = -1, lockedit = -1):
+ return self.W(_vbMethod, self.objectreference, 'OpenRecordset', source, type, option, lockedit)
+ def OpenSQL(self, SQL, option = -1):
+ return self.W(_vbMethod, self.objectreference, 'OpenSQL', SQL, option)
+ def OutputTo(self, objecttype, objectname = '', outputformat = '', outputfile = '', autostart = False, templatefile = ''
+ , encoding = acConstants.acUTF8Encoding, quality = acConstants.acExportQualityPrint):
+ if objecttype == acConstants.acOutputForm: encoding = 0
+ return self.W(_vbMethod, self.objectreference, 'OutputTo', objecttype, objectname, outputformat, outputfile
+ , autostart, templatefile, encoding, quality)
+ def QueryDefs(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'QueryDefs', index)
+ def Recordsets(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Recordsets', index)
+ def RunSQL(self, SQL, option = -1):
+ return self.W(_vbMethod, self.objectreference, 'RunSQL', SQL, option)
+ def TableDefs(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'TableDefs', index)
+
+
+class _Dialog(_BasicObject):
+ classProperties = dict(Caption = True, Height = True, IsLoaded = False, OnFocusGained = True
+ , OnFocusLost = True, OnKeyPressed = True, OnKeyReleased = True, OnMouseDragged = True
+ , OnMouseEntered = True, OnMouseExited = True, OnMouseMoved = True, OnMousePressed = True
+ , OnMouseReleased = True, Page = True, Parent = False, Visible = True, Width = True
+ )
+
+ @property
+ def UnoDialog(self): return self.W(_vbUNO, self.objectreference, 'UnoDialog')
+
+ def EndExecute(self, returnvalue):
+ return self.W(_vbMethod, self.objectreference, 'EndExecute', returnvalue)
+ def Execute(self):
+ return self.W(_vbMethod, self.objectreference, 'Execute')
+ def Move(self, left = -1, top = -1, width = -1, height = -1):
+ return self.W(_vbMethod, self.objectreference, 'Move', left, top, width, height)
+ def OptionGroup(self, groupname):
+ return self.W(_vbMethod, self.objectreference, 'OptionGroup', groupname)
+ def Start(self):
+ return self.W(_vbMethod, self.objectreference, 'Start')
+ def Terminate(self):
+ return self.W(_vbMethod, self.objectreference, 'Terminate')
+
+class _Event(_BasicObject):
+ classProperties = dict(ButtonLeft = False, ButtonMiddle = False, ButtonRight = False, ClickCount = False
+ , ContextShortcut = False, EventName = False, EventType = False, FocusChangeTemporary = False
+ , KeyAlt = False, KeyChar = False, KeyCode = False, KeyCtrl = False, KeyFunction = False, KeyShift = False
+ , Recommendation = False, RowChangeAction = False, Source = False, SubComponentName = False
+ , SubComponentType = False, XPos = False, YPos = False
+ )
+
+
+class _Field(_BasicObject):
+ classProperties = dict(DataType = False, DataUpdatable = False, DbType = False, DefaultValue = True
+ , Description = True, FieldSize = False, Size = False, Source = False
+ , SourceField = False, SourceTable = False, TypeName = False, Value = True
+ )
+
+ @property
+ def Column(self): return self.W(_vbUNO, self.objectreference, 'Column')
+
+ def AppendChunk(self, value):
+ return self.W(_vbMethod, self.objectreference, 'AppendChunk', value)
+ def GetChunk(self, offset, numbytes):
+ return self.W(_vbMethod, self.objectreference, 'GetChunk', offset, numbytes)
+ def ReadAllBytes(self, file):
+ return self.W(_vbMethod, self.objectreference, 'ReadAllBytes', file)
+ def ReadAllText(self, file):
+ return self.W(_vbMethod, self.objectreference, 'ReadAllText', file)
+ def WriteAllBytes(self, file):
+ return self.W(_vbMethod, self.objectreference, 'WriteAllBytes', file)
+ def WriteAllText(self, file):
+ return self.W(_vbMethod, self.objectreference, 'WriteAllText', file)
+
+
+class _Form(_BasicObject):
+ classProperties = dict(AllowAdditions = True, AllowDeletions = True, AllowEdits = True, Bookmark = True
+ , Caption = True, CurrentRecord = True, Filter = True, FilterOn = True, Height = True
+ , IsLoaded = False, OnApproveCursorMove = True, OnApproveParameter = True, OnApproveReset = True
+ , OnApproveRowChange = True, OnApproveSubmit = True, OnConfirmDelete = True, OnCursorMoved = True
+ , OnErrorOccurred = True, OnLoaded = True, OnReloaded = True, OnReloading = True, OnResetted = True
+ , OnRowChanged = True, OnUnloaded = True, OnUnloading = True, OpenArgs = False, OrderBy = True
+ , OrderByOn = True, Parent = False, Recordset = False, RecordSource = True, Visible = True
+ , Width = True
+ )
+
+ @property
+ def Component(self): return self.W(_vbUNO, self.objectreference, 'Component')
+ @property
+ def ContainerWindow(self): return self.W(_vbUNO, self.objectreference, 'ContainerWindow')
+ @property
+ def DatabaseForm(self): return self.W(_vbUNO, self.objectreference, 'DatabaseForm')
+
+ def Close(self):
+ return self.W(_vbMethod, self.objectreference, 'Close')
+ def Controls(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Controls', index)
+ def Move(self, left = -1, top = -1, width = -1, height = -1):
+ return self.W(_vbMethod, self.objectreference, 'Move', left, top, width, height)
+ def OptionGroup(self, groupname):
+ return self.W(_vbMethod, self.objectreference, 'OptionGroup', groupname)
+ def Refresh(self):
+ return self.W(_vbMethod, self.objectreference, 'Refresh')
+ def Requery(self):
+ return self.W(_vbMethod, self.objectreference, 'Requery')
+ def SetFocus(self):
+ return self.W(_vbMethod, self.objectreference, 'SetFocus')
+
+
+class _Module(_BasicObject):
+ classProperties = dict(CountOfDeclarationLines = False, CountOfLines = False, Type = False)
+
+ def __init__(self, reference = -1, objtype = None, name = ''):
+ super().__init__(reference, objtype, name)
+ self.localProperties = ('startline', 'startcolumn', 'endline', 'endcolumn', 'prockind')
+
+ def Find(self, target, startline, startcolumn, endline, endcolumn, wholeword = False
+ , matchcase = False, patternsearch = False):
+ Returned = self.W(_vbMethod, self.objectreference, 'Find', target, startline, startcolumn, endline
+ , endcolumn, wholeword, matchcase, patternsearch)
+ if isinstance(Returned, tuple):
+ if Returned[0] == True and len(Returned) == 5:
+ self.startline = Returned[1]
+ self.startcolumn = Returned[2]
+ self.endline = Returned[3]
+ self.endcolumn = Returned[4]
+ return Returned[0]
+ return Returned
+ def Lines(self, line, numlines):
+ return self.W(_vbMethod, self.objectreference, 'Lines', line, numlines)
+ def ProcBodyLine(self, procname, prockind):
+ return self.W(_vbMethod, self.objectreference, 'ProcBodyLine', procname, prockind)
+ def ProcCountLines(self, procname, prockind):
+ return self.W(_vbMethod, self.objectreference, 'ProcCountLines', procname, prockind)
+ def ProcOfLine(self, line, prockind):
+ Returned = self.W(_vbMethod, self.objectreference, 'ProcOfLine', line, prockind)
+ if isinstance(Returned, tuple):
+ if len(Returned) == 2:
+ self.prockind = Returned[1]
+ return Returned[0]
+ return Returned
+ def ProcStartLine(self, procname, prockind):
+ return self.W(_vbMethod, self.objectreference, 'ProcStartLine', procname, prockind)
+
+
+class _OptionGroup(_BasicObject):
+ classProperties = dict(Count = False, Value = True)
+
+ def Controls(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Controls', index)
+
+
+class _Property(_BasicObject):
+ classProperties = dict(Value = True)
+
+
+class _QueryDef(_BasicObject):
+ classProperties = dict(SQL = True, Type = False)
+
+ @property
+ def Query(self): return self.W(_vbUNO, self.objectreference, 'Query')
+
+ def Execute(self, options = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Execute', options)
+ def Fields(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Fields', index)
+ def OpenRecordset(self, type = -1, option = -1, lockedit = -1):
+ return self.W(_vbMethod, self.objectreference, 'OpenRecordset', type, option, lockedit)
+
+
+class _Recordset(_BasicObject):
+ classProperties = dict(AbsolutePosition = True, BOF = False, Bookmark = True, Bookmarkable = False
+ , EditMode = False, EOF = False, Filter = True, RecordCount = False
+ )
+
+ @property
+ def RowSet(self): return self.W(_vbUNO, self.objectreference, 'RowSet')
+
+ def AddNew(self):
+ return self.W(_vbMethod, self.objectreference, 'AddNew')
+ def CancelUpdate(self):
+ return self.W(_vbMethod, self.objectreference, 'CancelUpdate')
+ def Clone(self):
+ return self.W(_vbMethod, self.objectreference, 'Clone')
+ def Close(self):
+ return self.W(_vbMethod, self.objectreference, 'Close')
+ def Delete(self):
+ return self._Reset('RecordCount',self.W(_vbMethod, self.objectreference, 'Delete'))
+ def Edit(self):
+ return self.W(_vbMethod, self.objectreference, 'Edit')
+ def Fields(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Fields', index)
+ def GetRows(self, numrows):
+ return self.W(_vbMethod, self.objectreference, 'GetRows', numrows)
+ def Move(self, rows, startbookmark = acConstants.Missing):
+ return self._Reset('BOF', self.W(_vbMethod, self.objectreference, 'Move', rows, startbookmark))
+ def MoveFirst(self):
+ return self._Reset('BOF', self.W(_vbMethod, self.objectreference, 'MoveFirst'))
+ def MoveLast(self):
+ return self._Reset('BOF', self.W(_vbMethod, self.objectreference, 'MoveLast'))
+ def MoveNext(self):
+ return self._Reset('BOF', self.W(_vbMethod, self.objectreference, 'MoveNext'))
+ def MovePrevious(self):
+ return self._Reset('BOF', self.W(_vbMethod, self.objectreference, 'MovePrevious'))
+ def OpenRecordset(self, type = -1, option = -1, lockedit = -1):
+ return self.W(_vbMethod, self.objectreference, 'OpenRecordset', type, option, lockedit)
+ def Update(self):
+ return self._Reset('RecordCount',self.W(_vbMethod, self.objectreference, 'Update'))
+
+
+class _SubForm(_Form):
+ classProperties = dict(AllowAdditions = True, AllowDeletions = True, AllowEdits = True, CurrentRecord = True
+ , Filter = True, FilterOn = True, LinkChildFields = False, LinkMasterFields = False
+ , OnApproveCursorMove = True, OnApproveParameter = True, OnApproveReset = True
+ , OnApproveRowChange = True, OnApproveSubmit = True, OnConfirmDelete = True, OnCursorMoved = True
+ , OnErrorOccurred = True, OnLoaded = True, OnReloaded = True, OnReloading = True, OnResetted = True
+ , OnRowChanged = True, OnUnloaded = True, OnUnloading = True, OrderBy = True
+ , OrderByOn = True, Parent = False, Recordset = False, RecordSource = True, Visible = True
+ )
+
+ def SetFocus(self):
+ raise AttributeError("type object 'SubForm' has no method 'SetFocus'")
+
+
+class _TableDef(_BasicObject):
+ classProperties = dict()
+
+ @property
+ def Table(self): return self.W(_vbUNO, self.objectreference, 'Table')
+
+ def CreateField(self, name, type, size = 0, attributes = 0):
+ return self.W(_vbMethod, self.objectreference, 'CreateField', name, type, size, attributes)
+ def Fields(self, index = acConstants.Missing):
+ return self.W(_vbMethod, self.objectreference, 'Fields', index)
+ def OpenRecordset(self, type = -1, option = -1, lockedit = -1):
+ return self.W(_vbMethod, self.objectreference, 'OpenRecordset', type, option, lockedit)
+
+
+class _TempVar(_BasicObject):
+ classProperties = dict(Value = True)
+
+"""
+Set of directly callable error handling methods
+"""
+def DebugPrint(*args):
+ dargs = ()
+ for arg in args:
+ if isinstance(arg, _BasicObject):
+ arg = ('[' + arg.objecttype + '] ' + arg.name).rstrip()
+ dargs = dargs + (arg,)
+ return _A2B.invokeMethod('DebugPrint', _WRAPPERMODULE, *dargs)
+def TraceConsole(): return _A2B.invokeMethod('TraceConsole', 'Trace')
+def TraceError(tracelevel, errorcode, errorprocedure, errorline):
+ return _A2B.invokeMethod('TraceError', 'Trace', tracelevel, errorcode, errorprocedure, errorline)
+def TraceLevel(newtracelevel = 'ERROR'): return _A2B.invokeMethod('TraceLevel', 'Trace', newtracelevel)
+def TraceLog(tracelevel, text, messagebox = True):
+ return _A2B.invokeMethod('TraceLog', 'Trace', tracelevel, text, messagebox)
+
diff --git a/wizards/source/access2base/dialog.xlb b/wizards/source/access2base/dialog.xlb
new file mode 100644
index 000000000..dc06162b7
--- /dev/null
+++ b/wizards/source/access2base/dialog.xlb
@@ -0,0 +1,6 @@
+<?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="Access2Base" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="dlgTrace"/>
+ <library:element library:name="dlgFormat"/>
+</library:library>
diff --git a/wizards/source/access2base/dlgFormat.xdl b/wizards/source/access2base/dlgFormat.xdl
new file mode 100644
index 000000000..4b93fd720
--- /dev/null
+++ b/wizards/source/access2base/dlgFormat.xdl
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="dlgFormat" dlg:left="246" dlg:top="119" dlg:width="153" dlg:height="40" dlg:help-text="Export the form" dlg:closeable="true" dlg:moveable="true" dlg:title="OutputTo">
+ <dlg:bulletinboard>
+ <dlg:combobox dlg:id="cboFormat" dlg:tab-index="0" dlg:left="4" dlg:top="18" dlg:width="71" dlg:height="8" dlg:help-text="Format in which the form should be exported" dlg:value="PDF" dlg:spin="true">
+ <dlg:menupopup>
+ <dlg:menuitem dlg:value="PDF"/>
+ <dlg:menuitem dlg:value="ODT"/>
+ <dlg:menuitem dlg:value="DOC"/>
+ <dlg:menuitem dlg:value="HTML"/>
+ </dlg:menupopup>
+ </dlg:combobox>
+ <dlg:text dlg:id="lblFormat" dlg:tab-index="1" dlg:left="4" dlg:top="7" dlg:width="100" dlg:height="9" dlg:help-text="Format in which the form should be exported" dlg:value="Select the output format"/>
+ <dlg:button dlg:id="cmdOK" dlg:tab-index="2" dlg:left="111" dlg:top="5" dlg:width="35" dlg:height="12" dlg:help-text="Validate your choice" dlg:default="true" dlg:value="OK" dlg:button-type="ok">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Access2Base.Trace._TraceOK?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="3" dlg:left="111" dlg:top="20" dlg:width="35" dlg:height="12" dlg:help-text="Cancel and close the dialog" dlg:value="Cancel" dlg:button-type="cancel"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/access2base/dlgTrace.xdl b/wizards/source/access2base/dlgTrace.xdl
new file mode 100644
index 000000000..08324e47c
--- /dev/null
+++ b/wizards/source/access2base/dlgTrace.xdl
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="dlgTrace" dlg:left="81" dlg:top="63" dlg:width="438" dlg:height="154" dlg:help-text="Manage the console file and its entries" dlg:closeable="true" dlg:moveable="true" dlg:title="Console">
+ <dlg:styles>
+ <dlg:style dlg:style-id="0" dlg:font-name="Courier New" dlg:font-stylename="Regular" dlg:font-family="modern"/>
+ <dlg:style dlg:style-id="1" dlg:look="simple"/>
+ <dlg:style dlg:style-id="2" dlg:background-color="0xe6e6e6" dlg:border="none"/>
+ </dlg:styles>
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblEntries" dlg:tab-index="3" dlg:left="265" dlg:top="134" dlg:width="130" dlg:height="9" dlg:help-text="Clear the list and resize the circular buffer" dlg:value="Set max number of entries" dlg:align="right"/>
+ <dlg:numericfield dlg:id="numEntries" dlg:tab-index="4" dlg:left="399" dlg:top="129" dlg:width="28" dlg:height="16" dlg:help-text="Clear the list and resize the circular buffer" dlg:decimal-accuracy="0" dlg:value="20" dlg:value-min="5" dlg:value-max="999" dlg:spin="true"/>
+ <dlg:textfield dlg:style-id="0" dlg:id="txtTraceLog" dlg:tab-index="0" dlg:left="9" dlg:top="20" dlg:width="360" dlg:height="105" dlg:help-text="Text can be selected, copied, ..." dlg:hscroll="true" dlg:vscroll="true" dlg:multiline="true" dlg:readonly="true" dlg:value="--- Log file is empty ---"/>
+ <dlg:checkbox dlg:style-id="1" dlg:id="chkClear" dlg:tab-index="5" dlg:left="58" dlg:top="133" dlg:width="6" dlg:height="9" dlg:help-text="Clear the list" dlg:value="Clear" dlg:checked="false"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="6" dlg:left="381" dlg:top="38" dlg:width="40" dlg:height="12" dlg:help-text="Cancel and close the dialog" dlg:value="Cancel" dlg:button-type="cancel"/>
+ <dlg:text dlg:id="lblClear" dlg:tab-index="7" dlg:left="9" dlg:top="133" dlg:width="46" dlg:height="9" dlg:help-text="Clear the list" dlg:value="Clear the list" dlg:align="right"/>
+ <dlg:text dlg:id="lblMinLevel" dlg:tab-index="8" dlg:left="74" dlg:top="133" dlg:width="130" dlg:height="9" dlg:help-text="Register only logging requests above given level" dlg:value="Set minimal trace level" dlg:align="right"/>
+ <dlg:combobox dlg:id="cboMinLevel" dlg:tab-index="9" dlg:left="209" dlg:top="133" dlg:width="50" dlg:height="9" dlg:help-text="Register only logging requests above given level" dlg:spin="true">
+ <dlg:menupopup>
+ <dlg:menuitem dlg:value="DEBUG"/>
+ <dlg:menuitem dlg:value="INFO"/>
+ <dlg:menuitem dlg:value="WARNING"/>
+ <dlg:menuitem dlg:value="ERROR"/>
+ <dlg:menuitem dlg:value="ABORT"/>
+ </dlg:menupopup>
+ </dlg:combobox>
+ <dlg:button dlg:id="cmdOK" dlg:tab-index="1" dlg:left="381" dlg:top="20" dlg:width="40" dlg:height="12" dlg:help-text="Validate" dlg:default="true" dlg:value="OK" dlg:button-type="ok"/>
+ <dlg:button dlg:id="cmdDump" dlg:tab-index="2" dlg:left="381" dlg:top="68" dlg:width="40" dlg:height="31" dlg:help-text="Choose a file and dump the actual list content in it" dlg:value="Dump to file" dlg:multiline="true">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Access2Base.Trace._DumpToFile?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="lblNbEntries" dlg:tab-index="10" dlg:left="9" dlg:top="10" dlg:width="105" dlg:height="7" dlg:help-text="Actual size of list" dlg:value="Actual number of entries:"/>
+ <dlg:numericfield dlg:style-id="2" dlg:id="numNbEntries" dlg:tab-index="11" dlg:left="123" dlg:top="9" dlg:width="17" dlg:height="9" dlg:help-text="Actual size of list" dlg:readonly="true" dlg:decimal-accuracy="0" dlg:value="0"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/access2base/script.xlb b/wizards/source/access2base/script.xlb
new file mode 100644
index 000000000..478a061e8
--- /dev/null
+++ b/wizards/source/access2base/script.xlb
@@ -0,0 +1,34 @@
+<?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="Access2Base" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="Application"/>
+ <library:element library:name="Methods"/>
+ <library:element library:name="acConstants"/>
+ <library:element library:name="Test"/>
+ <library:element library:name="Trace"/>
+ <library:element library:name="DoCmd"/>
+ <library:element library:name="Utils"/>
+ <library:element library:name="Database"/>
+ <library:element library:name="PropertiesSet"/>
+ <library:element library:name="Collect"/>
+ <library:element library:name="PropertiesGet"/>
+ <library:element library:name="Form"/>
+ <library:element library:name="Python"/>
+ <library:element library:name="_License"/>
+ <library:element library:name="SubForm"/>
+ <library:element library:name="L10N"/>
+ <library:element library:name="OptionGroup"/>
+ <library:element library:name="Event"/>
+ <library:element library:name="Property"/>
+ <library:element library:name="Control"/>
+ <library:element library:name="Dialog"/>
+ <library:element library:name="Field"/>
+ <library:element library:name="DataDef"/>
+ <library:element library:name="Recordset"/>
+ <library:element library:name="TempVar"/>
+ <library:element library:name="Root_"/>
+ <library:element library:name="UtilProperty"/>
+ <library:element library:name="CommandBar"/>
+ <library:element library:name="CommandBarControl"/>
+ <library:element library:name="Module"/>
+</library:library>
diff --git a/wizards/source/config/dialog.xlc b/wizards/source/config/dialog.xlc
new file mode 100644
index 000000000..34064e83e
--- /dev/null
+++ b/wizards/source/config/dialog.xlc
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:libraries PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "libraries.dtd">
+<library:libraries xmlns:library="http://openoffice.org/2000/library" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <library:library library:name="Standard" library:link="false"/>
+</library:libraries>
diff --git a/wizards/source/config/script.xlc b/wizards/source/config/script.xlc
new file mode 100644
index 000000000..34064e83e
--- /dev/null
+++ b/wizards/source/config/script.xlc
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:libraries PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "libraries.dtd">
+<library:libraries xmlns:library="http://openoffice.org/2000/library" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <library:library library:name="Standard" library:link="false"/>
+</library:libraries>
diff --git a/wizards/source/configshare/dialog.xlc b/wizards/source/configshare/dialog.xlc
new file mode 100644
index 000000000..2849d7a9b
--- /dev/null
+++ b/wizards/source/configshare/dialog.xlc
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:libraries PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "libraries.dtd">
+<library:libraries xmlns:library="http://openoffice.org/2000/library" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <library:library library:name="FormWizard" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/FormWizard/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Template" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Template/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Tools" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Tools/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Gimmicks" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Gimmicks/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="ImportWizard" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/ImportWizard/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Euro" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Euro/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Depot" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Depot/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="ScriptBindingLibrary" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/ScriptBindingLibrary/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Access2Base" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Access2Base/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="ScriptForge" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/ScriptForge/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFDatabases" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDatabases/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFDialogs" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDialogs/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFDocuments" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDocuments/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFUnitTests" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFUnitTests/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFWidgets" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFWidgets/dialog.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ </library:libraries>
diff --git a/wizards/source/configshare/script.xlc b/wizards/source/configshare/script.xlc
new file mode 100644
index 000000000..ff05ff37b
--- /dev/null
+++ b/wizards/source/configshare/script.xlc
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:libraries PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "libraries.dtd">
+<library:libraries xmlns:library="http://openoffice.org/2000/library" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <library:library library:name="FormWizard" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/FormWizard/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Template" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Template/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Tools" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Tools/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Gimmicks" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Gimmicks/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="ImportWizard" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/ImportWizard/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Euro" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Euro/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Depot" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Depot/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="ScriptBindingLibrary" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/ScriptBindingLibrary/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="Access2Base" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/Access2Base/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="ScriptForge" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/ScriptForge/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFDatabases" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDatabases/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFDialogs" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDialogs/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFDocuments" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFDocuments/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFUnitTests" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFUnitTests/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+ <library:library library:name="SFWidgets" xlink:href="$(INST)/@LIBO_SHARE_FOLDER@/basic/SFWidgets/script.xlb/" xlink:type="simple" library:link="true" library:readonly="false"/>
+</library:libraries>
diff --git a/wizards/source/depot/CommonLang.xba b/wizards/source/depot/CommonLang.xba
new file mode 100644
index 000000000..ec2f62733
--- /dev/null
+++ b/wizards/source/depot/CommonLang.xba
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="CommonLang" script:language="StarBasic">REM ***** BASIC *****
+
+
+&apos; Column A has the index 1
+Public Const SBCOLUMNNAME1 = 3 &apos; Stock names, sheet 1
+Public Const SBCOLUMNID1 = 4 &apos; Stock ID, sheet 1
+Public Const SBCOLUMNQUANTITY1 = 5 &apos; Stock quantity sheet 1
+Public Const SBCOLUMNRATE1 = 7 &apos; Price for stocks, sheet 1
+Public Const SBCOLUMNNAME2 = 3 &apos; Stock names, sheet 2
+Public Const SBCOLUMNDATE2 = 4 &apos; Transaction dates, sheet 2
+Public Const SBCOLUMNQUANTITY2 = 5 &apos; Transaction quantity, sheet 2
+Public Const SBCOLUMNRATE2 = 6 &apos; Price for stocks, sheet 2
+Public Const SBCOLUMNPROVPERCENT2 = 7 &apos; Provision in %, sheet 2
+Public Const SBCOLUMNPROVMIN2 = 8 &apos; Minimum provision, sheet 2
+Public Const SBCOLUMNPROVFIX2 = 9 &apos; Fixed provision, sheet 2
+Public Const SBCOLUMNPROCEEDS2 = 12 &apos; Profit, sheet 2
+Public Const SBCOLUMNQTYSOLD2 = 14 &apos; Quantity sold, sheet 2
+Public Const SBCOLUMNQTYREST2 = 15 &apos; Quantity not sold yet, sheet 2
+Public Const SBCOLUMNPRCREST2 = 16 &apos; Proportional price for quantity not sold yet, sheet 2
+Public Const SBCOLUMNREALPROC2 = 17 &apos; Realized proceeds, sheet 2
+Public Const SBCOLUMNDIVIDEND2 = 18 &apos; Dividend paid, sheet 2
+Public Const SBCOLUMNREALPROFIT2 = 19 &apos; Realized profit, sheet 2
+Public Const SBROWFIRSTTRANSACT2 = 8 &apos; First data row, sheet 2
+Public Const SBROWHEADER1 = 6 &apos; Headline, sheet 1
+Public Const SBMSGOK = 0
+Public Const SBMSGYESNO = 4
+Public Const SBMSGSTOP = 16
+Public Const SBMSGQUESTION = 32
+Public Const SBMSGDEFAULTBTN2 = 256
+Public Const SBHASID = 1 &apos; 0 = no ID, 1 = stocks have an ID
+Public Const SBDIALOGSELL = 1 &apos; Step for main dialog
+Public Const SBDIALOGBUY = 2 &apos; Step for main dialog
+Public Const SBBINARY = 0
+Public TransactMode as Integer
+Public Const LIFO = -1
+Public Const FIFO = 1
+
+Public Const HANDLEDIVIDEND = 1
+Public Const HANDLESPLIT = 2
+
+Global oDocument as Object
+Global oDocFormats() as Object
+Global oController as Object
+Global oFirstSheet as Object
+Global oBankSheet as Object
+Global oMovementSheet as Object
+Global sDocLanguage as String
+Global sDocCountry as String
+Global oSheets as Object
+Global oDocLocale as New com.sun.star.lang.Locale
+Global bEnableMarket as Boolean
+Global bEnableInternet as Boolean
+Global oMarketModel as Object
+Global oInternetModel as Object
+
+Global sCurCurrency$, sCurExtension$, sCurChartSource$, sCurStockIDLabel$, sCurSeparator$
+
+Public oNumberFormatter as Object
+Public bDebugmode as Boolean
+Global GlobListindex as Integer
+Public blabla() as String
+Public SplitDate as Date
+Public oChartSheet as Object
+Public oBackgroundSheet as Object
+Public Const SBDATECOLUMN = 3
+Public Const SBVALUECOLUMN = 4
+Public Const SBSTARTROW = 25
+Public Const SBCHARTPERIOD = 14
+Public Const SBINTERVAL = &quot;d&quot;
+Public sColumnHeader as String
+Public StartDate as Date
+Public EndDate as Date
+Public iCurRow as Integer
+Public iMaxRow as Integer
+Public iStartDay as Integer
+Public iStartMonth as Integer
+Public iStartYear as Integer
+Public iEndDay as Integer
+Public iEndMonth as Integer
+Public iEndYear as Integer
+Public oStatusLine as Object
+Public Today as Date
+Public sInterval as String
+Public ShortMonths(11,1)
+Public iStep as Integer
+Public sDepotCurrency as String
+Public iValueCol as Integer
+
+Public DlgReference as Object
+Public DlgTransaction as Object
+Public DlgStockRates as Object
+Public DlgStartUp as Object
+Public TransactModel as Object
+Public StockRatesModel as Object
+Public StartUpModel as Object
+Public StockRatesTitle(1 To 3)
+Public TransactTitle(1 To 2)
+Public NullList()
+Public sStartupWelcome$, sStartupChooseMarket$, sStartupHint$
+
+Public sMarket(7,10) as String
+Public sCountryMarket(7,10) as String
+
+Public cDlgCaption1$, cDlgCaption2$
+Public sMsgError$, sMsgNoName$, sMsgNoQuantity$, sMsgNoDividend$, sMsgNoExchangeRate$
+Public sMsgNoValidExchangeDate$, sMsgWrongExchangeDate$, sMsgSellTooMuch$, sMsgConfirm$
+Public sMsgFreeStock$, sMsgTotalLoss$, sMsgEndDatebeforeNow$, sMsgStartDatebeforeEndDate$
+
+Public sOk$, sCancel$
+Public sMsgAuthorization$, sMsgDeleteAll$
+Public SellMethod$
+Public cSplit$
+Global HistoryChartSource as String
+Public DateCellStyle as String
+Public CurrCellStyle as String
+Public sStartDate$, sEndDate$, sHistory$
+Public sInsertStockname$
+Public sProductname$, sTitle$
+Public sInsertStocks$, sStockname$, sNoInternetUpdate$, sMarketplace$, sNoInternetDataAvailable$
+Public sCheckInternetSettings as String
+
+Sub LoadLanguage()
+ LoadDepotDialogs()
+ Select Case sDocLanguage
+ Case &quot;de&quot;
+ LoadGermanLanguage()
+ Case &quot;en&quot;
+ LoadEnglishLanguage()
+ Case &quot;fr&quot;
+ LoadFrenchLanguage()
+ Case &quot;it&quot;
+ LoadItalianLanguage()
+ Case &quot;es&quot;
+ LoadSpanishLanguage()
+ Case &quot;sv&quot;
+ LoadSwedishLanguage()
+ Case &quot;ja&quot;
+ LoadJapaneseLanguage()
+ Case &quot;ko&quot;
+ LoadKoreanLanguage()
+ Case &quot;zh&quot;
+ If sDocCountry = &quot;CN&quot; Then
+ LoadChineseSimpleLanguage()
+ Else
+ LoadChineseTradLanguage()
+ End If
+ End Select
+ InitializeStartUpModel()
+End Sub
+
+Sub CompleteMarketList()
+Dim EuroIndex as Integer
+Dim LocCountry as String
+Dim LocLanguage as String
+Dim sLangList() as String
+Dim sCountryList() as String
+Dim sExtensionList() as String
+Dim MaxIndex as Integer
+Dim bIsLocale as Boolean
+
+ GlobListIndex = -1
+ For n = 0 To 5
+ LocLanguage = sMarket(n,6)
+ LocCountry = sMarket(n,7)
+ If Instr(1,LocLanguage,&quot;;&quot;,SBBINARY) = 0 Then
+ bIsLocale = CheckDocLocale(LocLanguage, LocCountry)
+ Else
+ EuroIndex = 0
+ sLangList() = ArrayoutofString(LocLanguage, &quot;;&quot;, MaxIndex)
+ sCountryList() = ArrayoutofString(LocCountry, &quot;;&quot;, MaxIndex)
+ sExtensionList() = ArrayoutofString(sMarket(n,8), &quot;;&quot;, MaxIndex)
+ For m = 0 To MaxIndex
+ bIsLocale = CheckDocLocale(sLangList(m), sCountryList(m))
+ If bIsLocale Then
+ EuroIndex = m
+ Exit For
+ End If
+ Next m
+ sMarket(n,6) = sLangList(EuroIndex)
+ sMarket(n,7) = sCountryList(EuroIndex)
+ sMarket(n,8) = sExtensionList(EuroIndex)
+ End If
+ If bIsLocale Then
+ GlobListIndex = n
+ Exit For
+ End If
+ Next n
+End Sub
+
+Sub LocalizedCurrencies()
+ If GlobListIndex = -1 Then
+ sCountryMarket(0,0) = &quot;Euro&quot;
+ sCountryMarket(0,1) = chr(8364)
+ sCountryMarket(0,2) = &quot;Paris&quot;
+ sCountryMarket(0,3) = &quot;http://fr.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.PA&amp;f=s4l1t1c1ghov&amp;e=.csv&quot;
+ sCountryMarket(0,5) = &quot;Code&quot;
+ sCountryMarket(0,6) = &quot;fr&quot;
+ sCountryMarket(0,7) = &quot;FR&quot;
+ sCountryMarket(0,8) = &quot;40C&quot;
+ sCountryMarket(0,9) = &quot;59/9&quot;
+ sCountryMarket(0,10) = &quot;1&quot;
+
+ sCountryMarket(1,0) = &quot;Euro&quot;
+ sCountryMarket(1,1) = chr(8364)
+ sCountryMarket(1,2) = &quot;Milano&quot;
+ sCountryMarket(1,3) = &quot;http://it.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.MI&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sCountryMarket(1,5) = &quot;Codice&quot;
+ sCountryMarket(1,6) = &quot;it&quot;
+ sCountryMarket(1,7) = &quot;IT&quot;
+ sCountryMarket(1,8) = &quot;410&quot;
+ sCountryMarket(1,9) = &quot;44&quot;
+ sCountryMarket(1,10) = &quot;1&quot;
+
+ sCountryMarket(2,0) = &quot;Euro&quot;
+ sCountryMarket(2,1) = chr(8364)
+ sCountryMarket(2,2) = &quot;Madrid&quot;
+ sCountryMarket(2,3) = &quot;http://es.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;m=MC&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sCountryMarket(2,5) = &quot;Simbolo&quot;
+ sCountryMarket(2,6) = &quot;es&quot;
+ sCountryMarket(2,7) = &quot;ES&quot;
+ sCountryMarket(2,8) = &quot;40A&quot;
+ sCountryMarket(2,9) = &quot;44&quot;
+ sCountryMarket(2,10) = &quot;1&quot;
+
+ sCountryMarket(3,0) = &quot;Dansk krone&quot;
+ sCountryMarket(3,1) = &quot;kr&quot;
+ sCountryMarket(3,2) = &quot;København&quot;
+ sCountryMarket(3,3) = &quot;http://dk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID.CO&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sCountryMarket(3,5) = &quot;Aktiesymbol&quot;
+ sCountryMarket(3,6) = &quot;da&quot;
+ sCountryMarket(3,7) = &quot;DK&quot;
+ sCountryMarket(3,8) = &quot;406&quot;
+ sCountryMarket(3,9) = &quot;44&quot;
+ sCountryMarket(3,10) = &quot;1&quot;
+
+ sCountryMarket(4,0) = &quot;Svensk krona&quot;
+ sCountryMarket(4,1) = &quot;kr&quot;
+ sCountryMarket(4,2) = &quot;Stockholm&quot;
+ sCountryMarket(4,3) = &quot;http://se.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;f=sl1d1t1c1ohgv&amp;e=.c&quot;
+ sCountryMarket(4,5) = &quot;Kod&quot;
+ sCountryMarket(4,6) = &quot;sv&quot;
+ sCountryMarket(4,7) = &quot;SE&quot;
+ sCountryMarket(4,8) = &quot;41D&quot;
+ sCountryMarket(4,9) = &quot;44&quot;
+ sCountryMarket(4,10) = &quot;1&quot;
+
+ &apos; Taiwan Dollar
+ sCountryMarket(5,0) = &quot;新臺幣&quot;
+ sCountryMarket(5,1) = &quot;¥&quot;
+ sCountryMarket(5,2) = &quot;代號&quot;
+ sCountryMarket(5,3) = &quot;http://tw.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.TW&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sCountryMarket(5,5) = &quot;代號&quot;
+ sCountryMarket(5,6) = &quot;zh&quot;
+ sCountryMarket(5,7) = &quot;TW&quot;
+ sCountryMarket(5,8) = &quot;404&quot;
+ sCountryMarket(5,9) = &quot;44&quot;
+ sCountryMarket(5,10) = &quot;1&quot;
+
+ &apos; Chinese Yuan
+ sCountryMarket(6,0) = &quot;人民币&quot;
+ sCountryMarket(6,1) = &quot;¥&quot;
+ sCountryMarket(6,2) = &quot;代号&quot;
+ sCountryMarket(6,3) = &quot;http://cn.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.SS&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sCountryMarket(6,5) = &quot;代号&quot;
+ sCountryMarket(6,6) = &quot;zh&quot;
+ sCountryMarket(6,7) = &quot;CN&quot;
+ sCountryMarket(6,8) = &quot;804&quot;
+ sCountryMarket(6,9) = &quot;44&quot;
+ sCountryMarket(6,10) = &quot;1&quot;
+
+ &apos; korean Won
+ sCountryMarket(7,0) = &quot;한국 원화&quot;
+ sCountryMarket(7,1) = &quot;₩&quot;
+ sCountryMarket(7,2) = &quot;서울&quot;
+ sCountryMarket(7,3) = &quot;http://kr.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.KS&amp;f=snl1d1t1c1ohgv&amp;e=.csv&quot;
+ sCountryMarket(7,5) = &quot;종목 코드&quot;
+ sCountryMarket(7,6) = &quot;ko&quot;
+ sCountryMarket(7,7) = &quot;KR&quot;
+ sCountryMarket(7,8) = &quot;412&quot;
+ sCountryMarket(7,9) = &quot;44&quot;
+ sCountryMarket(7,10) = &quot;2&quot;
+
+
+&apos; sCountryMarket(5,0) = &quot;Российский рубль&quot;
+&apos; sCountryMarket(5,1) = &quot;р.&quot;
+&apos; sCountryMarket(5,2) = &quot;&quot;
+&apos; sCountryMarket(5,3) = &quot;&quot;
+&apos; sCountryMarket(5,5) = &quot;&quot;
+&apos; sCountryMarket(5,6) = &quot;ru&quot;
+&apos; sCountryMarket(5,7) = &quot;RU&quot;
+&apos; sCountryMarket(5,8) = &quot;-419&quot;
+&apos; sCountryMarket(5,9) = &quot;&quot;
+&apos;
+&apos; sCountryMarket(6,0) = &quot;Złoty polski&quot;
+&apos; sCountryMarket(6,1) = &quot;zł&quot;
+&apos; sCountryMarket(6,2) = &quot;&quot;
+&apos; sCountryMarket(6,3) = &quot;&quot;
+&apos; sCountryMarket(6,5) = &quot;&quot; &apos;Still Todo!!
+&apos; sCountryMarket(6,6) = &quot;pl&quot;
+&apos; sCountryMarket(6,7) = &quot;PL&quot;
+&apos; sCountryMarket(6,8) = &quot;-415&quot;
+&apos; sCountryMarket(6,9) = &quot;&quot;
+&apos;
+&apos; sCountryMarket(7,0) = &quot;Türkische Lira&quot;
+&apos; sCountryMarket(7,1) = &quot;TL&quot;
+&apos; sCountryMarket(7,2) = &quot;&quot;
+&apos; sCountryMarket(7,3) = &quot;&quot;
+&apos; sCountryMarket(7,5) = &quot;&quot; &apos;Still Todo!!
+&apos; sCountryMarket(7,6) = &quot;tr&quot;
+&apos; sCountryMarket(7,7) = &quot;TR&quot;
+&apos; sCountryMarket(7,8) = &quot;-41F&quot;
+&apos; sCountryMarket(7,9) = &quot;&quot;
+
+ Dim n as Integer
+ Dim m as Integer
+&apos; Dim sCountryMarket(6,9) as String
+
+ For n = 0 To Ubound(sCountryMarket(),1)
+ If sDocLanguage = sCountryMarket(n,6) and sDocCountry = sCountryMarket(n,7) Then
+ GlobListIndex = 6
+ For m = 0 To 10
+ sMarket(6,m) = sCountryMarket(n,m)
+ Next m
+ Exit For
+ End If
+ Next n
+ End If
+End Sub
+
+Sub LoadDepotDialogs()
+ DlgTransaction = LoadDialog(&quot;Depot&quot;, &quot;Dialog2&quot;)
+ DlgStockRates = LoadDialog(&quot;Depot&quot;, &quot;Dialog3&quot;)
+ DlgStartUp = LoadDialog(&quot;Depot&quot;, &quot;Dialog4&quot;)
+ TransactModel = DlgTransaction.Model
+ StockRatesModel = DlgStockRates.Model
+ StartUpModel = DlgStartUp.Model
+End Sub
+
+
+Sub InitializeStartUpModel()
+ With StartUpModel
+ .lblWelcome.Label = sStartupWelcome &amp; Chr(13) &amp; chr(13) &amp; sStartUpChooseMarket
+ sStartUpHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ .lblHint.Label = sStartupHint
+&apos; .cmdGoOn.Enabled = Ubound(StartUpModel.lstMarkets.SelectedItems()) &lt;&gt; -1
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+End Sub</script:module>
diff --git a/wizards/source/depot/Currency.xba b/wizards/source/depot/Currency.xba
new file mode 100644
index 000000000..d728424d3
--- /dev/null
+++ b/wizards/source/depot/Currency.xba
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Currency" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+
+Dim bDoUnLoad as Boolean
+
+
+Sub Startup()
+Dim i as Integer
+Dim a as Integer
+Dim ListString as String
+Dim MarketListBoxControl as Object
+ Initialize(False)
+ MarketListBoxControl = DlgStartUp.GetControl(&quot;lstMarkets&quot;)
+ a = 0
+ For i = 0 To Ubound(sMarket(),1)
+ ListString = sMarket(i,0)
+ If sMarket(i,0) &lt;&gt; &quot;&quot; Then
+ If sMarket(i,3) = &quot;&quot; Then
+ ListString = ListString &amp; &quot; (&quot; &amp; sNoInternetUpdate &amp; &quot;)&quot;
+ Else
+ ListString = ListString &amp; &quot; (&quot; &amp; sMarketplace &amp; &quot; &quot; &amp; sMarket(i,2) &amp; &quot;)&quot;
+ End If
+ MarketListBoxControl.AddItem(ListString, a)
+ a = a + 1
+ End If
+ Next i
+ MarketListBoxControl.SelectItemPos(GlobListIndex, True)
+ DlgStartUp.Title = sDepotCurrency
+ DlgStartUp.Model.cmdGoOn.DefaultButton = True
+ DlgStartUp.GetControl(&quot;lstMarkets&quot;).SetFocus()
+ DlgStartUp.Execute()
+ DlgStartUp.Dispose()
+End Sub
+
+
+Sub EnableGoOnButton()
+ StartUpModel.cmdGoOn.Enabled = True
+ StartUpModel.cmdGoOn.DefaultButton = True
+End Sub
+
+
+Sub CloseStartUpDialog()
+ DlgStartUp.EndExecute()
+&apos; oDocument.Dispose()
+End Sub
+
+
+Sub DisposeDocument()
+ If bDoUnload Then
+ oDocument.Dispose()
+ End If
+End Sub
+
+
+Sub ChooseMarket(Optional aEvent)
+Dim Index as Integer
+Dim bIsDocLanguage as Boolean
+Dim bIsDocCountry as Boolean
+ oInternetModel = GetControlModel(oDocument.Sheets(0), &quot;CmdInternet&quot;)
+ If Not IsMissing(aEvent) Then
+ Index = StartupModel.lstMarkets.SelectedItems(0)
+ oInternetModel.Tag = Index
+ Else
+ Index = oInternetModel.Tag
+ End If
+ oMarketModel = GetControlModel(oDocument.Sheets(0), &quot;CmdHistory&quot;)
+ sCurCurrency = sMarket(Index,1)
+ If Index = 0 Then
+ HistoryChartSource = sMarket(Index,4)
+ End If
+ sCurStockIDLabel = sMarket(Index,5)
+ sCurExtension = sMarket(Index,8)
+ iValueCol = Val(sMarket(Index,10))
+ If Instr(sCurExtension,&quot;;&quot;) &lt;&gt; 0 Then
+ &apos; Take the german extension as the stock place is Frankfurt
+ sCurExtension = &quot;407&quot;
+ End If
+ sCurChartSource = sMarket(Index,3)
+ bIsDocLanguage = Instr(1, sMarket(Index,6), sDocLanguage, SBBINARY) &lt;&gt; 0
+ bIsDocCountry = Instr(1, sMarket(Index,7), sDocCountry, SBBINARY) &lt;&gt; 0 OR SDocCountry = &quot;&quot;
+ sCurSeparator = sMarket(Index,9)
+ TransactModel.txtRate.CurrencySymbol = sCurCurrency
+ TransactModel.txtFix.CurrencySymbol = sCurCurrency
+ TransactModel.txtMinimum.CurrencySymbol = sCurCurrency
+ bEnableMarket = Index = 0
+ bEnableInternet = sCurChartSource &lt;&gt; &quot;&quot;
+ oMarketModel.Enabled = bEnableMarket
+ oInternetModel.Enabled = bEnableInternet
+ If Not IsMissing(aEvent) Then
+ ConvertStylesCurrencies()
+ bDoUnload = False
+ DlgStartUp.EndExecute()
+ End If
+End Sub
+
+
+Sub ConvertStylesCurrencies()
+Dim m as integer
+Dim aStyleFormat as Object
+Dim StyleName as String
+Dim bAddToList as Boolean
+Dim oStyle as Object
+Dim oStyles as Object
+ UnprotectSheets(oSheets)
+ oFirstSheet.GetCellByPosition(SBCOLUMNID1, SBROWHEADER1).SetString(sCurStockIDLabel)
+ oStyles = oDocument.StyleFamilies.GetbyIndex(0)
+ For m = 0 To oStyles.count-1
+ oStyle = oStyles.GetbyIndex(m)
+ StyleName = oStyle.Name
+ bAddToList = CheckFormatType(oStyle)
+ If bAddToList Then
+ SwitchNumberFormat(ostyle, oDocFormats, sCurCurrency, sCurExtension)
+ End If
+ Next m
+ ProtectSheets(oSheets)
+End Sub
+
+
+Sub SwitchNumberFormat(oObject as Object, oFormats as object, sNewSymbol as String, sNewExtension as String)
+Dim nFormatLanguage as Integer
+Dim nFormatDecimals as Integer
+Dim nFormatLeading as Integer
+Dim bFormatLeading as Integer
+Dim bFormatNegRed as Integer
+Dim bFormatThousands as Integer
+Dim aNewStr as String
+Dim iNumberFormat as Long
+Dim sSimpleStr as String
+Dim nSimpleKey as Long
+Dim aFormat()
+Dim oLocale as New com.sun.star.lang.Locale
+ &apos; Numberformat with the new Symbol as Base for new Format
+ sSimpleStr = &quot;0 [$&quot; &amp; sNewSymbol &amp; &quot;-&quot; &amp; sNewExtension &amp; &quot;]&quot;
+ nSimpleKey = Numberformat(oFormats, sSimpleStr, oDocLocale)
+ On Local Error Resume Next
+ iNumberFormat = oObject.NumberFormat
+ If Err &lt;&gt; 0 Then
+ Msgbox &quot;Error Reading the Number Format&quot;
+ Resume CLERROR
+ End If
+
+ On Local Error GoTo NOKEY
+ aFormat() = oFormats.getByKey(iNumberFormat)
+ On Local Error GoTo 0
+ &apos; set new currency format with according settings
+ nFormatDecimals = aFormat.Decimals
+ nFormatLeading = aFormat.LeadingZeros
+ bFormatNegRed = aFormat.NegativeRed
+ bFormatThousands = aFormat.ThousandsSeparator
+ oLocale = aFormat.Locale
+ aNewStr = oFormats.generateFormat(nSimpleKey, oLocale, bFormatThousands, bFormatNegRed, nFormatDecimals, nFormatLeading)
+ oObject.NumberFormat = Numberformat(oFormats, aNewStr, oLocale)
+ NOKEY:
+ If Err &lt;&gt; 0 Then
+ Resume CLERROR
+ End If
+ CLERROR:
+End Sub
+
+
+Function Numberformat( oFormats as Object, aFormatStr as String, oLocale as Variant )
+Dim nRetkey
+ nRetKey = oFormats.queryKey(aFormatStr, oLocale, True)
+ If nRetKey = -1 Then
+ nRetKey = oFormats.addNew( aFormatStr, oLocale )
+ If nRetKey = -1 Then nRetKey = 0
+ End If
+ Numberformat = nRetKey
+End Function
+
+
+Function CheckFormatType(oStyle as Object)
+Dim oFormatofObject as Object
+ oFormatofObject = oDocFormats.getByKey(oStyle.NumberFormat)
+ CheckFormatType = INT(oFormatOfObject.Type) AND com.sun.star.util.NumberFormat.CURRENCY
+End Function</script:module>
diff --git a/wizards/source/depot/Depot.xba b/wizards/source/depot/Depot.xba
new file mode 100644
index 000000000..6a8b1419c
--- /dev/null
+++ b/wizards/source/depot/Depot.xba
@@ -0,0 +1,517 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Depot" script:language="StarBasic">Option Explicit
+
+
+Sub Initialize(Optional bChooseMarketPlace as Boolean)
+Dim bEnableHistory as Boolean
+ GlobalScope.BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+&apos; oMarketModel = GetControlModel(oDocument.Sheets(0), &quot;CmdHistory&quot;)
+&apos; bEnableHistory = oMarketModel.Enabled
+ ToggleWindow(False)
+ Today = Date()
+ bDebugmode = False
+ oDocument = ThisComponent
+ oController = oDocument.GetCurrentController
+ oSheets = oDocument.Sheets
+ oFirstSheet = oSheets(0)
+ oMovementSheet = oSheets(1)
+ oBankSheet = oSheets(2)
+ oDocFormats = oDocument.NumberFormats
+ oNumberFormatter = CreateUnoService(&quot;com.sun.star.util.NumberFormatter&quot;)
+ oNumberFormatter.AttachNumberFormatsSupplier(oDocument)
+ oDocLocale = oDocument.CharLocale
+ sDocLanguage = oDocLocale.Language
+ sDocCountry = oDocLocale.Country
+ LoadLanguage()
+ ToggleWindow(True)
+&apos; oMarketModel.Enabled = bEnableHistory
+ If Not IsMissing(bChooseMarketPlace) Then
+ If bChoosemarketPlace Then
+ ChooseMarket()
+ End If
+ Else
+ ChooseMarket()
+ End If
+ If Not IsMissing(bChooseMarketPlace) Then
+ If bChooseMarketPlace Then
+ oMarketModel.Enabled = bEnableMarket
+ oInternetModel.Enabled = bEnableInternet
+ End If
+ End If
+End Sub
+
+
+Sub Buy()
+ Initialize(True)
+ FillListbox(DlgTransaction.GetControl(&quot;lstBuyStocks&quot;), TransactTitle(SBDIALOGBUY), False)
+ SetupTransactionControls(SBDIALOGBUY)
+ EnableTransactionControls(False)
+ DlgTransaction.Execute()
+End Sub
+
+
+Sub Sell()
+ Initialize(True)
+ If FillListbox(DlgTransaction.GetControl(&quot;lstSellStocks&quot;), TransactTitle(SBDIALOGSELL), True) Then
+ SetupTransactionControls(SBDIALOGSELL)
+ EnableTransactionControls(False)
+ DlgTransaction.Execute()
+ End If
+End Sub
+
+
+Sub Reset()
+Dim TransactionCount as Integer
+Dim StockCount, iStartRow, i as Integer
+Dim oRows, oRange as Object
+Dim StockName as String
+ Initialize(True)
+ &apos; Delete transactions and reset overview
+ If MsgBox(sMsgDeleteAll, SBMSGYESNO+SBMSGQUESTION+SBMSGDEFAULTBTN2, sMsgAuthorization) = 6 Then
+ &apos; Assumption: If and only if there is an overview, then there are transactions, too
+ UnprotectSheets(oSheets)
+ StockCount = GetStocksCount(iStartRow)
+
+ For i = 1 To StockCount
+ StockName = oFirstSheet.GetCellbyPosition(SBCOLUMNNAME1, iStartRow + i).String
+ If oSheets.HasbyName(StockName) Then
+ oSheets.RemoveByName(StockName)
+ End If
+ Next
+ oDocument.AddActionLock
+ RemoveStockRows(oFirstSheet, iStartRow + 1, StockCount)
+ TransactionCount = GetTransactionCount(iStartRow)
+ RemoveStockRows(oMovementSheet, iStartRow + 2, TransactionCount)
+ ProtectSheets(oSheets)
+ oDocument.RemoveActionLock
+ End If
+End Sub
+
+
+Sub TransactionOk
+Dim Sold as Long
+Dim RestQuantity, Value, PartialValue, Profit
+Dim iNewRow as Integer, iRow as Integer
+Dim iStockRow as Long, iRestQuantity as Long
+Dim oNameCell as Object
+Dim CellStockName as String, SelStockName as String
+Dim CurRate as Double
+Dim TransactDate as Date
+Dim LocStockName as String
+ &apos; Check for rate entered
+ If TransactModel.txtRate.Value = 0 Then
+ If TransactModel.Step = SBDIALOGBUY Then
+ If MsgBox(sMsgFreeStock, SBMSGYESNO+SBMSGQUESTION, sMsgConfirm)=7 Then
+ Exit Sub
+ End If
+ Else
+ If MsgBox(sMsgTotalLoss, SBMSGYESNO+SBMSGQUESTION, sMsgConfirm)=7 Then
+ Exit Sub
+ End If
+ End If
+ End If
+ CurRate = TransactModel.txtRate.Value
+ TransactDate = CDateFromUNODate(TransactModel.txtDate.Date)
+ DlgTransaction.EndExecute()
+ UnprotectSheets(oSheets)
+
+ iNewRow = DuplicateRow(oMovementSheet, &quot;HiddenRow3&quot;)
+
+ If TransactModel.Step = SBDIALOGBUY Then
+ CellStockName = TransactModel.lstBuyStocks.Text
+ If Instr(1,CellStockName,&quot;$&quot;) &lt;&gt; 0 Then
+ CellStockName = &quot;&apos;&quot; &amp; CellStockName &amp; &quot;&apos;&quot;
+ End If
+ oMovementSheet.GetCellByPosition(SBCOLUMNNAME2, iNewRow).String = CellStockName
+ oMovementSheet.GetCellByPosition(SBCOLUMNQUANTITY2, iNewRow).Value = TransactModel.txtQuantity.Value
+ Else
+ CellStockName = DlgTransaction.GetControl(&quot;lstSellStocks&quot;).GetSelectedItem()
+ oMovementSheet.GetCellByPosition(SBCOLUMNNAME2, iNewRow).String = CellStockName
+ oMovementSheet.GetCellByPosition(SBCOLUMNQUANTITY2, iNewRow).Value = -TransactModel.txtQuantity.Value
+ End If
+
+ oMovementSheet.GetCellByPosition(SBCOLUMNDATE2, iNewRow).Value = CDateFromUNODate(TransactModel.txtDate.Date)
+ oMovementSheet.GetCellByPosition(SBCOLUMNRATE2, iNewRow).Value = TransactModel.txtRate.Value
+ oMovementSheet.GetCellByPosition(SBCOLUMNPROVPERCENT2, iNewRow).Value = TransactModel.txtCommission.EffectiveValue
+ oMovementSheet.GetCellByPosition(SBCOLUMNPROVMIN2, iNewRow).Value = TransactModel.txtMinimum.Value
+ oMovementSheet.GetCellByPosition(SBCOLUMNPROVFIX2, iNewRow).Value = TransactModel.txtFix.Value
+
+ &apos; Buy stocks: Update overview for new stocks
+ If TransactModel.Step = SBDIALOGBUY Then
+ iStockRow = GetStockRowIndex(CellStockName)
+ If iStockRow = -1 Then
+ iNewRow = DuplicateRow(oFirstSheet, &quot;HiddenRow2&quot;)
+ oFirstSheet.GetCellByPosition(SBCOLUMNNAME1, iNewRow).String = CellStockName
+ oFirstSheet.GetCellByPosition(SBCOLUMNID1, iNewRow).String = TransactModel.txtStockID.Text
+ iStockRow = GetStockRowIndex(CellStockName)
+ End If
+ &apos; Sell stocks: Get transaction value, then update Transaction sheet
+ ElseIf TransactModel.Step = SBDIALOGSELL Then
+ Profit = oMovementSheet.GetCellByPosition(SBCOLUMNPROCEEDS2, iNewRow).Value
+ Value = Profit
+ Sold = TransactModel.txtQuantity.Value
+ SelStockName = DlgTransaction.GetControl(&quot;lstSellStocks&quot;).GetSelectedItem()
+ &apos; Go to first name
+ If TransactMode = FIFO Then
+ iRow = SBROWFIRSTTRANSACT2
+ Else
+ iRow = iNewRow-1
+ End If
+
+ &apos; Check that no transaction after split date exists else cancel split
+ Do While Sold &gt; 0
+ oNameCell = oMovementSheet.GetCellByPosition(SBCOLUMNNAME2, iRow)
+ CellStockName = oNameCell.String
+ If CellStockName = SelStockName Then
+ &apos; Update transactions: Note quantity sold
+ RestQuantity = oMovementSheet.GetCellByPosition(SBCOLUMNQTYREST2, iRow).Value
+ &apos; If there still is a rest left ...
+ If RestQuantity &gt; 0 Then
+ If RestQuantity &lt; Sold Then
+ &apos; Recalculate profit of new transaction
+ Profit = Profit - oMovementSheet.GetCellByPosition(SBCOLUMNPRCREST2, iRow).Value
+ AddValueToCellContent(SBCOLUMNQTYSOLD2, iRow, RestQuantity)
+ PartialValue = RestQuantity / Sold * Value
+ AddValueToCellContent(SBCOLUMNREALPROC2, iRow, PartialValue)
+ Sold = Sold - RestQuantity
+ Value = Value - PartialValue
+ Else
+ &apos; Recalculate profit of neTransactModel.lstBuyStocks.Textw transaction
+ PartialValue = oMovementSheet.GetCellByPosition(SBCOLUMNPRCREST2, iRow).Value
+ Profit = Profit - PartialValue/RestQuantity * Sold
+ &apos; Update sold shares cell
+ AddValueToCellContent(SBCOLUMNQTYSOLD2, iRow, Sold)
+ &apos; Update sales turnover cell
+ AddValueToCellContent(SBCOLUMNREALPROC2, iRow, Value)
+ &apos; Update variables for rest of transaction
+ Sold = 0
+ Value = 0
+ End If
+ End If
+ End If
+ iRow = iRow + TransactMode
+ Loop
+ oMovementSheet.GetCellByPosition(SBCOLUMNREALPROFIT2,iNewRow).Value = Profit
+ iStockRow = GetStockRowIndex(SelStockName)
+ iRestQuantity = oFirstSheet.GetCellbyPosition(SBCOLUMNQUANTITY1, iStockRow).Value
+&apos; If iRestQuantity = 0 Then
+&apos; If oSheets.HasbyName(SelStockName) Then
+&apos; oSheets.RemoveByName(SelStockName)
+&apos; End If
+&apos; Else
+
+&apos; End If
+ End If
+ InsertCurrentValue(CurRate, iStockRow,TransactDate)
+ ProtectSheets(oSheets)
+End Sub
+
+
+Sub SelectStockname(aEvent as Object)
+Dim iCurRow as Integer
+Dim CurStockName as String
+ With TransactModel
+ &apos; Find row with stock name
+ If TransactModel.Step = SBDIALOGBUY Then
+ CurStockName = .lstBuyStocks.Text
+ iCurRow = GetStockRowIndex(CurStockName)
+ .txtQuantity.ValueMax = 10000000
+ Else
+ Dim ListBoxList() as String
+ ListBoxList() = GetSelectedListboxItems(aEvent.Source.getModel())
+ CurStockName = ListBoxList(0)
+&apos; CurStockName = DlgTransaction.GetControl(aEvent.Source.getModel.Name).GetSelectedItem()
+ iCurRow = GetStockRowIndex(CurStockName)
+ Dim fdouble as Double
+ fdouble = oFirstSheet.GetCellByPosition(SBCOLUMNQUANTITY1, iCurRow).Value
+ .txtQuantity.Value = fdouble
+ .txtQuantity.ValueMax = oFirstSheet.GetCellByPosition(SBCOLUMNQUANTITY1, iCurRow).Value
+ .txtRate.Value = oFirstSheet.GetCellbyPosition(SBCOLUMNRATE1, iCurRow).Value
+ End If
+ .txtStockID.Enabled = .Step = SBDIALOGBUY
+ .lblStockID.Enabled = .Step = SBDIALOGBUY
+ &apos; Default settings for quantity and rate
+ .txtStockID.Text = GetStockID(CurStockName, iCurRow)
+ End With
+ EnableTransactionControls(CurStockName &lt;&gt; &quot;&quot;)
+ TransactModel.cmdGoOn.DefaultButton = True
+End Sub
+
+
+
+Sub HandleStocks(Mode as Integer, oDialog as Object)
+Dim DividendPerShare, DividendTotal, RestQuantity, OldValue
+Dim SelStockName, CellStockName as String
+Dim oNameCell as Object, oDateCell as Object
+Dim iRow as Integer
+Dim oDividendCell as Object
+Dim Amount
+Dim OldNumber, NewNumber as Integer
+Dim NoteText as String
+Dim TotalStocksCount as Long
+Dim oModel as Object
+ oDocument.AddActionLock
+ oDialog.EndExecute()
+ oModel = oDialog.Model
+ SelStockName = DlgStockRates.GetControl(&quot;lstStockNames&quot;).GetSelectedItem()
+ Select Case Mode
+ Case HANDLEDIVIDEND
+ Dim bTakeTotal as Boolean
+ &apos; Update transactions: Enter dividend paid for all Buy transactions not sold completely
+ bTakeTotal = oModel.optTotal.State = 1
+ If bTakeTotal Then
+ DividendTotal = oModel.txtDividend.Value
+ iRow = GetStockRowIndex(SelStockName)
+ TotalStocksCount = oFirstSheet.GetCellByPosition(SBCOLUMNQUANTITY1,iRow).Value
+ DividendPerShare = DividendTotal/TotalStocksCount
+ Else
+ DividendPerShare = oModel.txtDividend.Value
+ End If
+
+ Case HANDLESPLIT
+ &apos; Store entered values in variables
+ OldNumber = oModel.txtOldRate.Value
+ NewNumber = oModel.txtNewRate.Value
+ SplitDate = CDateFromUNODate(oModel.txtDate.Date)
+ iRow = SBROWFIRSTTRANSACT2
+ NoteText = cSplit &amp; SplitDate &amp; &quot;, &quot; &amp; oModel.txtOldRate.Value &amp; oModel.lblColon.Label &amp; oModel.txtNewRate.Value
+ Do
+ oNameCell = oMovementSheet.GetCellByPosition(SBCOLUMNNAME2, iRow)
+ CellStockName = oNameCell.String
+ If CellStockName = SelStockName Then
+ oDateCell = oMovementSheet.GetCellByPosition(SBCOLUMNDATE2, iRow)
+ If oDateCell.Value &gt;= SplitDate Then
+ MsgBox sMsgWrongExchangeDate, SBMSGOK + SBMSGSTOP, sMsgError
+ Exit Sub
+ End If
+ End If
+ iRow = iRow + 1
+ Loop Until CellStockName = &quot;&quot;
+ End Select
+ iRow = SBROWFIRSTTRANSACT2
+ UnprotectSheets(oSheets)
+ Do
+ oNameCell = oMovementSheet.GetCellByPosition(SBCOLUMNNAME2, iRow)
+ CellStockName = oNameCell.String
+ If CellStockName = SelStockName Then
+ Select Case Mode
+ Case HANDLEDIVIDEND
+ RestQuantity = oMovementSheet.GetCellByPosition(SBCOLUMNQTYREST2, iRow).Value
+ If RestQuantity &gt; 0 Then
+ oDividendCell = oMovementSheet.GetCellByPosition(SBCOLUMNDIVIDEND2, iRow)
+ OldValue = oDividendCell.Value
+ oDividendCell.Value = OldValue + RestQuantity * DividendPerShare
+ End If
+ Case HANDLESPLIT
+ oDateCell = oMovementSheet.GetCellByPosition(SBCOLUMNDATE2, iRow)
+ SplitCellValue(oMovementSheet, NewNumber, OldNumber, SBCOLUMNQUANTITY2, iRow, NoteText)
+ SplitCellValue(oMovementSheet, OldNumber, NewNumber, SBCOLUMNRATE2, iRow, &quot;&quot;)
+ SplitCellValue(oMovementSheet, NewNumber, OldNumber, SBCOLUMNQTYSOLD2, iRow, &quot;&quot;)
+ End Select
+ End If
+ iRow = iRow + 1
+ Loop Until CellStockName = &quot;&quot;
+ If Mode = HANDLESPLIT Then
+ CalculateChartafterSplit(SelStockName, NewNumber, OldNumber, NoteText, SplitDate)
+ End If
+ oDocument.CalculateAll()
+ ProtectSheets(oSheets)
+ oDocument.RemoveActionLock
+End Sub
+
+
+Sub CancelStockRate()
+ DlgStockRates.EndExecute()
+End Sub
+
+
+Sub CancelTransaction()
+ DlgTransaction.EndExecute()
+End Sub
+
+
+Sub CommitStockRate()
+Dim CurStep as Integer
+ CurStep = StockRatesModel.Step
+ Select Case CurStep
+ Case 1
+ &apos; Check for quantity entered
+ If StockRatesModel.txtDividend.Value = 0 Then
+ MsgBox sMsgNoDividend, SBMSGSTOP+SBMSGSTOP, sMsgError
+ Exit Sub
+ End If
+ HandleStocks(HANDLEDIVIDEND, DlgStockRates)
+ Case 2
+ HandleStocks(HANDLESPLIT, DlgStockRates)
+ Case 3
+ InsertCompanyHistory()
+ End Select
+End Sub
+
+
+Sub EnableTransactionControls(bEnable as Boolean)
+ With TransactModel
+ .lblQuantity.Enabled = bEnable
+ .txtQuantity.Enabled = bEnable
+ .lblRate.Enabled = bEnable
+ .txtRate.Enabled = bEnable
+ .lblDate.Enabled = bEnable
+ .txtDate.Enabled = bEnable
+ .lblCommission.Enabled = bEnable
+ .txtCommission.Enabled = bEnable
+ .lblMinimum.Enabled = bEnable
+ .txtMinimum.Enabled = bEnable
+ .lblFix.Enabled = bEnable
+ .txtFix.Enabled = bEnable
+ If TransactModel.Step = SBDIALOGSELL Then
+ .cmdGoOn.Enabled = Ubound(TransactModel.lstSellStocks.SelectedItems()) &gt; -1
+ DlgTransaction.GetControl(&quot;lstSellStocks&quot;).SetFocus()
+ Else
+ .cmdGoOn.Enabled = TransactModel.lstBuyStocks.Text &lt;&gt; &quot;&quot;
+ DlgTransaction.GetControl(&quot;lstBuyStocks&quot;).SetFocus()
+ End If
+ If bEnable Then
+ TransactModel.cmdGoOn.DefaultButton = True
+ End If
+ End With
+End Sub
+
+
+Sub SetupTransactionControls(CurStep as Integer)
+ DlgReference = DlgTransaction
+ With TransactModel
+ .txtDate.Date = CDateToUNODate(Date())
+ .txtDate.DateMax = CDateToUNODate(Date())
+ .txtStockID.Enabled = False
+ .lblStockID.Enabled = False
+ .lblStockID.Label = sCurStockIDLabel
+ .txtRate.CurrencySymbol = sCurCurrency
+ .txtFix.CurrencySymbol = sCurCurrency
+ .Step = CurStep
+ End With
+ DlgTransaction.Title = TransactTitle(CurStep)
+ CellValuetoControl(oBankSheet, TransactModel.txtCommission, &quot;ProvisionPercent&quot;)
+ CellValuetoControl(oBankSheet, TransactModel.txtMinimum, &quot;ProvisionMinimum&quot;)
+ CellValuetoControl(oBankSheet, TransactModel.txtFix, &quot;ProvisionFix&quot;)
+End Sub
+
+
+Sub AddShortCuttoControl()
+Dim SelCompany as String
+Dim iRow, SelIndex as Integer
+ SelIndex = DlgTransaction.GetControl(&quot;lstBuyStocks&quot;).GetSelectedItemPos()
+ If SelIndex &lt;&gt; -1 Then
+ SelCompany = TransactModel.lstBuyStocks.StringItemList(SelIndex)
+ iRow = GetStockRowIndex(SelCompany)
+ If iRow &lt;&gt; -1 Then
+ TransactModel.txtStockID.Text = oFirstSheet.GetCellByPosition(SBCOLUMNID1,iRow).String
+ TransactModel.txtRate.Value = oFirstSheet.GetCellByPosition(SBCOLUMNRATE1,iRow).Value
+ Else
+ TransactModel.txtStockID.Text = &quot;&quot;
+ TransactModel.txtRate.Value = 0
+ End If
+ Else
+ TransactModel.txtStockID.Text = &quot;&quot;
+ TransactModel.txtRate.Value = 0
+ End If
+End Sub
+
+
+Sub OpenStockRatePage(aEvent)
+Dim CurStep as Integer
+ Initialize(True)
+ CurStep = aEvent.Source.Model.Tag
+ If FillListbox(DlgStockRates.GetControl(&quot;lstStockNames&quot;), StockRatesTitle(CurStep), True) Then
+ StockRatesModel.Step = CurStep
+ ToggleStockRateControls(False, CurStep)
+ InitializeStockRatesControls(CurStep)
+ DlgStockRates.Execute()
+ End If
+End Sub
+
+
+Sub SelectStockNameForRates()
+Dim StockName as String
+ StockName = DlgStockRates.GetControl(&quot;lstStockNames&quot;).GetSelectedItem()
+ If StockName &lt;&gt; &quot;&quot; Then
+ StockRatesModel.txtStockID.Text = GetStockID(StockName)
+ ToggleStockRateControls(True, StockRatesModel.Step)
+ End If
+ StockRatesModel.cmdGoOn.DefaultButton = True
+End Sub
+
+
+Sub ToggleStockRateControls(bDoEnable as Boolean, CurStep as Integer)
+ With StockRatesModel
+ .lblStockID.Enabled = False
+ .txtStockID.Enabled = False
+ .cmdGoOn.Enabled = Ubound(StockRatesModel.lstStockNames.SelectedItems()) &lt;&gt; -1
+ Select Case CurStep
+ Case 1
+ .optPerShare.Enabled = bDoEnable
+ .optTotal.Enabled = bDoEnable
+ .lblDividend.Enabled = bDoEnable
+ .txtDividend.Enabled = bDoEnable
+ Case 2
+ .lblExchangeRate.Enabled = bDoEnable
+ .lblDate.Enabled = bDoEnable
+ .lblColon.Enabled = bDoEnable
+ .txtOldRate.Enabled = bDoEnable
+ .txtNewRate.Enabled = bDoEnable
+ .txtDate.Enabled = bDoEnable
+ Case 3
+ .lblStartDate.Enabled = bDoEnable
+ .lblEndDate.Enabled = bDoEnable
+ .txtStartDate.Enabled = bDoEnable
+ .txtEndDate.Enabled = bDoEnable
+ .hlnInterval.Enabled = bDoEnable
+ .optDaily.Enabled = bDoEnable
+ .optWeekly.Enabled = bDoEnable
+ End Select
+ End With
+End Sub
+
+
+Sub InitializeStockRatesControls(CurStep as Integer)
+ DlgReference = DlgStockRates
+ DlgStockRates.Title = StockRatesTitle(CurStep)
+ With StockRatesModel
+ .txtStockID.Text = &quot;&quot;
+ .lblStockID.Label = sCurStockIDLabel
+ Select Case CurStep
+ Case 1
+ .txtDividend.Value = 0
+ .optPerShare.State = 1
+ .txtDividend.CurrencySymbol = sCurCurrency
+ Case 2
+ .txtOldRate.Value = 1
+ .txtNewRate.Value = 1
+ .txtDate.Date = CDateToUNODate(Date())
+ Case 3
+ .txtStartDate.DateMax = CDateToUNODate(CDate(Date())-1)
+ .txtEndDate.DateMax = CDateToUNODate(CDate(Date())-1)
+ .txtStartDate.Date = CDateToUNODate(CDate(Date())-8)
+ .txtEndDate.Date = CDateToUNODate(CDate(Date())-1)
+ .optDaily.State = 1
+ End Select
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Dialog2.xdl b/wizards/source/depot/Dialog2.xdl
new file mode 100644
index 000000000..94851c3e4
--- /dev/null
+++ b/wizards/source/depot/Dialog2.xdl
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="Dialog2" dlg:tab-index="0" dlg:left="91" dlg:top="24" dlg:width="220" dlg:height="128" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_DIALOG_SELLBUY" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblStockNames" dlg:tab-index="0" dlg:left="6" dlg:top="6" dlg:width="102" dlg:height="8" dlg:value="lblStockNames"/>
+ <dlg:menulist dlg:id="lstSellStocks" dlg:tab-index="1" dlg:left="6" dlg:top="17" dlg:width="102" dlg:height="12" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_1_LSTSELLSTOCKS" dlg:spin="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Depot.Depot.SelectStockname?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:combobox dlg:id="lstBuyStocks" dlg:tab-index="2" dlg:left="6" dlg:top="17" dlg:width="102" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_2_LSTBUYSTOCKS" dlg:spin="true">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:Depot.Depot.SelectStockname?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:combobox>
+ <dlg:text dlg:id="lblStockID" dlg:tab-index="3" dlg:left="150" dlg:top="6" dlg:width="66" dlg:height="8" dlg:value="lblStockID"/>
+ <dlg:textfield dlg:id="txtStockID" dlg:tab-index="4" dlg:left="150" dlg:top="17" dlg:width="40" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTSTOCKID_SELLBUY"/>
+ <dlg:text dlg:id="lblQuantity" dlg:tab-index="5" dlg:left="6" dlg:top="36" dlg:width="57" dlg:height="8" dlg:value="lblQuantity"/>
+ <dlg:numericfield dlg:id="txtQuantity" dlg:tab-index="6" dlg:left="6" dlg:top="47" dlg:width="46" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTQUANTITY" dlg:decimal-accuracy="0" dlg:value-min="1"/>
+ <dlg:currencyfield dlg:id="txtRate" dlg:tab-index="7" dlg:left="68" dlg:top="47" dlg:width="40" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTRATE" dlg:value-min="0"/>
+ <dlg:datefield dlg:id="txtDate" dlg:tab-index="8" dlg:left="150" dlg:top="47" dlg:width="50" dlg:height="12" dlg:tag="Dialog2" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTDATE" dlg:strict-format="true" dlg:spin="true">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:Depot.tools.CheckInputDate?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:datefield>
+ <dlg:text dlg:id="lblRate" dlg:tab-index="9" dlg:left="68" dlg:top="36" dlg:width="77" dlg:height="8" dlg:value="lblRate"/>
+ <dlg:text dlg:id="lblDate" dlg:tab-index="10" dlg:left="150" dlg:top="37" dlg:width="66" dlg:height="8" dlg:value="lblDate"/>
+ <dlg:formattedfield dlg:id="txtCommission" dlg:tab-index="11" dlg:left="6" dlg:top="90" dlg:width="40" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTCOMMISSION" dlg:format-code="0,00%" dlg:format-locale="de;DE"/>
+ <dlg:text dlg:id="lblCommission" dlg:tab-index="12" dlg:left="6" dlg:top="79" dlg:width="60" dlg:height="8" dlg:value="lblCommission"/>
+ <dlg:currencyfield dlg:id="txtFix" dlg:tab-index="13" dlg:left="68" dlg:top="90" dlg:width="40" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTFIX" dlg:value-min="0"/>
+ <dlg:currencyfield dlg:id="txtMinimum" dlg:tab-index="14" dlg:left="150" dlg:top="90" dlg:width="40" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTMINIMUM" dlg:value-min="0"/>
+ <dlg:text dlg:id="lblFix" dlg:tab-index="15" dlg:left="68" dlg:top="79" dlg:width="71" dlg:height="8" dlg:value="lblFix"/>
+ <dlg:text dlg:id="lblMinimum" dlg:tab-index="16" dlg:left="150" dlg:top="79" dlg:width="66" dlg:height="8" dlg:value="lblMinimum"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="17" dlg:left="58" dlg:top="109" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_CMDCANCEL_SELLBUY" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Depot.Depot.CancelTransaction?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="18" dlg:left="111" dlg:top="109" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_CMDGOON_SELLBUY" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Depot.Depot.TransactionOk?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:fixedline dlg:id="hlnCommission" dlg:tab-index="19" dlg:left="6" dlg:top="66" dlg:width="210" dlg:height="8" dlg:value="hlnCommission"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/depot/Dialog3.xdl b/wizards/source/depot/Dialog3.xdl
new file mode 100644
index 000000000..3b8904700
--- /dev/null
+++ b/wizards/source/depot/Dialog3.xdl
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="Dialog3" dlg:left="161" dlg:top="81" dlg:width="176" dlg:height="119" dlg:page="3" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_DIALOG_SPLIT" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblStockNames" dlg:tab-index="0" dlg:left="6" dlg:top="6" dlg:width="98" dlg:height="8" dlg:value="lblStockNames"/>
+ <dlg:menulist dlg:id="lstStockNames" dlg:tab-index="1" dlg:left="5" dlg:top="17" dlg:width="102" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_LSTSTOCKNAMES" dlg:spin="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Depot.Depot.SelectStockNameForRates?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:textfield dlg:id="txtStockID" dlg:tab-index="2" dlg:left="120" dlg:top="17" dlg:width="50" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_TXTSTOCKID_SPLIT"/>
+ <dlg:datefield dlg:id="txtStartDate" dlg:tab-index="3" dlg:left="63" dlg:top="37" dlg:width="50" dlg:height="12" dlg:page="3" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_3_TXTSTARTDATE" dlg:spin="true">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:Depot.tools.CheckInputDate?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:datefield>
+ <dlg:datefield dlg:id="txtEndDate" dlg:tab-index="4" dlg:left="63" dlg:top="53" dlg:width="50" dlg:height="12" dlg:page="3" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_3_TXTENDDATE" dlg:spin="true">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:Depot.tools.CheckInputDate?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:datefield>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optDaily" dlg:tab-index="5" dlg:left="12" dlg:top="83" dlg:width="75" dlg:height="10" dlg:page="3" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_3_OPTDAILY" dlg:value="optDaily"/>
+ <dlg:radio dlg:id="optWeekly" dlg:tab-index="6" dlg:left="101" dlg:top="83" dlg:width="69" dlg:height="10" dlg:page="3" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_3_OPTWEEKLY" dlg:value="optWeekly"/>
+ </dlg:radiogroup>
+ <dlg:datefield dlg:id="txtDate" dlg:tab-index="7" dlg:left="71" dlg:top="73" dlg:width="50" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_2_TXTDATE" dlg:spin="true">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:Depot.tools.CheckInputDate?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:datefield>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optPerShare" dlg:tab-index="8" dlg:left="6" dlg:top="37" dlg:width="69" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_1_OPTPERSHARE" dlg:value="optPerShare"/>
+ <dlg:radio dlg:id="optTotal" dlg:tab-index="9" dlg:left="6" dlg:top="51" dlg:width="69" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_1_OPTTOTAL" dlg:value="optTotal"/>
+ </dlg:radiogroup>
+ <dlg:currencyfield dlg:id="txtDividend" dlg:tab-index="10" dlg:left="6" dlg:top="80" dlg:width="50" dlg:height="12" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_1_TXTDIVIDEND" dlg:value-min="0" dlg:spin="true"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="11" dlg:left="41" dlg:top="98" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_CMDCANCEL_SPLIT" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Depot.Depot.CancelStockRate?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="12" dlg:left="94" dlg:top="98" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_CMDGOON_SPLIT" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Depot.Depot.CommitStockRate?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="lblStockID" dlg:tab-index="13" dlg:left="120" dlg:top="6" dlg:width="50" dlg:height="8" dlg:value="lblStockID"/>
+ <dlg:text dlg:id="lblDividend" dlg:tab-index="14" dlg:left="6" dlg:top="68" dlg:width="73" dlg:height="8" dlg:page="1" dlg:value="lblDividend"/>
+ <dlg:text dlg:id="lblExchangeRate" dlg:tab-index="15" dlg:left="6" dlg:top="39" dlg:width="92" dlg:height="8" dlg:page="2" dlg:value="lblExchangeRate"/>
+ <dlg:text dlg:id="lblColon" dlg:tab-index="16" dlg:left="40" dlg:top="55" dlg:width="5" dlg:height="8" dlg:page="2" dlg:value=" :"/>
+ <dlg:text dlg:id="lblDate" dlg:tab-index="17" dlg:left="5" dlg:top="75" dlg:width="66" dlg:height="8" dlg:page="2" dlg:value="lblDate"/>
+ <dlg:fixedline dlg:id="hlnInterval" dlg:tab-index="18" dlg:left="6" dlg:top="72" dlg:width="164" dlg:height="8" dlg:page="3" dlg:value="hlnInterval"/>
+ <dlg:text dlg:id="lblStartDate" dlg:tab-index="19" dlg:left="6" dlg:top="39" dlg:width="53" dlg:height="8" dlg:page="3" dlg:value="lblStartDate"/>
+ <dlg:text dlg:id="lblEndDate" dlg:tab-index="20" dlg:left="6" dlg:top="55" dlg:width="53" dlg:height="8" dlg:page="3" dlg:value="lblEndDate"/>
+ <dlg:numericfield dlg:id="txtOldRate" dlg:tab-index="21" dlg:left="6" dlg:top="53" dlg:width="30" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_2_TXTOLDRATE" dlg:decimal-accuracy="0" dlg:value-min="1" dlg:spin="true"/>
+ <dlg:numericfield dlg:id="txtNewRate" dlg:tab-index="22" dlg:left="50" dlg:top="53" dlg:width="30" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_2_TXTNEWRATE" dlg:decimal-accuracy="0" dlg:value-min="1" dlg:spin="true"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/depot/Dialog4.xdl b/wizards/source/depot/Dialog4.xdl
new file mode 100644
index 000000000..057eb9d17
--- /dev/null
+++ b/wizards/source/depot/Dialog4.xdl
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="Dialog4" dlg:left="161" dlg:top="81" dlg:width="160" dlg:height="120" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_DIALOG_HISTORY" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblWelcome" dlg:tab-index="0" dlg:left="6" dlg:top="6" dlg:width="148" dlg:height="49" dlg:value="lblWelcome" dlg:multiline="true"/>
+ <dlg:text dlg:id="lblHint" dlg:tab-index="1" dlg:left="6" dlg:top="73" dlg:width="148" dlg:height="26" dlg:value="lblHint" dlg:multiline="true"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="2" dlg:left="28" dlg:top="100" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_CMDCANCEL_HISTORY" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Depot.Currency.CloseStartUpDialog?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="3" dlg:left="84" dlg:top="100" dlg:width="52" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_0_CMDGOON_HISTORY" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Depot.Currency.ChooseMarket?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:menulist dlg:id="lstMarkets" dlg:tab-index="4" dlg:left="6" dlg:top="57" dlg:width="148" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGDEPOT_LSTMARKETS" dlg:spin="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Depot.Currency.EnableGoOnButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/depot/Internet.xba b/wizards/source/depot/Internet.xba
new file mode 100644
index 000000000..d3393bc72
--- /dev/null
+++ b/wizards/source/depot/Internet.xba
@@ -0,0 +1,356 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Internet" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+Public sNewSheetName as String
+
+Function CheckHistoryControls()
+Dim bLocGoOn as Boolean
+Dim Firstdate as Date
+Dim LastDate as Date
+ LastDate = CDateFromUNODate(StockRatesModel.txtEndDate.Date)
+ FirstDate = CDateFromUNODate(StockRatesModel.txtStartDate.Date)
+ bLocGoOn = FirstDate &lt;&gt; 0 And LastDate &lt;&gt; 0
+ If bLocGoOn Then
+ If FirstDate &gt;= LastDate Then
+ Msgbox(sMsgStartDatebeforeEndDate,16, sProductname)
+ bLocGoOn = False
+ End If
+ End If
+ CheckHistoryControls = bLocGoon
+End Function
+
+
+Sub InsertCompanyHistory()
+Dim StockName as String
+Dim CurRow as Integer
+Dim sMsgInternetError as String
+Dim CurRate as Double
+Dim oCell as Object
+Dim sStockID as String
+Dim ChartSource as String
+ If CheckHistoryControls() Then
+ StartDate = CDateFromUNODate(StockRatesModel.txtStartDate.Date)
+ EndDate = CDateFromUNODate(StockRatesModel.txtEndDate.Date)
+ DlgStockRates.EndExecute()
+ If StockRatesModel.optDaily.State = 1 Then
+ sInterval = &quot;d&quot;
+ iStep = 1
+ ElseIf StockRatesModel.optWeekly.State = 1 Then
+ sInterval = &quot;w&quot;
+ iStep = 7
+ StartDate = StartDate - WeekDay(StartDate) + 2
+ EndDate = EndDate - WeekDay(EndDate) + 2
+ End If
+ iEndDay = Day(EndDate)
+ iEndMonth = Month(EndDate)
+ iEndYear = Year(EndDate)
+ iStartDay = Day(StartDate)
+ iStartMonth = Month(StartDate)
+ iStartYear = Year(StartDate)
+&apos; oDocument.AddActionLock()
+ UnprotectSheets(oSheets)
+ InitializeStatusline(&quot;&quot;, 10, 1)
+ oBackGroundSheet = oSheets.GetbyName(&quot;Background&quot;)
+ StockName = DlgStockRates.GetControl(&quot;lstStockNames&quot;).GetSelectedItem()
+ CurRow = GetStockRowIndex(Stockname)
+ sStockID = oFirstSheet.GetCellByPosition(SBCOLUMNID1, CurRow).String
+ ChartSource = ReplaceString(HistoryChartSource, sStockID, &quot;&lt;StockID&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, iStartDay, &quot;&lt;StartDay&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, cStr(iStartMonth-1), &quot;&lt;StartMonth&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, iStartYear, &quot;&lt;StartYear&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, iEndDay, &quot;&lt;EndDay&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, cStr(iEndMonth-1), &quot;&lt;EndMonth&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, iEndYear, &quot;&lt;EndYear&gt;&quot;)
+ ChartSource = ReplaceString(ChartSource, sInterval, &quot;&lt;interval&gt;&quot;)
+ oStatusLine.SetValue(2)
+ If GetCurrentRate(ChartSource, CurRate, 1) Then
+ oStatusLine.SetValue(8)
+ UpdateValue(StockName, Today, CurRate)
+ oStatusLine.SetValue(9)
+ UpdateChart(StockName)
+ oStatusLine.SetValue(10)
+ Else
+ sMsgInternetError = Stockname &amp; &quot;: &quot; &amp; sNoInternetDataAvailable &amp; chr(13) &amp; sCheckInternetSettings
+ Msgbox(sMsgInternetError, 16, sProductname)
+ End If
+ ProtectSheets(oSheets)
+ oStatusLine.End
+ If oSheets.HasbyName(sNewSheetName) Then
+ oController.ActiveSheet = oSheets.GetByName(sNewSheetName)
+ End If
+&apos; oDocument.RemoveActionLock()
+ End If
+End Sub
+
+
+
+Sub InternetUpdate()
+Dim i as Integer
+Dim StocksCount as Integer
+Dim iStartRow as Integer
+Dim sUrl as String
+Dim StockName as String
+Dim CurRate as Double
+Dim oCell as Object
+Dim sMsgInternetError as String
+Dim sStockID as String
+Dim ChartSource as String
+&apos; oDocument.AddActionLock()
+ Initialize(True)
+ UnprotectSheets(oSheets)
+ StocksCount = GetStocksCount(iStartRow)
+ InitializeStatusline(&quot;&quot;, StocksCount + 1, 1)
+ Today = CDate(Date)
+ For i = iStartRow + 1 To iStartRow + StocksCount
+ StockName = oFirstSheet.GetCellbyPosition(SBCOLUMNNAME1, i).String
+ sStockID = oFirstSheet.GetCellByPosition(SBCOLUMNID1, i).String
+ ChartSource = ReplaceString(sCurChartSource, sStockID, &quot;&lt;StockID&gt;&quot;)
+ If GetCurrentRate(ChartSource, CurRate, 0) Then
+ InsertCurrentValue(CurRate, i, Now)
+ Else
+ sMsgInternetError = Stockname &amp; &quot;: &quot; &amp; sNoInternetDataAvailable &amp; chr(13) &amp; sCheckInternetSettings
+ Msgbox(sMsgInternetError, 16, sProductname)
+ End If
+ oStatusline.SetValue(i - iStartRow + 1)
+ Next
+ ProtectSheets(oSheets)
+ oStatusLine.End
+&apos; oDocument.RemoveActionLock
+End Sub
+
+
+
+Function GetCurrentRate(sUrl as String, fValue As Double, iValueRow as Integer) as Boolean
+Dim sFilter As String
+Dim sOptions As String
+Dim oLinkSheet As Object
+Dim sDate as String
+ If oSheets.hasByName(&quot;Link&quot;) Then
+ oLinkSheet = oSheets.getByName(&quot;Link&quot;)
+ Else
+ oLinkSheet = oDocument.createInstance(&quot;com.sun.star.sheet.Spreadsheet&quot;)
+ oSheets.insertByName(&quot;Link&quot;, oLinkSheet)
+ oLinkSheet.IsVisible = False
+ End If
+
+ sFilter = &quot;Text - txt - csv (StarCalc)&quot;
+ sOptions = sCurSeparator &amp; &quot;,34,SYSTEM,1,1/10/2/10/3/10/4/10/5/10/6/10/7/10/8/10/9/10&quot;
+
+ oLinkSheet.LinkMode = com.sun.star.sheet.SheetLinkMode.NONE
+ oLinkSheet.link(sUrl, &quot;&quot;, sFilter, sOptions, 1 )
+ fValue = oLinkSheet.getCellByPosition(iValueCol, iValueRow).Value
+ If fValue = 0 Then
+ Dim sValue as String
+ sValue = oLinkSheet.getCellByPosition(1, iValueRow).String
+ sValue = ReplaceString(sValue, &quot;.&quot;,&quot;,&quot;)
+ fValue = Val(sValue)
+ End If
+ GetCurrentRate = fValue &lt;&gt; 0
+End Function
+
+
+
+Sub UpdateValue(ByVal sName As String, fDate As Double, fValue As Double )
+Dim oSheet As Object
+Dim iColumn As Long
+Dim iRow As Long
+Dim i as Long
+Dim oCell As Object
+Dim LastDate as Date
+Dim bLeaveLoop as Boolean
+Dim RemoveCount as Long
+Dim iLastRow as Long
+Dim iLastLinkRow as Long
+Dim dDate as Date
+Dim CurDate as Date
+Dim oLinkSheet as Object
+Dim StartIndex as Long
+Dim iCellValue as Long
+ &apos; Insert Sheet with Company - Chart
+ sName = CheckNewSheetname(oSheets, sName)
+ If NOT oSheets.hasByName(sName) Then
+ oSheets.CopybyName(&quot;Background&quot;, sName, oSheets.Count)
+ oSheet = oSheets.getByName(sName)
+ iCurRow = SBSTARTROW
+ iMaxRow = iCurRow
+ oCell = oSheet.getCellByPosition(SBDATECOLUMN, iCurRow)
+ oCell.Value = fDate
+ End If
+ sNewSheetName = sName
+ oLinkSheet = oSheets.GetByName(&quot;Link&quot;)
+ oSheet = oSheets.getByName(sName)
+ iLastRow = GetLastUsedRow(oSheet)- 2
+ iLastLinkRow = GetLastUsedRow(oLinkSheet)
+ iCurRow = iLastRow
+ bLeaveLoop = False
+ RemoveCount = 0
+ &apos; Delete all Cells in Date Area
+ Do
+ oCell = oSheet.GetCellbyPosition(SBDATECOLUMN,iCurRow)
+ If oCell.CellStyle = sColumnHeader Then
+ bLeaveLoop = True
+ StartIndex = iCurRow
+ iCurRow = iCurRow + 1
+ Else
+ RemoveCount = RemoveCount + 1
+ iCurRow = iCurRow - 1
+ End If
+ Loop Until bLeaveLoop
+ If RemoveCount &gt; 1 Then
+ oSheet.Rows.RemoveByIndex(iCurRow, RemoveCount-1)
+ End If
+ For i = 1 To iLastLinkRow
+ oCell = oSheet.GetCellbyPosition(SBDATECOLUMN,iCurRow)
+ iCellValue = oLinkSheet.GetCellByPosition(0,i).Value
+ If iCellValue &gt; 0 Then
+ oCell.SetValue(oLinkSheet.GetCellByPosition(0,i).Value)
+ Else
+ oCell.SetValue(StringToDate(oLinkSheet.GetCellByPosition(0,i).String))
+ End If
+ oCell = oSheet.GetCellbyPosition(SBVALUECOLUMN,iCurRow)
+ oCell.SetValue(oLinkSheet.GetCellByPosition(4,i).Value)
+ If i &lt; iLastLinkRow Then
+ iCurRow = iCurRow + 1
+ oSheet.Rows.InsertByIndex(iCurRow,1)
+ End If
+ Next i
+ iMaxRow = iCurRow
+End Sub
+
+
+Function StringToDate(DateString as String) as Date
+Dim ShortMonths(11)
+Dim DateList() as String
+Dim MaxIndex as Integer
+Dim i as Integer
+ ShortMonths(0) = &quot;Jan&quot;
+ ShortMonths(1) = &quot;Feb&quot;
+ ShortMonths(2) = &quot;Mar&quot;
+ ShortMonths(3) = &quot;Apr&quot;
+ ShortMonths(4) = &quot;May&quot;
+ ShortMonths(5) = &quot;Jun&quot;
+ ShortMonths(6) = &quot;Jul&quot;
+ ShortMonths(7) = &quot;Aug&quot;
+ ShortMonths(8) = &quot;Sep&quot;
+ ShortMonths(9) = &quot;Oct&quot;
+ ShortMonths(10) = &quot;Nov&quot;
+ ShortMonths(11) = &quot;Dec&quot;
+ For i = 0 To 11
+ DateString = ReplaceString(DateString,CStr(i+1),ShortMonths(i))
+ Next i
+ DateString = ReplaceString(DateString, &quot;.&quot;, &quot;-&quot;)
+ StringToDate = CDate(DateString)
+End Function
+
+
+Sub UpdateChart(sName As String)
+Dim oSheet As Object
+Dim oCell As Object, oCursor As Object
+Dim oChartRange As Object
+Dim oEmbeddedChart As Object, oCharts As Object
+Dim oChart As Object, oDiagram As Object
+Dim oYAxis As Object, oXAxis As Object
+Dim fMin As Double, fMax As Double
+Dim nDateFormat As Long
+Dim aPos As Variant
+Dim aSize As Variant
+Dim oContainerChart as Object
+Dim mRangeAddresses(0) as New com.sun.star.table.CellRangeAddress
+ mRangeAddresses(0).Sheet = GetSheetIndex(oSheets, sNewSheetName)
+ mRangeAddresses(0).StartColumn = SBDATECOLUMN
+ mRangeAddresses(0).StartRow = SBSTARTROW-1
+ mRangeAddresses(0).EndColumn = SBVALUECOLUMN
+ mRangeAddresses(0).EndRow = iMaxRow
+
+ oSheet = oDocument.Sheets.getByName(sNewSheetName)
+ oCharts = oSheet.Charts
+
+ If Not oCharts.hasElements Then
+ oSheet.GetCellbyPosition(2,2).SetString(sName)
+ oChartRange = oSheet.getCellRangeByPosition(SBDATECOLUMN,6,5,SBSTARTROW-3)
+ aPos = oChartRange.Position
+ aSize = oChartRange.Size
+
+ Dim oRectangleShape As New com.sun.star.awt.Rectangle
+ oRectangleShape.X = aPos.X
+ oRectangleShape.Y = aPos.Y
+ oRectangleShape.Width = aSize.Width
+ oRectangleShape.Height = aSize.Height
+ oCharts.addNewByName(sName, oRectangleShape, mRangeAddresses(), True, False)
+ oContainerChart = oCharts.getByName(sName)
+ oChart = oContainerChart.EmbeddedObject
+ oChart.Title.String = &quot;&quot;
+ oChart.HasLegend = False
+ oChart.diagram = oChart.createInstance(&quot;com.sun.star.chart.XYDiagram&quot;)
+ oDiagram = oChart.Diagram
+ oDiagram.DataRowSource = com.sun.star.chart.ChartDataRowSource.COLUMNS
+ oChart.Area.LineStyle = com.sun.star.drawing.LineStyle.SOLID
+ oXAxis = oDiagram.XAxis
+ oXAxis.TextBreak = False
+ nDateFormat = oXAxis.NumberFormats.getStandardFormat(com.sun.star.util.NumberFormat.DATE, oDocLocale)
+
+ oYAxis = oDiagram.getYAxis()
+ oYAxis.AutoOrigin = True
+ Else
+ oChart = oCharts(0)
+ oChart.Ranges = mRangeAddresses()
+ oChart.HasRowHeaders = False
+ oEmbeddedChart = oChart.EmbeddedObject
+ oDiagram = oEmbeddedChart.Diagram
+ oXAxis = oDiagram.XAxis
+ End If
+ oXAxis.AutoStepMain = False
+ oXAxis.AutoStepHelp = False
+ oXAxis.StepMain = iStep
+ oXAxis.StepHelp = iStep
+ fMin = oSheet.getCellByPosition(SBDATECOLUMN,SBSTARTROW).Value
+ fMax = oSheet.getCellByPosition(SBDATECOLUMN,iMaxRow).Value
+ oXAxis.Min = fMin
+ oXAxis.Max = fMax
+ oXAxis.AutoMin = False
+ oXAxis.AutoMax = False
+End Sub
+
+
+Sub CalculateChartafterSplit(SheetName, NewNumber, OldNumber, NoteText, SplitDate)
+Dim oSheet as Object
+Dim i as Integer
+Dim oValueCell as Object
+Dim oDateCell as Object
+Dim bLeaveLoop as Boolean
+ If oSheets.HasbyName(SheetName) Then
+ oSheet = oSheets.GetbyName(SheetName)
+ i = 0
+ bLeaveLoop = False
+ Do
+ oValueCell = oSheet.GetCellbyPosition(SBVALUECOLUMN, SBSTARTROW + i)
+ If oValueCell.CellStyle = CurrCellStyle Then
+ SplitCellValue(oSheet, OldNumber, NewNumber, SBVALUECOLUMN, SBSTARTROW + i, &quot;&quot;)
+ i = i + 1
+ Else
+ bLeaveLoop = True
+ End If
+ Loop Until bLeaveLoop
+ oDateCell = oSheet.GetCellbyPosition(SBDATECOLUMN, SBSTARTROW + i-1)
+ oDateCell.Annotation.SetString(NoteText)
+ End If
+End Sub
+</script:module>
diff --git a/wizards/source/depot/Lang_de.xba b/wizards/source/depot/Lang_de.xba
new file mode 100644
index 000000000..a8b4c55ca
--- /dev/null
+++ b/wizards/source/depot/Lang_de.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_de" script:language="StarBasic">Option Explicit
+
+Sub LoadGermanLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~OK&quot;
+ sCancel = &quot;Abbrechen&quot;
+ sColumnHeader = &quot;Spaltenkopf&quot;
+ sInsertStockName = &quot;Bitte fügen Sie zunächst einige Aktien in Ihr Depot ein!&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: Aktienverwaltung&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;Eingabefehler&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;Bitte geben Sie eine Stückzahl größer als 0 ein&quot;
+ sMsgNoDividend = &quot;Bitte geben Sie eine Dividende je Stück oder eine Gesamtdividende ein&quot;
+ sMsgNoExchangeRate = &quot;Bitte geben Sie eine korrekte Umtauschrate ein (alte Aktien -&gt; neue Aktien).&quot;
+ sMsgNoValidExchangeDate = &quot;Bitte geben Sie ein gültiges Datum für den Aktiensplitt ein.&quot;
+ sMsgWrongExchangeDate = &quot;Splitt nicht möglich, da bereits Transaktionen nach dem Splitt-Datum existieren.&quot;
+ sMsgSellTooMuch = &quot;So viele Aktien können Sie nicht verkaufen. Maximum: &quot;
+ sMsgConfirm = &quot;Bestätigung erforderlich&quot;
+ sMsgFreeStock = &quot;Beabsichtigen Sie die Eingabe von Gratisaktien?&quot;
+ sMsgTotalLoss = &quot;Beabsichtigen Sie die Eingabe eines Totalverlustes?&quot;
+ sMsgAuthorization = &quot;Sicherheitsabfrage&quot;
+ sMsgDeleteAll = &quot;Wollen Sie alle Bewegungen löschen und die Depotübersicht rücksetzen?&quot;
+ cSplit = &quot;Aktiensplitt am &quot;
+ sHistory = &quot;Historie&quot;
+ TransactTitle(1) = &quot;Aktien verkaufen&quot;
+ TransactTitle(2) = &quot;Aktien kaufen&quot;
+ StockRatesTitle(1) = &quot;Dividendenzahlung&quot;
+ StockRatesTitle(2) = &quot;Aktiensplitt&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;Depotwährung&quot;
+ sStockName = &quot;Aktienname&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;Ergebnis Datum&quot;
+ CurrCellStyle = &quot;Ergebnis Euro mit Dezimalen&quot;
+ sStartDate = &quot;Startdatum:&quot;
+ sEndDate = &quot;Enddatum:&quot;
+ sStartUpWelcome = &quot;Diese Vorlage ermöglicht Ihnen eine effiziente Verwaltung Ihres Aktiendepots&quot;
+ sStartUpChooseMarket = &quot;Wählen Sie zunächst Ihre Referenz-Währung und damit den Börsenplatz für das Internet Update aus!&quot;
+ sStartUpHint = &quot;Leider steht Ihnen die &lt;History&gt;- Funktion nur für den amerikanischen Markt zur Verfügung!&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;ohne Internet Update&quot;
+ sMarketPlace = &quot;Börsenplatz:&quot;
+ sNoInternetDataAvailable = &quot;Internet-Kurse konnten nicht empfangen werden!&quot;
+ sCheckInternetSettings = &quot;Mögliche Ursachen sind: &lt;BR&gt; Ihre Internet Einstellungen müssen überprüft werden.&lt;BR&gt; Sie haben eine falsche Kennung (z.B. Symbol, WKN) für die Aktie eingegeben.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;Das Enddatum muss vor dem heutigen Tag liegen!&quot;
+ sMsgStartDatebeforeEndDate = &quot;Das Startdatum muss vor dem Enddatum liegen!&quot;
+
+ sMarket(0,0) = &quot;Amerikanischer Dollar&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;New York&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;Symbol&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;Euro&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;Frankfurt&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;WKN&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;Englisches Pfund&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;London&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;Symbol&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;Japanischer Yen&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;Tokyo&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;Code&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;Hongkong Dollar&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;Hongkong&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.HK&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;Nummer&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;Australischer Dollar&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;Sydney&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;Symbol&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;Menge&quot;
+ .lblRate.Label = &quot;Kurs&quot;
+ .lblDate.Label = &quot;Transaktionsdatum&quot;
+ .hlnCommission.Label = &quot;Sonstige Ausgaben&quot;
+ .lblCommission.Label = &quot;Provision&quot;
+ .lblMinimum.Label = &quot;Mindestprovision&quot;
+ .lblFix.Label = &quot;Festbetrag/Spesen&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;Dividende/Aktie&quot;
+ .optTotal.Label = &quot;Dividende gesamt&quot;
+ .lblDividend.Label = &quot;Betrag&quot;
+ .lblExchangeRate.Label = &quot;Umtauschrate (alt-&gt;neu)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;Umtauschdatum:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~Täglich&quot;
+ .optWeekly.Label = &quot;~Wöchentlich&quot;
+ .hlnInterval.Label = &quot;Zeitraum&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_en.xba b/wizards/source/depot/Lang_en.xba
new file mode 100644
index 000000000..b97efb156
--- /dev/null
+++ b/wizards/source/depot/Lang_en.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_en" script:language="StarBasic">Option Explicit
+
+Sub LoadEnglishLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~OK&quot;
+ sCancel = &quot;Cancel&quot;
+ sColumnHeader = &quot;Column Header&quot;
+ sInsertStockName = &quot;Please enter shares in your portfolio.&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: Stocks Manager&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;Input Error&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;Please enter a quantity larger than 0&quot;
+ sMsgNoDividend = &quot;Please enter the dividend per share or the total dividend&quot;
+ sMsgNoExchangeRate = &quot;Please enter the correct exchange rate (old shares -&gt; new shares)&quot;
+ sMsgNoValidExchangeDate = &quot;Please enter a valid date for the split.&quot;
+ sMsgWrongExchangeDate = &quot;Splitting not possible, as transactions already exist after the split date.&quot;
+ sMsgSellTooMuch = &quot;You cannot sell that many shares. Maximum: &quot;
+ sMsgConfirm = &quot;Confirmation Required&quot;
+ sMsgFreeStock = &quot;Do you intend to enter free shares?&quot;
+ sMsgTotalLoss = &quot;Do you intend to enter a total loss?&quot;
+ sMsgAuthorization = &quot;Security Query&quot;
+ sMsgDeleteAll = &quot;Do you want to delete all movements and reset the portfolio overview?&quot;
+ cSplit = &quot;Stock split on &quot;
+ sHistory = &quot;History&quot;
+ TransactTitle(1) = &quot;StarOffice Stocks Manager: Selling Shares&quot;
+ TransactTitle(2) = &quot;StarOffice Stocks Manager: Buying Shares&quot;
+ StockRatesTitle(1) = &quot;StarOffice Stocks Manager: Dividend Payment&quot;
+ StockRatesTitle(2) = &quot;Stock Split&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;Portfolio Currency&quot;
+ sStockName = &quot;Name of Stock&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;Result Date&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;Start date:&quot;
+ sEndDate = &quot;End date:&quot;
+ sStartUpWelcome = &quot;This template enables you to manage your stock portfolio efficiently.&quot;
+ sStartUpChooseMarket = &quot;First, select your reference currency and thus the stock exchange for the Internet update.&quot;
+ sStartUpHint = &quot;Unfortunately, the only &lt;History&gt; function available to you is that for the American market.&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;without Internet update&quot;
+ sMarketPlace = &quot;Stock exchange:&quot;
+ sNoInternetDataAvailable = &quot;No prices could be received from the Internet!&quot;
+ sCheckInternetSettings = &quot;Possible causes could be: &lt;BR&gt;Your Internet settings have to be modified. &lt;BR&gt;The Symbol (e.g. Code, Ticker Symbol) entered for the stock was incorrect.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;The end date has to be before today&apos;s date.&quot;
+ sMsgStartDatebeforeEndDate = &quot;The start date has to be before the end date.&quot;
+
+ sMarket(0,0) = &quot;American Dollar&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;New York&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;Symbol&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;Euro&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;Frankfurt&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;Ticker Symbol&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;British Pound&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;London&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;Symbol&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;Japanese Yen&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;Tokyo&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;Code&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;Hong Kong Dollar&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;Hong Kong&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;Number&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;Australian Dollar&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;Sydney&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;Symbol&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;Quantity&quot;
+ .lblRate.Label = &quot;Price&quot;
+ .lblDate.Label = &quot;Transaction Date&quot;
+ .hlnCommission.Label = &quot;Other expenditures&quot;
+ .lblCommission.Label = &quot;Commission&quot;
+ .lblMinimum.Label = &quot;Min. Commission&quot;
+ .lblFix.Label = &quot;Fixed Costs/Charges&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;Dividends/Stocks&quot;
+ .optTotal.Label = &quot;Total Dividends&quot;
+ .lblDividend.Label = &quot;Amount&quot;
+ .lblExchangeRate.Label = &quot;Exchange Rate (old-&gt;new)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;Exchange Date:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~Daily&quot;
+ .optWeekly.Label = &quot;~Weekly&quot;
+ .hlnInterval.Label = &quot;Time period&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_es.xba b/wizards/source/depot/Lang_es.xba
new file mode 100644
index 000000000..b6bf01c43
--- /dev/null
+++ b/wizards/source/depot/Lang_es.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_es" script:language="StarBasic">Option Explicit
+
+Sub LoadSpanishLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~Aceptar&quot;
+ sCancel = &quot;Cancelar&quot;
+ sColumnHeader = &quot;Título de columna&quot;
+ sInsertStockName = &quot;Introduzca primero algunas acciones en su depósito.&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: Administración de acciones&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;Error de entrada&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;Indique una cantidad mayor que 0&quot;
+ sMsgNoDividend = &quot;Indique un dividendo por unidad o un dividendo total&quot;
+ sMsgNoExchangeRate = &quot;Indique aquí un cambio correcto (acción vieja -&gt; nueva acción)&quot;
+ sMsgNoValidExchangeDate = &quot;Indique una fecha correcta para el fraccionamiento de la acción.&quot;
+ sMsgWrongExchangeDate = &quot;El fraccionamiento no es posible porque existen transacciones después de la fecha de fraccionamiento.&quot;
+ sMsgSellTooMuch = &quot;No puede vender tantas acciones. Como máximo: &quot;
+ sMsgConfirm = &quot;Confirmación necesaria&quot;
+ sMsgFreeStock = &quot;¿Tiene previsto considerar acciones gratis?&quot;
+ sMsgTotalLoss = &quot;¿Tiene previsto introducir una pérdida total?&quot;
+ sMsgAuthorization = &quot;Pregunta de seguridad&quot;
+ sMsgDeleteAll = &quot;¿Desea borrar todos los movimientos y reiniciar el balance de depósito?&quot;
+ cSplit = &quot;Fraccionamiento el &quot;
+ sHistory = &quot;Historia&quot;
+ TransactTitle(1) = &quot;Vender acciones&quot;
+ TransactTitle(2) = &quot;Comprar acciones&quot;
+ StockRatesTitle(1) = &quot;Pago de dividendos&quot;
+ StockRatesTitle(2) = &quot;Fraccionamiento&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;Moneda del depósito&quot;
+ sStockName = &quot;Nombre de la acción&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;Resultado Fecha&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;Fecha de inicio:&quot;
+ sEndDate = &quot;Fecha final:&quot;
+ sStartUpWelcome = &quot;Esta plantilla le permite administrar eficientemente su depósito de acciones&quot;
+ sStartUpChooseMarket = &quot;Seleccione primero la moneda de referencia y la plaza bursátil para la actualización a través de Internet.&quot;
+ sStartUpHint = &quot;La función &lt;History&gt; está disponible únicamente para el mercado americano.&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;Sin actualización por Internet&quot;
+ sMarketPlace = &quot;Plaza bursátil:&quot;
+ sNoInternetDataAvailable = &quot;No se pudieron recibir las cotizaciones por Internet.&quot;
+ sCheckInternetSettings = &quot;Causas posibles: &lt;BR&gt; Debe comprobar la configuración de Internet.&lt;BR&gt; Ha indicado un código incorrecto (p.ej. número, símbolo, etc.) para la acción.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;La fecha final debe ser anterior a la fecha de hoy.&quot;
+ sMsgStartDatebeforeEndDate = &quot;La fecha inicial debe ser anterior a la fecha final.&quot;
+
+ sMarket(0,0) = &quot;Dólar estadounidense&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;Nueva York&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;Símbolo&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;Euro&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;Frankfurt&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;Código&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;Libra esterlina&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;Londres&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;Símbolo&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;Yen japonés&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;Tokio&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;Código&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;Dólar hongkonés&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;Hong Kong&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.HK&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;Número&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;Dólar australiano&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;Sidney&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;Símbolo&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;Cantidad&quot;
+ .lblRate.Label = &quot;Cotización&quot;
+ .lblDate.Label = &quot;Fecha de operación&quot;
+ .hlnCommission.Label = &quot;Otros gastos&quot;
+ .lblCommission.Label = &quot;Provisión&quot;
+ .lblMinimum.Label = &quot;Provisión mínima&quot;
+ .lblFix.Label = &quot;Cantidad fija/comisión&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;Dividendos/Acción&quot;
+ .optTotal.Label = &quot;Dividendos totales&quot;
+ .lblDividend.Label = &quot;Importe&quot;
+ .lblExchangeRate.Label = &quot;Cambio (vieja-&gt;nueva)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;Fecha de cambio:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~Diario&quot;
+ .optWeekly.Label = &quot;~Semanal&quot;
+ .hlnInterval.Label = &quot;Periodo&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_fr.xba b/wizards/source/depot/Lang_fr.xba
new file mode 100644
index 000000000..27f9a685c
--- /dev/null
+++ b/wizards/source/depot/Lang_fr.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_fr" script:language="StarBasic">Option Explicit
+
+Sub LoadFrenchLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~OK&quot;
+ sCancel = &quot;Annuler&quot;
+ sColumnHeader = &quot;En-tête de colonne&quot;
+ sInsertStockName = &quot;Saisissez quelques actions dans votre portefeuille !&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt; : Gestion d&apos;actions&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;Erreur de saisie&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;Saisissez une quantité supérieure à 0 !&quot;
+ sMsgNoDividend = &quot;Vous devez saisir le montant des dividendes perçus (soit les dividendes par action, soit la somme totale perçue).&quot;
+ sMsgNoExchangeRate = &quot;Saisissez un taux correct de conversion (anciennes actions -&gt; nouvelles actions).&quot;
+ sMsgNoValidExchangeDate = &quot;Saisissez une date correcte pour le split d&apos;action.&quot;
+ sMsgWrongExchangeDate = &quot;Split impossible car il y a déjà eu des transactions après la date du split !&quot;
+ sMsgSellTooMuch = &quot;Impossible de vendre autant d&apos;actions ! Maximum : &quot;
+ sMsgConfirm = &quot;Confirmation required&quot;
+ sMsgFreeStock = &quot;S&apos;agit-il d&apos;actions gratuites ?&quot;
+ sMsgTotalLoss = &quot;Prévoyez-vous une perte totale ?&quot;
+ sMsgAuthorization = &quot;Requête de sécurité&quot;
+ sMsgDeleteAll = &quot;Voulez-vous supprimer tous les mouvements et remettre le portefeuille d&apos;actions à zéro ?&quot;
+ cSplit = &quot;Split d&apos;action le &quot;
+ sHistory = &quot;Historique&quot;
+ TransactTitle(1) = &quot;Vente d&apos;actions&quot;
+ TransactTitle(2) = &quot;Achat d&apos;actions&quot;
+ StockRatesTitle(1) = &quot;Versement des dividendes&quot;
+ StockRatesTitle(2) = &quot;Split d&apos;action&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;Monnaie du portefeuille&quot;
+ sStockName = &quot;Nom de l&apos;action&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;Résultat date&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;Date de début :&quot;
+ sEndDate = &quot;Date de fin :&quot;
+ sStartUpWelcome = &quot;Utilisez ce modèle pour une gestion efficiente de votre portefeuille d&apos;actions !&quot;
+ sStartUpChooseMarket = &quot;Commencez par choisir une monnaie de référence et ainsi la place boursière pour la mise à jour Internet !&quot;
+ sStartUpHint = &quot;La fonction &lt;History&gt; n&apos;est cependant disponible que pour le marché américain.&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;Sans mise à jour Internet&quot;
+ sMarketPlace = &quot;Place boursière :&quot;
+ sNoInternetDataAvailable = &quot;Réception des cours Internet impossible !&quot;
+ sCheckInternetSettings = &quot;Causes possibles : &lt;BR&gt; Problème de paramétrage Internet : vérifiez les paramètres !&lt;BR&gt; Vous avez saisi un identificateur (par ex. symbole ou code) incorrect pour l&apos;action.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;La date spécifiée pour la fin doit précéder celle de ce jour !&quot;
+ sMsgStartDatebeforeEndDate = &quot;La date spécifiée pour le début doit succéder à celle de ce jour !&quot;
+
+ sMarket(0,0) = &quot;Dollar Américain&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;New York&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;Symbole&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;Euro&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;Francfort&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;Code&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;Livre Sterling&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;Londres&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;Symbole&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;Yen Japonais&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;Tokyo&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;Code&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;Dollar de Hong Kong&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;Hong Kong&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;Numéro&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;Dollar Australien&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;Sydney&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;Symbole&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;Quantité&quot;
+ .lblRate.Label = &quot;Cours&quot;
+ .lblDate.Label = &quot;Date de transaction&quot;
+ .hlnCommission.Label = &quot;Dépenses diverses&quot;
+ .lblCommission.Label = &quot;Commission&quot;
+ .lblMinimum.Label = &quot;Commission minimale&quot;
+ .lblFix.Label = &quot;Montant fixe/frais&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;Dividende/action&quot;
+ .optTotal.Label = &quot;Dividende total&quot;
+ .lblDividend.Label = &quot;Montant&quot;
+ .lblExchangeRate.Label = &quot;Taux de conversion (ancien-&gt;nouveau)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;Date de la conversion:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~Quotidien&quot;
+ .optWeekly.Label = &quot;~Hebdomadaire&quot;
+ .hlnInterval.Label = &quot;Période&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module>
diff --git a/wizards/source/depot/Lang_it.xba b/wizards/source/depot/Lang_it.xba
new file mode 100644
index 000000000..a8d21bf25
--- /dev/null
+++ b/wizards/source/depot/Lang_it.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_it" script:language="StarBasic">Option Explicit
+
+Sub LoadItalianLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~OK&quot;
+ sCancel = &quot;Annulla&quot;
+ sColumnHeader = &quot;Intestazione colonna&quot;
+ sInsertStockName = &quot;Inserite un nome di azioni&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: Gestione delle azioni&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;Errore dati immessi&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;Inserite il numero delle azioni&quot;
+ sMsgNoDividend = &quot;Inserite un dividendo a unità oppure un dividendo totale&quot;
+ sMsgNoExchangeRate = &quot;Indicate un corretto tasso di cambio (vecchie azioni -&gt; nuove azioni).&quot;
+ sMsgNoValidExchangeDate = &quot;Indicate la data di frazionamento delle azioni.&quot;
+ sMsgWrongExchangeDate = &quot;Il frazionamento non è possibile perché sono ancora in atto transazioni dopo la data indicata.&quot;
+ sMsgSellTooMuch = &quot;Non potete vendere così tante azioni. Massimo: &quot;
+ sMsgConfirm = &quot;È necessaria una conferma&quot;
+ sMsgFreeStock = &quot;Confermate la digitazione di azioni gratuite?&quot;
+ sMsgTotalLoss = &quot;Confermate la digitazione di perdita totale?&quot;
+ sMsgAuthorization = &quot;Domanda di sicurezza&quot;
+ sMsgDeleteAll = &quot;Eliminare tutti i movimenti e ripristinare la panoramica dei depositi?&quot;
+ cSplit = &quot;Frazionamento delle azioni il: &quot;
+ sHistory = &quot;Cronologia&quot;
+ TransactTitle(1) = &quot;Vendita di azioni&quot;
+ TransactTitle(2) = &quot;Acquisto di azioni&quot;
+ StockRatesTitle(1) = &quot;Pagamento dei dividendi&quot;
+ StockRatesTitle(2) = &quot;Frazionamento azioni&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;Valuta deposito&quot;
+ sStockName = &quot;Nome delle azioni&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;Risultato data&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;Data d&apos;inizio:&quot;
+ sEndDate = &quot;Data finale:&quot;
+ sStartUpWelcome = &quot;Questo modello vi permette una gestione efficace delle vostre azioni.&quot;
+ sStartUpChooseMarket = &quot;Selezionate la valuta di riferimento e la Borsa per il collegamento Internet.&quot;
+ sStartUpHint = &quot;La funzione &lt;History&gt; è disponibile solo per il mercato americano.&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;Senza aggiornamento Internet&quot;
+ sMarketPlace = &quot;Borsa:&quot;
+ sNoInternetDataAvailable = &quot;Impossibile ricevere le quotazioni Internet&quot;
+ sCheckInternetSettings = &quot;Possibili cause: &lt;BR&gt; le impostazioni Internet devono essere modificate.&lt;BR&gt; Avete indicato un indice (ad es. simbolo o codice) errato per le azioni.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;La data finale dev&apos;essere anteriore alla data odierna.&quot;
+ sMsgStartDatebeforeEndDate = &quot;La data d&apos;inizio deve precedere la data finale.&quot;
+
+ sMarket(0,0) = &quot;Dollaro USA&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;New York&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;Simbolo&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;Euro&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;Francoforte&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;Numero identificazione titoli&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;Sterlina inglese&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;Londra&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;Simbolo&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;Yen&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;Tokyo&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;Codice&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;Dollaro Hong Kong&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;Hong Kong&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;Numero&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;Dollaro australiano&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;Sydney&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;Simbolo&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;Quantità&quot;
+ .lblRate.Label = &quot;Quotazione&quot;
+ .lblDate.Label = &quot;Data della transazione&quot;
+ .hlnCommission.Label = &quot;Spese extra&quot;
+ .lblCommission.Label = &quot;Commissioni&quot;
+ .lblMinimum.Label = &quot;Commissione minima&quot;
+ .lblFix.Label = &quot;Importo fisso/Spese&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;Dividendo/Azione&quot;
+ .optTotal.Label = &quot;Dividendo totale&quot;
+ .lblDividend.Label = &quot;Importo&quot;
+ .lblExchangeRate.Label = &quot;Tasso di cambio (vecchio-&gt;nuovo)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;Data di cambio:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~Giornaliero&quot;
+ .optWeekly.Label = &quot;~Settimanale&quot;
+ .hlnInterval.Label = &quot;Durata&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module>
diff --git a/wizards/source/depot/Lang_ja.xba b/wizards/source/depot/Lang_ja.xba
new file mode 100644
index 000000000..114a0bf08
--- /dev/null
+++ b/wizards/source/depot/Lang_ja.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_ja" script:language="StarBasic">Option Explicit
+
+Sub LoadJapaneseLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~OK&quot;
+ sCancel = &quot;キャンセル&quot;
+ sColumnHeader = &quot;列番号&quot;
+ sInsertStockName = &quot;最初に株の銘柄を入力してください。&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: 株管理&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;入力フィールド&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;0 より大きな額を入力してください。&quot;
+ sMsgNoDividend = &quot;1株当たりの配当金額または総配当金額を入力してください。&quot;
+ sMsgNoExchangeRate = &quot;交換比率(旧株-&gt;新株)を入力してください。&quot;
+ sMsgNoValidExchangeDate = &quot;株式分割日を入力してください。&quot;
+ sMsgWrongExchangeDate = &quot;分割日以降に取引がすでに存在するので、分割できません。&quot;
+ sMsgSellTooMuch = &quot;売却できる株式数を超えています。最大値: &quot;
+ sMsgConfirm = &quot;ご確認ください&quot;
+ sMsgFreeStock = &quot;無料株式を入力しますか?&quot;
+ sMsgTotalLoss = &quot;全損の入力を行いますか?&quot;
+ sMsgAuthorization = &quot;確認ダイアログ&quot;
+ sMsgDeleteAll = &quot;すべての移動を取り消し、ポートフォリオの概要をリセットしますか?&quot;
+ cSplit = &quot;株式分割日 &quot;
+ sHistory = &quot;履歴&quot;
+ TransactTitle(1) = &quot;株を買う&quot;
+ TransactTitle(2) = &quot;株を買う&quot;
+ StockRatesTitle(1) = &quot;配当額&quot;
+ StockRatesTitle(2) = &quot;株式分割&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;ポートフォリオの通貨&quot;
+ sStockName = &quot;株式名&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;結果(日付)&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;開始日:&quot;
+ sEndDate = &quot;終了日:&quot;
+ sStartUpWelcome = &quot;このテンプレートを使えば、株式のポートフォリオをより効率的に管理できます。&quot;
+ sStartUpChooseMarket = &quot;まず、インターネットにより情報を更新する基準通貨と、対応する証券取引所を選択します。&quot;
+ sStartUpHint = &quot;残念ながら、&lt;History&gt; 機能を使用できるのは米国市場に限られています。&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;インターネットによる情報の更新を行いません&quot;
+ sMarketPlace = &quot;証券取引所:&quot;
+ sNoInternetDataAvailable = &quot;インターネットから株価情報を受信できない場合があります!&quot;
+ sCheckInternetSettings = &quot;考えられる原因は次のとおりです。&lt;BR&gt;インターネット設定の変更が必要です。&lt;BR&gt;入力した株式のが間違っています。&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;終了日は、今日の日付より前であることが必要です。&quot;
+ sMsgStartDatebeforeEndDate = &quot;開始日は、終了日より前であることが必要です。&quot;
+
+ sMarket(0,0) = &quot;米ドル&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;ニューヨーク&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;シンボル&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;ユーロ&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;フランクフルト&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;銘柄コード&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;英ポンド&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;ロンドン&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;シンボル&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;日本円&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;東京&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;コード&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;香港ドル&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;香港&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.HK&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;番号&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;オーストリア・ドル&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;シドニー&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;シンボル&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;株数&quot;
+ .lblRate.Label = &quot;価格&quot;
+ .lblDate.Label = &quot;取引日&quot;
+ .hlnCommission.Label = &quot;その他の経費n&quot;
+ .lblCommission.Label = &quot;手数料&quot;
+ .lblMinimum.Label = &quot;最低手数料&quot;
+ .lblFix.Label = &quot;固定費/諸経費&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;配当金/株式数&quot;
+ .optTotal.Label = &quot;配当金の総額&quot;
+ .lblDividend.Label = &quot;金額&quot;
+ .lblExchangeRate.Label = &quot;交換比率(旧株-&gt;新株)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;交換日:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~毎日&quot;
+ .optWeekly.Label = &quot;~毎週&quot;
+ .hlnInterval.Label = &quot;期間&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_ko.xba b/wizards/source/depot/Lang_ko.xba
new file mode 100644
index 000000000..fcc3224e1
--- /dev/null
+++ b/wizards/source/depot/Lang_ko.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_ko" script:language="StarBasic">Option Explicit
+
+Sub LoadKoreanLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;~확인&quot;
+ sCancel = &quot;취소&quot;
+ sColumnHeader = &quot;열 머리글&quot;
+ sInsertStockName = &quot;주식 종목을 삽입해주십시오.&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: 주식 매수&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;입력 오류&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;0 이하의 매수를 입력해주십시오.&quot;
+ sMsgNoDividend = &quot;한 주당 배당분 또는 총배당분을 입력해주십시오.&quot;
+ sMsgNoExchangeRate = &quot;정확한 환율을 입력해주십시오 (구주를 신주로 소급 시).&quot;
+ sMsgNoValidExchangeDate = &quot;유효한 배당 결제일을 입력해주십시오.&quot;
+ sMsgWrongExchangeDate = &quot;배당 기준일이 경과하여 배당할 수 없습니다.&quot;
+ sMsgSellTooMuch = &quot;이렇게 많은 주식을 팔 수 없습니다. 최대 매도수: &quot;
+ sMsgConfirm = &quot;확인 필요&quot;
+ sMsgFreeStock = &quot;공짜 주식을 입력하시겠습니까?&quot;
+ sMsgTotalLoss = &quot;주가 폭락세를 입력하시겠습니까?&quot;
+ sMsgAuthorization = &quot;안정성 조회&quot;
+ sMsgDeleteAll = &quot;모든 주가 움직임을 삭제하고 계좌 현황을 원래대로 하시겠습니까?&quot;
+ cSplit = &quot;주식 배당일 &quot;
+ sHistory = &quot;내역&quot;
+ TransactTitle(1) = &quot;주식 관리: 주식 매도&quot;
+ TransactTitle(2) = &quot;주식 관리: 주식 매수&quot;
+ StockRatesTitle(1) = &quot;주식 관리: 배당금 지불&quot;
+ StockRatesTitle(2) = &quot;주식 관리: 주식 배분&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;주식 계좌 통화&quot;
+ sStockName = &quot;주식 종목명&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;결과, 날짜&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;매매일:&quot;
+ sEndDate = &quot;만기일:&quot;
+ sStartUpWelcome = &quot;이 템플릿을 사용하여 주식 투자 관리를 효율적으로 할 수 있습니다.&quot;
+ sStartUpChooseMarket = &quot;인터넷 업데이트를 위해 우선 관련 통화와 증권 장소를 선택하십시오.&quot;
+ sStartUpHint = &quot;&lt;내역&gt; 기능은 미국 시장용으로만 사용할 수 있습니다.&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;인터넷 업데이트 없음&quot;
+ sMarketPlace = &quot;증권 장소:&quot;
+ sNoInternetDataAvailable = &quot;인터넷 시세는 받을 수 없었습니다.&quot;
+ sCheckInternetSettings = &quot;원인: &lt;BR&gt; 인터넷 설정을 점검해야만 합니다.&lt;BR&gt; 옳지 않은 암호&lt;예를 들어 잘못된 문자 또는 종목 코드&gt;를 입력했습니다.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;만기일은 오늘 날짜 전에 기입되어야 합니다.&quot;
+ sMsgStartDatebeforeEndDate = &quot;매매일은 만기일 전에 기입되어야 합니다.&quot;
+
+ sMarket(0,0) = &quot;미국 달러&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;뉴욕&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;기호&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;유로&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;프랑크푸르트&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;WKN&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;영국 파운드&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;런던&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;기호&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;엔화&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;도쿄&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;코드&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;홍콩 달러&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;홍콩&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.HK&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;번호&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;호주 달러&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;시드니&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;기호&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;수량&quot;
+ .lblRate.Label = &quot;시세&quot;
+ .lblDate.Label = &quot;배당 결산일&quot;
+ .hlnCommission.Label = &quot;기타 지출&quot;
+ .lblCommission.Label = &quot;수수료&quot;
+ .lblMinimum.Label = &quot;최저 수수료&quot;
+ .lblFix.Label = &quot;약정 금액/기타 경비&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;배당분/주&quot;
+ .optTotal.Label = &quot;배당분 합계&quot;
+ .lblDividend.Label = &quot;금액&quot;
+ .lblExchangeRate.Label = &quot;환율(구주-&gt;신주)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;환율일자&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~매일&quot;
+ .optWeekly.Label = &quot;~매주&quot;
+ .hlnInterval.Label = &quot;기간&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_sv.xba b/wizards/source/depot/Lang_sv.xba
new file mode 100644
index 000000000..cbe67e1c2
--- /dev/null
+++ b/wizards/source/depot/Lang_sv.xba
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_sv" script:language="StarBasic">Option Explicit
+
+Sub LoadSwedishLanguage()
+ sProductname = GetProductname
+ sOK = &quot;~OK&quot;
+ sCancel = &quot;Avbryt&quot;
+ sColumnHeader = &quot;Kolumnhuvud&quot;
+ sInsertStockName = &quot;Infoga först några aktier i Din portfölj!&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: Aktieförvaltning&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;Inmatningsfel&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;Var vänlig och mata in ett större antal än 0&quot;
+ sMsgNoDividend = &quot;Var vänlig och mata in utdelning per styck eller den totala utdelningen&quot;
+ sMsgNoExchangeRate = &quot;Var vänlig och mata in en korrekt omräkningskurs (gamla aktier -&gt; nya aktier).&quot;
+ sMsgNoValidExchangeDate = &quot;Var vänlig och mata in ett giltigt datum för aktiesplitten.&quot;
+ sMsgWrongExchangeDate = &quot;Split är inte möjlig eftersom det redan finns transaktioner efter splitdatum.&quot;
+ sMsgSellTooMuch = &quot;Så många aktier kan Du inte sälja. Maximum: &quot;
+ sMsgConfirm = &quot;Bekräftelse krävs&quot;
+ sMsgFreeStock = &quot;Avser Du att mata in gratisaktier?&quot;
+ sMsgTotalLoss = &quot;Avser Du att mata in en totalförlust?&quot;
+ sMsgAuthorization = &quot;Säkerhetskontroll&quot;
+ sMsgDeleteAll = &quot;Vill Du ta bort alla rörelser och återställa portföljöversikten?&quot;
+ cSplit = &quot;Aktiesplit den &quot;
+ sHistory = &quot;Historik&quot;
+ TransactTitle(1) = &quot;Sälja aktier&quot;
+ TransactTitle(2) = &quot;Köpa aktier&quot;
+ StockRatesTitle(1) = &quot;Aktieutdelning&quot;
+ StockRatesTitle(2) = &quot;Aktiesplit&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;Portföljvaluta&quot;
+ sStockName = &quot;Aktienamn&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;Resultat datum&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;Startdatum:&quot;
+ sEndDate = &quot;Slutdatum:&quot;
+ sStartUpWelcome = &quot;Med hjälp av den här mallen kan Du förvalta Din aktieportfölj effektivt&quot;
+ sStartUpChooseMarket = &quot;Välj först Din referensvaluta och därigenom börs för Internet-uppdateringen!&quot;
+ sStartUpHint = &quot;Tyvärr är &lt;History&gt;-funktionen bara tillgänglig för den amerikanska marknaden!&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;utan Internet-uppdatering&quot;
+ sMarketPlace = &quot;Börs:&quot;
+ sNoInternetDataAvailable = &quot;Det gick inte att ta emot Internet-kurser!&quot;
+ sCheckInternetSettings = &quot;Detta kan bero på att: &lt;BR&gt; Dina Internet-inställningar måste ändras.&lt;BR&gt; Du har angivit ett felaktigt ID (t.ex. symbol, värdepappersnr.) för aktien.&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;Slutdatum måste ligga före idag!&quot;
+ sMsgStartDatebeforeEndDate = &quot;Startdatum måste ligga före slutdatum!&quot;
+
+ sMarket(0,0) = &quot;Amerikansk dollar&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;New York&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;Symbol&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;Euro&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;Frankfurt&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;Värdepappersnr&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;Engelskt pund&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;London&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;Symbol&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;Japansk yen&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;Tokyo&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;Kod&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;Hongkongdollar&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;Hongkong&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;Nummer&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;Australisk dollar&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;Sydney&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;Symbol&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;Antal&quot;
+ .lblRate.Label = &quot;Kurs&quot;
+ .lblDate.Label = &quot;Transaktionsdatum&quot;
+ .hlnCommission.Label = &quot;Övriga utgifter&quot;
+ .lblCommission.Label = &quot;Provision&quot;
+ .lblMinimum.Label = &quot;Minimiprovision&quot;
+ .lblFix.Label = &quot;Fast belopp/omkostnader&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;Utdelning per aktie&quot;
+ .optTotal.Label = &quot;Utdelning totalt&quot;
+ .lblDividend.Label = &quot;Belopp&quot;
+ .lblExchangeRate.Label = &quot;Omräkningskurs (gammal-&gt;ny)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;Omräkningsdatum:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;~Dagligen&quot;
+ .optWeekly.Label = &quot;~Varje vecka&quot;
+ .hlnInterval.Label = &quot;Period&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_tw.xba b/wizards/source/depot/Lang_tw.xba
new file mode 100644
index 000000000..a4df8c1b6
--- /dev/null
+++ b/wizards/source/depot/Lang_tw.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_tw" script:language="StarBasic">Option Explicit
+
+Sub LoadChineseTradLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;確定&quot;
+ sCancel = &quot;取消&quot;
+ sColumnHeader = &quot;欄標簽&quot;
+ sInsertStockName = &quot;請先填入股票名稱!&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;: 股票管理&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;輸入無效&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;請輸入大於0的交易股數&quot;
+ sMsgNoDividend = &quot;請輸入每股股息金額或股息總額&quot;
+ sMsgNoExchangeRate = &quot;請鍵入正確的換算比率(舊股票 -&gt; 新股票)。&quot;
+ sMsgNoValidExchangeDate = &quot;請輸入股票分割的日期。&quot;
+ sMsgWrongExchangeDate = &quot;無法分割股票,因為分割日期之後已經買進或賣出股票。&quot;
+ sMsgSellTooMuch = &quot;最多能出售的股票數: &quot;
+ sMsgConfirm = &quot;需要确認&quot;
+ sMsgFreeStock = &quot;需要輸入一個贈送的股票?&quot;
+ sMsgTotalLoss = &quot;要輸入一個全部損失的股票?&quot;
+ sMsgAuthorization = &quot;安全詢問&quot;
+ sMsgDeleteAll = &quot;您要刪除所有的交易資料,重新建立一個股票一覽表?&quot;
+ cSplit = &quot;股票分割的日期 &quot;
+ sHistory = &quot;紀錄&quot;
+ TransactTitle(1) = &quot;出售股票&quot;
+ TransactTitle(2) = &quot;購買股票&quot;
+ StockRatesTitle(1) = &quot;支付股息&quot;
+ StockRatesTitle(2) = &quot;股票分割&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;股票的貨幣&quot;
+ sStockName = &quot;股票名稱&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;結果 日期&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;交割日期:&quot;
+ sEndDate = &quot;到期日期:&quot;
+ sStartUpWelcome = &quot;這個樣式用於高效能地管理股票交易。&quot;
+ sStartUpChooseMarket = &quot;請先選一個參照的貨幣和一個可直接從 Internet 更新資料的贈券交易所。&quot;
+ sStartUpHint = &quot;很遺憾,&lt;History&gt;-功能僅適用於美國的交易所。&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;不透過 internet 更新&quot;
+ sMarketPlace = &quot;證券交易所:&quot;
+ sNoInternetDataAvailable = &quot;無法接受 Internet 股票價格!&quot;
+ sCheckInternetSettings = &quot;可能的原因:&lt;BR&gt;Internet 設定不正確,需要重新設定。&lt;BR&gt;輸入了一個錯誤的股票代碼。&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;到期日期必須是在今日之前!&quot;
+ sMsgStartDatebeforeEndDate = &quot;交割日期必須是在到期日期之前!&quot;
+
+ sMarket(0,0) = &quot;美元&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;紐約&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;股票符號&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;歐元&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;法蘭克福&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;股代碼&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;英鎊&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;倫敦&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;股票符號&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;日元&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;東京&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;代碼&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;港幣&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;香港&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.HK&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;編號&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;澳元&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;悉尼&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;股票符號&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;數量&quot;
+ .lblRate.Label = &quot;股票價格&quot;
+ .lblDate.Label = &quot;交易日期&quot;
+ .hlnCommission.Label = &quot;其它的支出費用&quot;
+ .lblCommission.Label = &quot;手續費&quot;
+ .lblMinimum.Label = &quot;最低手續費&quot;
+ .lblFix.Label = &quot;固定金額/費用&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;每股股息&quot;
+ .optTotal.Label = &quot;股息總計&quot;
+ .lblDividend.Label = &quot;金額&quot;
+ .lblExchangeRate.Label = &quot;轉換比率(舊股票 -&gt; 新股票)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;轉換日期:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;每日&quot;
+ .optWeekly.Label = &quot;每週&quot;
+ .hlnInterval.Label = &quot;時間週期&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/Lang_zh.xba b/wizards/source/depot/Lang_zh.xba
new file mode 100644
index 000000000..a4dde61b4
--- /dev/null
+++ b/wizards/source/depot/Lang_zh.xba
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Lang_zh" script:language="StarBasic">Option Explicit
+
+Sub LoadChineseSimpleLanguage()
+
+ sProductname = GetProductname
+ sOK = &quot;确定&quot;
+ sCancel = &quot;取消&quot;
+ sColumnHeader = &quot;列标题&quot;
+ sInsertStockName = &quot;请首先往您的帐号内输入一些股票名称!&quot;
+ sTitle = &quot;&lt;PRODUCTNAME&gt;:股票管理&quot;
+ sTitle = ReplaceString(sTitle, sProductName, &quot;&lt;PRODUCTNAME&gt;&quot;)
+ sMsgError = &quot;输入错误&quot;
+ sMsgNoName = sInsertStockname
+ sMsgNoQuantity = &quot;请输入大于0的交易股数&quot;
+ sMsgNoDividend = &quot;请输入每股的红利金额或红利总额&quot;
+ sMsgNoExchangeRate = &quot;请输入一个正确的兑换率(旧股-&gt; 新股)。&quot;
+ sMsgNoValidExchangeDate = &quot;请输入拆股生效日期。&quot;
+ sMsgWrongExchangeDate = &quot;因为在拆股生效后已经进行了股票交易,所以无法拆股。&quot;
+ sMsgSellTooMuch = &quot;您最多能出售的股票数为: &quot;
+ sMsgConfirm = &quot;需要确认&quot;
+ sMsgFreeStock = &quot;您想要输入赠送股票?&quot;
+ sMsgTotalLoss = &quot;您想要输入总亏损值?&quot;
+ sMsgAuthorization = &quot;安全查询&quot;
+ sMsgDeleteAll = &quot;您要删除所有的交易信息并重新建立股票帐号一览表吗?&quot;
+ cSplit = &quot;股票拆股日期 &quot;
+ sHistory = &quot;记录&quot;
+ TransactTitle(1) = &quot;出售股票&quot;
+ TransactTitle(2) = &quot;购买股票&quot;
+ StockRatesTitle(1) = &quot;支付红利&quot;
+ StockRatesTitle(2) = &quot;股票拆股&quot;
+ StockRatesTitle(3) = sHistory
+ sDepotCurrency = &quot;股票交易的货币&quot;
+ sStockName = &quot;股票名称&quot;
+ TransactMode = LIFO &apos; Possible values: &quot;FIFO&quot; and &quot;LIFO&quot;
+ DateCellStyle = &quot;结果 日期&quot;
+ CurrCellStyle = &quot;1&quot;
+ sStartDate = &quot;起始日期:&quot;
+ sEndDate = &quot;终止日期:&quot;
+ sStartUpWelcome = &quot;这个样式能够帮助您有效地管理自己的股票帐号&quot;
+ sStartUpChooseMarket = &quot;请首先选择采用的参考货币以及要直接用国际互联网来更新资料的证券交易所!&quot;
+ sStartUpHint = &quot;很遗憾,&lt;History&gt;功能仅可供美国市场使用!&quot;
+ sStartupHint = ReplaceString(sStartUpHint, sHistory, &quot;&lt;History&gt;&quot;)
+ sNoInternetUpdate = &quot;不通过国际互联网更新&quot;
+ sMarketPlace = &quot;交易所:&quot;
+ sNoInternetDataAvailable = &quot;无法获得国际互联网上的行情!&quot;
+ sCheckInternetSettings = &quot;可能的原因是:&lt;BR&gt;您的国际互联网设定不正确,需要重新设定。&lt;BR&gt;输入了一个错误的股票号码。&quot;
+ sCheckInternetSettings = ReplaceString(sCheckInternetSettings, chr(13), &quot;&lt;BR&gt;&quot;)
+
+ sMsgEndDatebeforeNow = &quot;终止日期必须在今天之前!&quot;
+ sMsgStartDatebeforeEndDate = &quot;起始日期必须在终止日期之前!&quot;
+
+ sMarket(0,0) = &quot;美元&quot;
+ sMarket(0,1) = &quot;$&quot;
+ sMarket(0,2) = &quot;纽约&quot;
+ sMarket(0,3) = &quot;http://finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(0,4) = &quot;http://ichart.finance.yahoo.com/table.csv?&quot; &amp;_
+ &quot;s=&lt;StockID&gt;&amp;d=&lt;EndMonth&gt;&amp;e=&lt;EndDay&gt;&amp;f=&lt;Endyear&gt;&amp;g=d&amp;&quot; &amp;_
+ &quot;a=&lt;StartMonth&gt;&amp;b=&lt;StartDay&gt;&amp;c=&lt;Startyear&gt;&amp;ignore=.csv&quot;
+ sMarket(0,5) = &quot;图标&quot;
+ sMarket(0,6) = &quot;en&quot;
+ sMarket(0,7) = &quot;US&quot;
+ sMarket(0,8) = &quot;409&quot;
+ sMarket(0,9) = &quot;44&quot;
+ sMarket(0,10) = &quot;1&quot;
+
+ sMarket(1,0) = &quot;欧元&quot;
+ sMarket(1,1) = chr(8364)
+ sMarket(1,2) = &quot;法兰克福&quot;
+ sMarket(1,3) = &quot;http://de.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.F&amp;f=sl1t1c1ghpv&amp;e=.csv&quot;
+ sMarket(1,5) = &quot;代码&quot;
+ sMarket(1,6) = &quot;de;nl;pt;el&quot;
+ sMarket(1,7) = &quot;DE;NL;PT;GR&quot;
+ sMarket(1,8) = &quot;407;413;816;408&quot;
+ sMarket(1,9) = &quot;59/9&quot;
+ sMarket(1,10) = &quot;1&quot;
+
+ sMarket(2,0) = &quot;英镑&quot;
+ sMarket(2,1) = &quot;£&quot;
+ sMarket(2,2) = &quot;伦敦&quot;
+ sMarket(2,3) = &quot;http://uk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.L&amp;m=*&amp;f=sl1t1c1ghov&amp;e=.csv&quot;
+ sMarket(2,5) = &quot;股票代码&quot;
+ sMarket(2,6) = &quot;en&quot;
+ sMarket(2,7) = &quot;GB&quot;
+ sMarket(2,8) = &quot;809&quot;
+ sMarket(2,9) = &quot;44&quot;
+ sMarket(2,10) = &quot;1&quot;
+
+ sMarket(3,0) = &quot;日元&quot;
+ sMarket(3,1) = &quot;¥&quot;
+ sMarket(3,2) = &quot;东京&quot;
+ sMarket(3,3) = &quot;&quot;
+ sMarket(3,5) = &quot;代码&quot;
+ sMarket(3,6) = &quot;ja&quot;
+ sMarket(3,7) = &quot;JP&quot;
+ sMarket(3,8) = &quot;411&quot;
+ sMarket(3,9) = &quot;&quot;
+ sMarket(3,10) = &quot;&quot;
+
+ sMarket(4,0) = &quot;港币&quot;
+ sMarket(4,1) = &quot;HK$&quot;
+ sMarket(4,2) = &quot;香港&quot;
+ sMarket(4,3) = &quot;http://hk.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;.HK&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(4,5) = &quot;编号&quot;
+ sMarket(4,6) = &quot;zh&quot;
+ sMarket(4,7) = &quot;HK&quot;
+ sMarket(4,8) = &quot;C04&quot;
+ sMarket(4,9) = &quot;44&quot;
+ sMarket(4,10) = &quot;1&quot;
+
+ sMarket(5,0) = &quot;澳元&quot;
+ sMarket(5,1) = &quot;$&quot;
+ sMarket(5,2) = &quot;悉尼&quot;
+ sMarket(5,3) = &quot;http://au.finance.yahoo.com/d/quotes.csv?s=&lt;StockID&gt;&amp;f=sl1d1t1c1ohgv&amp;e=.csv&quot;
+ sMarket(5,5) = &quot;股票代码&quot;
+ sMarket(5,6) = &quot;en&quot;
+ sMarket(5,7) = &quot;AU&quot;
+ sMarket(5,8) = &quot;C09&quot;
+ sMarket(5,9) = &quot;44&quot;
+ sMarket(5,10) = &quot;1&quot;
+
+&apos; ****************************End of the default subset*********************************
+ CompleteMarketList()
+
+ LocalizedCurrencies()
+
+ With TransactModel
+ .lblStockNames.Label = sStockname
+ .lblQuantity.Label = &quot;数量&quot;
+ .lblRate.Label = &quot;股票牌价&quot;
+ .lblDate.Label = &quot;交易日期&quot;
+ .hlnCommission.Label = &quot;其它支出费用&quot;
+ .lblCommission.Label = &quot;手续费&quot;
+ .lblMinimum.Label = &quot;最低手续费&quot;
+ .lblFix.Label = &quot;固定金额/费用&quot;
+ .cmdGoOn.Label = sOK
+ .cmdCancel.Label = sCancel
+ End With
+
+ With StockRatesModel
+ .optPerShare.Label = &quot;每股红利&quot;
+ .optTotal.Label = &quot;红利总计&quot;
+ .lblDividend.Label = &quot;金额&quot;
+ .lblExchangeRate.Label = &quot;兑换率(旧-&gt;新)&quot;
+ .lblColon.Label = &quot;:&quot;
+ .lblDate.Label = &quot;兑换日期:&quot;
+ .lblStockNames.Label = sStockname
+ .lblStartDate.Label = sStartDate
+ .lblEndDate.Label = sEndDate
+ .optDaily.Label = &quot;每天&quot;
+ .optWeekly.Label = &quot;每周&quot;
+ .hlnInterval.Label = &quot;时间周期&quot;
+ .cmdGoOn.Label = sOk
+ .cmdCancel.Label = sCancel
+ End With
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/depot/dialog.xlb b/wizards/source/depot/dialog.xlb
new file mode 100644
index 000000000..764ea3f35
--- /dev/null
+++ b/wizards/source/depot/dialog.xlb
@@ -0,0 +1,7 @@
+<?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="Depot" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="Dialog2"/>
+ <library:element library:name="Dialog3"/>
+ <library:element library:name="Dialog4"/>
+</library:library>
diff --git a/wizards/source/depot/script.xlb b/wizards/source/depot/script.xlb
new file mode 100644
index 000000000..372665b22
--- /dev/null
+++ b/wizards/source/depot/script.xlb
@@ -0,0 +1,19 @@
+<?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="Depot" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="Depot"/>
+ <library:element library:name="CommonLang"/>
+ <library:element library:name="Currency"/>
+ <library:element library:name="Internet"/>
+ <library:element library:name="Lang_de"/>
+ <library:element library:name="tools"/>
+ <library:element library:name="Lang_en"/>
+ <library:element library:name="Lang_fr"/>
+ <library:element library:name="Lang_it"/>
+ <library:element library:name="Lang_es"/>
+ <library:element library:name="Lang_sv"/>
+ <library:element library:name="Lang_zh"/>
+ <library:element library:name="Lang_tw"/>
+ <library:element library:name="Lang_ko"/>
+ <library:element library:name="Lang_ja"/>
+</library:library>
diff --git a/wizards/source/depot/tools.xba b/wizards/source/depot/tools.xba
new file mode 100644
index 000000000..daadf4988
--- /dev/null
+++ b/wizards/source/depot/tools.xba
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="tools" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+
+Sub RemoveSheet()
+ If oSheets.HasbyName(&quot;Link&quot;) then
+ oSheets.RemovebyName(&quot;Link&quot;)
+ End If
+End Sub
+
+
+Sub InitializeStatusLine(StatusText as String, MaxValue as Integer, FirstValue as Integer)
+ oStatusline = oDocument.GetCurrentController.GetFrame.CreateStatusIndicator()
+ oStatusLine.Start(StatusText, MaxValue)
+ oStatusline.SetValue(FirstValue)
+End Sub
+
+
+Sub MakeRangeVisible(oSheet as Object, RangeName as String, BIsVisible as Boolean)
+Dim oRangeAddress, oColumns as Object
+Dim i, iStartColumn, iEndColumn as Integer
+ oRangeAddress = oSheet.GetCellRangeByName(RangeName).RangeAddress
+ iStartColumn = oRangeAddress.StartColumn
+ iEndColumn = oRangeAddress.EndColumn
+ oColumns = oSheet.Columns
+ For i = iStartColumn To iEndColumn
+ oSheet.Columns(i).IsVisible = bIsVisible
+ Next i
+End Sub
+
+
+Function GetRowIndex(oSheet as Object, RowName as String)
+Dim oRange as Object
+ oRange = oSheet.GetCellRangeByName(RowName)
+ GetRowIndex = oRange.RangeAddress.StartRow
+End Function
+
+
+Function GetTransactionCount(iStartRow as Integer)
+Dim iEndRow as Integer
+ iStartRow = GetRowIndex(oMovementSheet, &quot;ColumnsToHide&quot;)
+ iEndRow = GetRowIndex(oMovementSheet, &quot;HiddenRow3&quot; )
+ GetTransactionCount = iEndRow -iStartRow - 2
+End Function
+
+
+Function GetStocksCount(iStartRow as Integer)
+Dim iEndRow as Integer
+ iStartRow = GetRowIndex(oFirstSheet, &quot;HiddenRow1&quot;)
+ iEndRow = GetRowIndex(oFirstSheet, &quot;HiddenRow2&quot;)
+ GetStocksCount = iEndRow -iStartRow - 1
+End Function
+
+
+Function FillListbox(ListboxControl as Object, MsgTitle as String, bShowMessage) as Boolean
+Dim i, StocksCount as Integer
+Dim iStartRow as Integer
+Dim oCell as Object
+ &apos; Add stock names to empty list box
+ StocksCount = GetStocksCount(iStartRow)
+ If StocksCount &gt; 0 Then
+ ListboxControl.Model.StringItemList() = NullList()
+ For i = 1 To StocksCount
+ oCell = oFirstSheet.GetCellByPosition(SBCOLUMNNAME1,iStartRow + i)
+ ListboxControl.AddItem(oCell.String, i-1)
+ Next
+ FillListbox() = True
+ Else
+ If bShowMessage Then
+ Msgbox(sInsertStockName, 16, MsgTitle)
+ FillListbox() = False
+ End If
+ End If
+End Function
+
+
+Sub CellValuetoControl(oSheet, oControl as Object, CellName as String)
+Dim oCell as Object
+Dim StringValue
+ oCell = GetCellByName(oSheet, CellName)
+ If oControl.PropertySetInfo.HasPropertyByName(&quot;EffectiveValue&quot;) Then
+ oControl.EffectiveValue = oCell.Value
+ Else
+ oControl.Value = oCell.Value
+ End If
+&apos; If oCell.FormulaResultType = 1 Then
+&apos; StringValue = oNumberFormatter.GetInputString(oCell.NumberFormat, oCell.Value)
+&apos; oControl.Text = DeleteStr(StringValue, &quot;%&quot;)
+&apos; Else
+&apos; oControl.Text = oCell.String
+&apos; End If
+End Sub
+
+
+Sub RemoveStockRows(oSheet as Object, iStartRow, RowCount as Integer)
+ If RowCount &gt; 0 Then
+ oSheet.Rows.RemoveByIndex(iStartRow, RowCount)
+ End If
+End Sub
+
+
+Sub AddValueToCellContent(iCellCol, iCellRow as Integer, AddValue)
+Dim oCell as Object
+Dim OldValue
+ oCell = oMovementSheet.GetCellByPosition(iCellCol, iCellRow)
+ OldValue = oCell.Value
+ oCell.Value = OldValue + AddValue
+End Sub
+
+
+Sub CheckInputDate(aEvent as Object)
+Dim oRefDialog as Object
+Dim oRefModel as Object
+Dim oDateModel as Object
+ oDateModel = aEvent.Source.Model
+ oRefModel = DlgReference.GetControl(&quot;cmdGoOn&quot;).Model
+ oRefModel.Enabled = oDateModel.Date &lt;&gt; 0
+End Sub
+
+
+
+&apos; Updates the cell with the CurrentValue after checking if the
+&apos; Newdate is later than the one that is referred to in the annotation
+&apos; of the cell
+Sub InsertCurrentValue(CurValue as Double, iRow as Integer, Newdate as Date)
+Dim oCell as Object
+Dim OldDate as Date
+ oCell = oFirstSheet.GetCellByPosition(SBCOLUMNRATE1, iRow)
+ OldDate = CDate(oCell.Annotation.Text.String)
+ If NewDate &gt;= OldDate Then
+ oCell.SetValue(CurValue)
+ oCell.Annotation.Text.SetString(CStr(NewDate))
+ End If
+End Sub
+
+
+Sub SplitCellValue(oSheet, FirstNumber, SecondNumber, iCol, iRow, NoteText)
+Dim oCell as Object
+Dim OldValue
+ oCell = oSheet.GetCellByPosition(iCol, iRow)
+ OldValue = oCell.Value
+ oCell.Value = OldValue * FirstNumber / SecondNumber
+ If NoteText &lt;&gt; &quot;&quot; Then
+ oCell.Annotation.SetString(NoteText)
+ End If
+End Sub
+
+
+Function GetStockRowIndex(ByVal Stockname) as Integer
+Dim i, StocksCount as Integer
+Dim iStartRow as Integer
+Dim oCell as Object
+ StocksCount = GetStocksCount(iStartRow)
+ For i = 1 To StocksCount
+ oCell = oFirstSheet.GetCellByPosition(SBCOLUMNNAME1,iStartRow + i)
+ If oCell.String = Stockname Then
+ GetStockRowIndex = iStartRow + i
+ Exit Function
+ End If
+ Next
+ GetStockRowIndex = -1
+End Function
+
+
+Function GetStockID(StockName as String, Optional iFirstRow as Integer) as String
+Dim CellStockName as String
+Dim i as Integer
+Dim iCount as Integer
+Dim iLastRow as Integer
+ If IsMissing(iFirstRow) Then
+ iFirstRow = GetRowIndex(oFirstSheet, &quot;HiddenRow1&quot;)
+ End If
+ iCount = GetStocksCount(iFirstRow)
+ iLastRow = iFirstRow + iCount
+ For i = iFirstRow To iLastRow
+ CellStockName = oFirstSheet.GetCellByPosition(SBCOLUMNNAME1, i).String
+ If CellStockname = StockName Then
+ Exit For
+ End If
+ Next i
+ If i &gt; iLastRow Then
+ GetStockID() = &quot;&quot;
+ Else
+ If Not IsMissing(iFirstRow) Then
+ iFirstRow = i
+ End If
+ GetStockID() = oFirstSheet.GetCellByPosition(SBCOLUMNID1, i).String
+ End If
+End Function
+
+
+Function CheckDocLocale(LocLanguage as String, LocCountry as String)
+Dim bIsDocLanguage as Boolean
+Dim bIsDocCountry as Boolean
+ bIsDocLanguage = Instr(1, LocLanguage, sDocLanguage, SBBINARY) &lt;&gt; 0
+ bIsDocCountry = Instr(1, LocCountry, sDocCountry, SBBINARY) &lt;&gt; 0 OR SDocCountry = &quot;&quot;
+ CheckDocLocale = (bIsDocLanguage And bIsDocCountry)
+End Function
+</script:module>
diff --git a/wizards/source/euro/AutoPilotRun.xba b/wizards/source/euro/AutoPilotRun.xba
new file mode 100644
index 000000000..77ca182df
--- /dev/null
+++ b/wizards/source/euro/AutoPilotRun.xba
@@ -0,0 +1,415 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="AutoPilotRun" script:language="StarBasic">Option Explicit
+
+Public SourceDir as String
+Public TargetDir as String
+Public TargetStemDir as String
+Public SourceFile as String
+Public TargetFile as String
+Public Source as String
+Public SubstFile as String
+Public SubstDir as String
+Public NoArgs()
+Public TypeList(6) as String
+Public GoOn as Boolean
+Public DoUnprotect as Integer
+Public Password as String
+Public DocIndex as Integer
+Public oPathSettings as Object
+Public oUcb as Object
+Public TotDocCount as Integer
+Public sTotDocCount as String
+Public OpenProperties(1) as New com.sun.star.beans.PropertyValue
+
+
+Sub StartAutoPilot()
+Dim i As Integer
+Dim oFactoryKey as Object
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ BasicLibraries.LoadLibrary(&quot;ImportWizard&quot;)
+ If InitResources(&quot;Euro Converter&quot;) Then
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ oLocale = GetStarOfficeLocale()
+ InitializeConverter(oLocale, 2)
+ ToggleGoOnButton()
+ oFactoryKey = GetRegistryKeyContent(&quot;org.openoffice.Setup/Office/Factories&quot;)
+ DialogModel.chkTextDocuments.Enabled = oFactoryKey.hasbyName(&quot;com.sun.star.text.TextDocument&quot;)
+ DialogModel.cmdGoOn.DefaultButton = True
+ DialogModel.lstCurrencies.TabIndex = 12
+ DialogConvert.GetControl(&quot;optWholeDir&quot;).SetFocus()
+ DialogConvert.Execute()
+ DialogConvert.Dispose()
+ End If
+End Sub
+
+
+Sub ConvertDocuments()
+Dim FilesList()
+Dim bDisposable as Boolean
+
+ If Source &lt;&gt; &quot;&quot; And TargetDir &lt;&gt; &quot;&quot; Then
+ If DialogModel.optSingleFile.State = 1 Then
+ SourceFile = Source
+ TotDocCount = 1
+ Else
+ SourceDir = Source
+ TargetStemDir = TargetDir
+ TypeList(0) = &quot;calc8&quot;
+ TypeList(1) = &quot;calc_StarOffice_XML_Calc&quot;
+ If DialogModel.chkTextDocuments.State = 1 Then
+ ReDim Preserve TypeList(5) as String
+
+ TypeList(2) = &quot;writer8&quot;
+ TypeList(3) = &quot;writerglobal8&quot;
+ TypeList(4) = &quot;writer_StarOffice_XML_Writer&quot;
+ TypeList(5) = &quot;writer_globaldocument_StarOffice_XML_Writer_GlobalDocument&quot;
+ End If
+ FilesList() = ReadDirectories(SourceDir, bRecursive, True, False, TypeList())
+ TotDocCount = Ubound(FilesList(),1) + 1
+ End If
+ InitializeProgressPage(DialogModel)
+&apos; ChangeToNextProgressStep()
+ sTotDocCount = CStr(TotDocCount)
+ OpenProperties(0).Name = &quot;Hidden&quot;
+ OpenProperties(0).Value = True
+ OpenProperties(1).Name = &quot;AsTemplate&quot;
+ OpenProperties(1).Value = False
+ For DocIndex = 0 To TotDocCount - 1
+ If InitializeDocument(FilesList(), bDisposable) Then
+ If StoreDocument() Then
+ ConvertDocument()
+ oDocument.Store
+ End If
+ If bDisposable Then
+ oDocument.Dispose()
+ End If
+ End If
+ Next DocIndex
+ DialogModel.cmdBack.Enabled = True
+ DialogModel.cmdGoOn.Enabled = True
+ DialogModel.cmdGoOn.Label = sReady
+ DialogModel.cmdCancel.Label = sEnd
+ End If
+End Sub
+
+
+Function InitializeDocument(FilesList(), bDisposable as Boolean) as Boolean
+&apos; The Autopilot is started from step No. 2
+Dim sViewPath as String
+Dim bIsReadOnly as Boolean
+Dim sExtension as String
+ On Local Error Goto NEXTFILE
+ If Not bCancelTask Then
+ If DialogModel.optWholeDir.State = 1 Then
+ SourceFile = FilesList(DocIndex,0)
+ TargetFile = ReplaceString(SourceFile,TargetStemDir,SourceDir)
+ TargetDir = DirectorynameoutofPath(TargetFile, &quot;/&quot;)
+ Else
+ SourceFile = Source
+ TargetFile = TargetDir &amp; &quot;/&quot; &amp; FileNameoutofPath(SourceFile, &quot;/&quot;)
+ End If
+ If CreateFolder(TargetDir) Then
+ sExtension = GetFileNameExtension(SourceFile, &quot;/&quot;)
+ oDocument = OpenDocument(SourceFile, OpenProperties(), bDisposable)
+ If (oDocument.IsReadOnly) AND (UCase(SourceFile) = UCase(TargetFile)) Then
+ bIsReadOnly = True
+ Msgbox(sMsgDOCISREADONLY, 16, GetProductName())
+ Else
+ bIsReadOnly = False
+ RetrieveDocumentObjects()
+ sViewPath = CutPathView(SourceFile, 60)
+ DialogModel.lblCurDocument.Label = Str(DocIndex+1) &amp; &quot;/&quot; &amp; sTotDocCount &amp; &quot; (&quot; &amp; sViewPath &amp; &quot;)&quot;
+ End If
+ InitializeDocument() = Not bIsReadOnly
+ Else
+ InitializeDocument() = False
+ End If
+ Else
+ InitializeDocument() = False
+ End If
+NEXTFILE:
+ If Err &lt;&gt; 0 Then
+ InitializeDocument() = False
+ Resume LETSGO
+LETSGO:
+ End If
+End Function
+
+
+Sub ChangeToNextProgressStep()
+ DialogModel.lblCurProgress.FontWeight = com.sun.star.awt.FontWeight.NORMAL
+ DialogConvert.GetControl(&quot;lblCurProgress&quot;).Visible = True
+End Sub
+
+
+Function StoreDocument() as Boolean
+Dim sCurFileExists as String
+Dim iOverWrite as Integer
+ If (TargetFile &lt;&gt; &quot;&quot;) And (Not bCancelTask) Then
+ On Local Error Goto NOSAVING
+ If oUcb.Exists(TargetFile) Then
+ sCurFileExists = ReplaceString(sMsgFileExists, ConvertFromUrl(TargetFile), &quot;&lt;1&gt;&quot;)
+ sCurFileExists = ReplaceString(sCurFileExists, chr(13), &quot;&lt;CR&gt;&quot;)
+ iOverWrite = Msgbox (sCurFileExists, 32 + 3, sMsgDLGTITLE)
+ Select Case iOverWrite
+ Case 1 &apos; OK
+ Case 2 &apos; Abort
+ bCancelTask = True
+ StoreDocument() = False
+ Exit Function
+ Case 7 &apos; No
+ StoreDocument() = False
+ Exit Function
+ End Select
+ End If
+ If TargetFile &lt;&gt; SourceFile Then
+ oDocument.StoreAsUrl(TargetFile,NoArgs)
+ Else
+ oDocument.Store
+ End If
+ StoreDocument() = True
+ NOSAVING:
+ If Err &lt;&gt; 0 Then
+ StoreDocument() = False
+ Resume CLERROR
+ End If
+ CLERROR:
+ End If
+End Function
+
+
+Sub SwapExtent()
+ DialogModel.chkRecursive.Enabled = DialogModel.optWholeDir.State = 1
+ If DialogModel.optWholeDir.State = 1 Then
+ DialogModel.lblSource.Label = sSOURCEDIR
+ If Not IsNull(SubstFile) Then
+ SubstFile = DialogModel.txtSource.Text
+ DialogModel.txtSource.Text = SubstDir
+ End If
+ Else
+ DialogModel.LblSource.Label = sSOURCEFILE
+ If Not IsNull(SubstDir) Then
+ SubstDir = DialogModel.txtSource.Text
+ DialogModel.txtSource.Text = SubstFile
+ End If
+ End If
+ ToggleGoOnButton()
+End Sub
+
+
+Function InitializeThirdStep() as Boolean
+Dim TextBoxText as String
+ Source = AssignFileName(DialogModel.txtSource.Text, DialogModel.lblSource.Label, True)
+ If CheckTextBoxPath(DialogModel.txtTarget, True, True, sMsgDLGTITLE, True) Then
+ TargetDir = AssignFileName(DialogModel.txtTarget.Text, DialogModel.lblTarget.Label, False)
+ Else
+ TargetDir = &quot;&quot;
+ End If
+ If Source &lt;&gt; &quot;&quot; And TargetDir &lt;&gt; &quot;&quot; Then
+ bRecursive = DialogModel.chkRecursive.State = 1
+ bDoUnprotect = DialogModel.chkProtect.State = 1
+ DialogModel.lblRetrieval.FontWeight = com.sun.star.awt.FontWeight.BOLD
+ DialogModel.lblRetrieval.Label = sPrgsRETRIEVAL
+ DialogModel.lblCurProgress.Label = sPrgsCONVERTING
+ If DialogModel.optWholeDir.State = 1 Then
+ TextBoxText = sSOURCEDIR &amp; &quot; &quot; &amp; ConvertFromUrl(Source) &amp; chr(13)
+ If DialogModel.chkRecursive.State = 1 Then
+ TextBoxText = TextBoxText &amp; DeleteStr(sInclusiveSubDir,&quot;~&quot;) &amp; chr(13)
+ End If
+ Else
+ TextBoxText = sSOURCEFILE &amp; &quot; &quot; &amp; ConvertFromUrl(Source) &amp; chr(13)
+ End If
+ TextBoxText = TextBoxText &amp; sTARGETDIR &amp; &quot; &quot; &amp; ConvertFromUrl(TargetDir) &amp; chr(13)
+ If DialogModel.chkProtect.State = 1 Then
+ TextBoxText = TextboxText &amp; sPrgsUNPROTECT
+ End If
+ DialogModel.txtConfig.Text = TextBoxText
+ ToggleProgressStep()
+ DialogModel.cmdGoOn.Enabled = False
+ InitializeThirdStep() = True
+ Else
+ InitializeThirdStep() = False
+ End If
+End Function
+
+
+Sub ToggleProgressStep(Optional aEvent as Object)
+Dim bMakeVisible as Boolean
+Dim LocStep as Integer
+ &apos; If the Sub is call by the &apos;cmdBack&apos; Button then set the &apos;bMakeVisible&apos; variable accordingly
+ bMakeVisible = IsMissing(aEvent)
+ If bMakeVisible Then
+ DialogModel.Step = 3
+ Else
+ DialogModel.Step = 2
+ End If
+ DialogConvert.GetControl(&quot;lblCurrencies&quot;).Visible = Not bMakeVisible
+ DialogConvert.GetControl(&quot;lstCurrencies&quot;).Visible = Not bMakeVisible
+ DialogConvert.GetControl(&quot;cmdBack&quot;).Visible = bMakeVisible
+ DialogConvert.GetControl(&quot;cmdGoOn&quot;).Visible = bMakeVisible
+ DialogModel.imgPreview.ImageUrl = BitmapDir &amp; &quot;euro_&quot; &amp; DialogModel.Step &amp; &quot;.png&quot;
+End Sub
+
+
+Sub EnableStep2DialogControls(OnValue as Boolean)
+ With DialogModel
+ .hlnExtent.Enabled = OnValue
+ .optWholeDir.Enabled = OnValue
+ .optSingleFile.Enabled = OnValue
+ .chkProtect.Enabled = OnValue
+ .cmdCallSourceDialog.Enabled = OnValue
+ .cmdCallTargetDialog.Enabled = OnValue
+ .lblSource.Enabled = OnValue
+ .lblTarget.Enabled = OnValue
+ .txtSource.Enabled = OnValue
+ .txtTarget.Enabled = OnValue
+ .imgPreview.Enabled = OnValue
+ .lstCurrencies.Enabled = OnValue
+ .lblCurrencies.Enabled = OnValue
+ If OnValue Then
+ ToggleGoOnButton()
+ .chkRecursive.Enabled = .optWholeDir.State = 1
+ Else
+ .cmdGoOn.Enabled = False
+ .chkRecursive.Enabled = False
+ End If
+ End With
+End Sub
+
+
+Sub InitializeProgressPage()
+ DialogConvert.GetControl(&quot;lblRetrieval&quot;).Visible = False
+ DialogConvert.GetControl(&quot;lblCurProgress&quot;).Visible = False
+ DialogModel.lblRetrieval.FontWeight = com.sun.star.awt.FontWeight.NORMAL
+ DialogModel.lblCurProgress.FontWeight = com.sun.star.awt.FontWeight.BOLD
+ DialogConvert.GetControl(&quot;lblRetrieval&quot;).Visible = True
+ DialogConvert.GetControl(&quot;lblCurProgress&quot;).Visible = True
+End Sub
+
+
+Function AssignFileName(sPath as String, ByVal HeaderString, bCheckFileType as Boolean) as String
+Dim bIsValid as Boolean
+Dim sLocMimeType as String
+Dim sNoDirMessage as String
+ HeaderString = DeleteStr(HeaderString, &quot;:&quot;)
+ sPath = ConvertToUrl(Trim(sPath))
+ bIsValid = oUcb.Exists(sPath)
+ If bIsValid Then
+ If DialogModel.optSingleFile.State = 1 Then
+ If bCheckFileType Then
+ sLocMimeType = GetRealFileContent(sPath)
+ If DialogModel.chkTextDocuments.State = 1 Then
+ If (Instr(1, sLocMimeType, &quot;text&quot;) = 0) And (Instr(1, sLocMimeType, &quot;calc&quot;) = 0) Then
+ Msgbox(sMsgFileInvalid, 48, sMsgDLGTITLE)
+ bIsValid = False
+ End If
+ Else
+ If (Instr(1, sLocMimeType, &quot;spreadsheet&quot;) = 0) And (Instr(1, sLocMimeType, &quot;calc&quot;)) = 0 Then
+ Msgbox(sMsgFileInvalid, 48, sMsgDLGTITLE)
+ bIsValid = False
+ End If
+ End If
+ End If
+ Else
+ If Not oUcb.IsFolder(sPath) Then
+ sNoDirMessage = ReplaceString(sMsgNODIRECTORY,sPath,&quot;&lt;1&gt;&quot;)
+ Msgbox(sNoDirMessage,48, sMsgDLGTITLE)
+ bIsValid = False
+ Else
+ sPath = RTrimStr(sPath,&quot;/&quot;)
+ sPath = sPath &amp; &quot;/&quot;
+ End If
+ End if
+ Else
+ Msgbox(HeaderString &amp; &quot; &apos;&quot; &amp; ConvertFromUrl(sPath) &amp; &quot;&apos; &quot; &amp; sMsgNOTTHERE,48, sMsgDLGTITLE)
+ End If
+ If bIsValid Then
+ AssignFileName() = sPath
+ Else
+ AssignFilename() = &quot;&quot;
+ End If
+End Function
+
+
+Sub ToggleGoOnButton()
+Dim bDoEnable as Boolean
+Dim sLocMimeType as String
+Dim sPath as String
+ bDoEnable = Ubound(DialogModel.lstCurrencies.SelectedItems()) &gt; -1
+ If bDoEnable Then
+ &apos; Check if Source is set correctly
+ sPath = ConvertToUrl(Trim(DialogModel.txtSource.Text))
+ bDoEnable = oUcb.Exists(sPath)
+ End If
+ DialogModel.cmdGoOn.Enabled = bDoEnable
+End Sub
+
+
+Sub CallFolderPicker()
+ GetFolderName(DialogModel.txtTarget)
+ ToggleGoOnButton()
+End Sub
+
+
+Sub CallFilePicker()
+ If DialogModel.optSingleFile.State = 1 Then
+ Dim oMasterKey as Object
+ Dim oTypes() as Object
+ Dim oUIKey() as Object
+
+ oMasterKey = GetRegistryKeyContent(&quot;org.openoffice.TypeDetection.Types&quot;)
+ oTypes() = oMasterKey.Types
+ oUIKey = GetRegistryKeyContent(&quot;org.openoffice.Office.UI/FilterClassification/LocalFilters&quot;)
+ If DialogModel.chkTextDocuments.State = 1 Then
+ Dim FilterNames(7,1) as String
+ FilterNames(4,0) = oTypes.GetByName(&quot;writer_StarOffice_XML_Writer&quot;).UIName
+ FilterNames(4,1) = &quot;*.sxw&quot;
+ FilterNames(5,0) = oTypes.GetByName(&quot;writer_StarOffice_XML_Writer_Template&quot;).UIName
+ FilterNames(5,1) = &quot;*.stw&quot;
+ FilterNames(6,0) = oTypes.GetByName(&quot;writer8&quot;).UIName
+ FilterNames(6,1) = &quot;*.odt&quot;
+ FilterNames(7,0) = oTypes.GetByName(&quot;writer8_template&quot;).UIName
+ FilterNames(7,1) = &quot;*.ott&quot;
+ Else
+ ReDim FilterNames(3,1) as String
+ End If
+ FilterNames(0,0) = oTypes.GetByName(&quot;calc8&quot;).UIName
+ Filternames(0,1) = &quot;*.ods&quot;
+ FilterNames(1,0) = oTypes.GetByName(&quot;calc8_template&quot;).UIName
+ Filternames(1,1) = &quot;*.ots&quot;
+ FilterNames(2,0) = oTypes.GetByName(&quot;calc_StarOffice_XML_Calc&quot;).UIName
+ Filternames(2,1) = &quot;*.sxc&quot;
+ FilterNames(3,0) = oTypes.GetByName(&quot;calc_StarOffice_XML_Calc_Template&quot;).UIName
+ Filternames(3,1) = &quot;*.stc&quot;
+ GetFileName(DialogModel.txtSource, Filternames())
+ Else
+ GetFolderName(DialogModel.txtSource)
+ End If
+ ToggleGoOnButton()
+End Sub
+
+
+Sub PreviousStep()
+ DialogModel.Step = 2
+ DialogModel.cmdGoOn.Label = sGOON
+ DialogModel.cmdCancel.Label = sCANCEL
+End Sub
+</script:module>
diff --git a/wizards/source/euro/Common.xba b/wizards/source/euro/Common.xba
new file mode 100644
index 000000000..550042ee9
--- /dev/null
+++ b/wizards/source/euro/Common.xba
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Common" script:language="StarBasic"> REM ***** BASIC *****
+Public DialogModel as Object
+Public DialogConvert as Object
+Public DialogPassword as Object
+Public PasswordModel as Object
+
+Sub RetrieveDocumentObjects()
+ CurMimeType = Tools.GetDocumentType(oDocument)
+ If Instr(1, CurMimeType, &quot;calc&quot;) &lt;&gt; 0 Then
+ oSheets = oDocument.Sheets
+ oSheet = oDocument.Sheets.GetbyIndex(0)
+ oAddressRanges = oDocument.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ End If
+ &apos; Retrieve the indices for the cellformatations
+ oFormats = oDocument.NumberFormats
+End Sub
+
+
+Sub CancelTask()
+&apos; If Not DocDisposed Then
+&apos; ReprotectSheets()
+&apos; End If
+ If DialogModel.Step = 3 And (Not bCancelTask) Then
+ If Msgbox(sMsgCancelConversion, 36, sMsgCancelTitle) = 6 Then
+ bCancelTask = True
+ DialogConvert.EndExecute
+ Else
+ bCancelTask = False
+ End If
+ Else
+ DialogConvert.EndExecute()
+ End If
+End Sub
+
+
+Function ConvertDocument()
+ GoOn = True
+&apos; DocDisposed = True
+ InitializeProgressbar()
+ If Instr(1, CurMimeType, &quot;calc&quot;) &lt;&gt; 0 Then
+ bDocHasProtectedSheets = CheckSheetProtection(oSheets)
+ If bDocHasProtectedSheets Then
+ bDocHasProtectedSheets = UnprotectSheetsWithPassword(oSheets, bDoUnProtect)
+ End If
+ If Not bDocHasProtectedSheets Then
+ If Not bRangeListDefined Then
+ TotCellCount = 0
+ CreateRangeEnumeration(True)
+ Else
+ IncreaseStatusvalue(SBRelGet/3)
+ End If
+ RangeIndex = Ubound(RangeList())
+ If RangeIndex &gt; -1 Then
+ ConvertThehardWay(RangeList(), True, False)
+ MakeStyleEnumeration(True)
+ oDocument.calculateAll()
+ End If
+ ReprotectSheets()
+ bRangeListDefined = False
+ End If
+ Else
+ DialogModel.ProgressBar.ProgressValue = 10 &apos; oStatusline.SetValue(10)
+ ConvertTextFields()
+ DialogModel.ProgressBar.ProgressValue = 80 &apos; oStatusline.SetValue(80)
+ ConvertWriterTables()
+ End If
+ EndStatusLine()
+ On Local Error Goto 0
+End Function
+
+
+Sub SwitchNumberFormat(oObject as Object, oFormats as object)
+Dim nFormatLanguage as Integer
+Dim nFormatDecimals as Integer
+Dim nFormatLeading as Integer
+Dim bFormatLeading as Integer
+Dim bFormatNegRed as Integer
+Dim bFormatThousands as Integer
+Dim i as Integer
+Dim aNewStr as String
+Dim iNumberFormat as Long
+Dim AddToList as Boolean
+Dim sOldCurrSymbol as String
+ On Local Error Resume Next
+ iNumberFormat = oObject.NumberFormat
+ On Local Error GoTo NOKEY
+ aFormat() = oFormats.getByKey(iNumberFormat)
+ On Local Error GoTo 0
+ sOldCurrSymbol = aFormat.CurrencySymbol
+ If sOldCurrSymbol = CurrValue(CurrIndex,5) Then
+ aSimpleStr = &quot;0 [$EUR]&quot;
+ Else
+ aSimpleStr = &quot;0 [$&quot; &amp; sEuroSign &amp; aFormat.CurrencyExtension &amp; &quot;]&quot;
+ End If
+
+ nSimpleKey = Numberformat(oFormats, aSimpleStr, oLocale)
+ &apos; set new Currency format with according settings
+ nFormatDecimals = 2
+ nFormatLeading = aFormat.LeadingZeros
+ bFormatNegRed = aFormat.NegativeRed
+ bFormatThousands = aFormat.ThousandsSeparator
+ aNewStr = oFormats.generateFormat( nSimpleKey, aFormat.Locale, bFormatThousands, bFormatNegRed, nFormatDecimals, nFormatLeading)
+ oObject.NumberFormat = Numberformat(oFormats, aNewStr, aFormat.Locale)
+ NOKEY:
+ If Err &lt;&gt; 0 Then
+ Resume CLERROR
+ End If
+ CLERROR:
+End Sub
+
+
+Function Numberformat( oFormats as Object, aFormatStr as String, oLocale as Object)
+Dim nRetkey
+Dim l as String
+Dim c as String
+ nRetKey = oFormats.queryKey( aFormatStr, oLocale, True )
+ If nRetKey = -1 Then
+ l = oLocale.Language
+ c = oLocale.Country
+ nRetKey = oFormats.addNew( aFormatStr, oLocale )
+ If nRetKey = -1 Then nRetKey = 0
+ End If
+ Numberformat = nRetKey
+End Function
+
+
+Function CheckFormatType( FormatObject as object)
+Dim i as Integer
+Dim LocCurrIndex as Integer
+Dim nFormatFormatString as String
+Dim FormatLangID as Integer
+Dim sFormatCurrExt as String
+Dim oFormatofObject() as Object
+
+ &apos; Retrieve the Format of the Object
+ On Local Error GoTo NOKEY
+ oFormatofObject = oFormats.getByKey(FormatObject.NumberFormat)
+ On Local Error GoTo 0
+ If NOT INT(oFormatofObject.Type) AND com.sun.star.util.NumberFormat.CURRENCY Then
+ CheckFormatType = False
+ Exit Function
+ End If
+ If FieldInArray(CurrSymbolList(),2,oFormatofObject.CurrencySymbol) Then
+ &apos; If the Currencysymbol of the object is the one needed, then check the Currency extension
+ sFormatCurrExt = oFormatofObject.CurrencyExtension
+
+ If FieldInList(CurExtension(),2,sFormatCurrExt) Then
+ &apos; The Currency - extension also fits
+ CheckFormatType = True
+ Else
+ &apos; The Currency - symbol is Euro-conforming (like &apos;DEM&apos;), so there is no Currency-Extension
+ CheckFormatType = oFormatofObject.CurrencySymbol = CurrsymbolList(2)
+ End If
+ Else
+ &apos; The Currency Symbol of the object is not the desired one
+ If oFormatofObject.CurrencySymbol = &quot;&quot; Then
+ &apos; Format is &quot;automatic&quot;
+ CheckFormatType = CheckLocale(oFormatofObject.Locale)
+ Else
+ CheckFormatType = False
+ End If
+ End If
+
+ NOKEY:
+ If Err &lt;&gt; 0 Then
+ CheckFormatType = False
+ Resume CLERROR
+ End If
+ CLERROR:
+End Function
+
+
+Sub StartConversion()
+ GoOn = True
+ Select Case DialogModel.Step
+ Case 1
+ If DialogModel.chkComplete.State = 1 Then
+ ConvertWholeDocument()
+ Else
+ ConvertRangesorStylesofDocument()
+ End If
+ Case 2
+ bCancelTask = False
+ If InitializeThirdStep() Then
+ ConvertDocuments()
+ bCancelTask = True
+ End If
+ Case 3
+ DialogConvert.EndExecute()
+ End Select
+End Sub
+
+
+Sub IncreaseStatusValue(AddStatusValue as Integer)
+ StatusValue = Int(StatusValue + AddStatusValue)
+ If DialogModel.Step = 3 Then
+ DialogModel.ProgressBar.ProgressValue = StatusValue
+ Else
+ oStatusline.SetValue(StatusValue)
+ End If
+End Sub
+
+
+Sub SelectCurrency()
+Dim AddtoList as Boolean
+Dim NullList()
+Dim OldCurrIndex as Integer
+ bRangeListDefined = False
+ OldCurrIndex = CurrIndex
+ CurrIndex = DialogModel.lstCurrencies.SelectedItems(0)
+ If OldCurrIndex &lt;&gt; CurrIndex Then
+ InitializeCurrencyValues(CurrIndex)
+ CurExtension(0) = LangIDValue(CurrIndex,0,2)
+ CurExtension(1) = LangIDValue(CurrIndex,1,2)
+ CurExtension(2) = LangIDValue(CurrIndex,2,2)
+ If DialogModel.Step = 1 Then
+ EnableStep1DialogControls(False,False, False)
+ If DialogModel.optCellTemplates.State = 1 Then
+ EnableStep1DialogControls(False, False, False)
+ CreateStyleEnumeration()
+ ElseIf ((DialogModel.optSheetRanges.State = 1) OR (DialogModel.optDocRanges.State = 1)) AND (DialogModel.Step = 1) Then
+ CreateRangeEnumeration(False)
+ If Ubound(RangeList()) = -1 Then
+ DialogModel.lstSelection.StringItemList() = NullList()
+ End If
+ ElseIf DialogModel.optSelRange.State= 1 Then
+ &apos;Preselected Range
+ End If
+ EnableStep1DialogControls(True, True, True)
+ ElseIf DialogModel.Step = 2 Then
+ EnableStep2DialogControls(True)
+ End If
+ End If
+End Sub
+
+
+Sub FillUpCurrencyListbox()
+Dim i as Integer
+Dim MaxIndex as Integer
+ MaxIndex = Ubound(CurrValue(),1)
+ Dim LocList(MaxIndex) as String
+ For i = 0 To MaxIndex
+ LocList(i) = CurrValue(i,0)
+ Next i
+ DialogModel.lstCurrencies.StringItemList() = LocList()
+ If CurrIndex &gt; -1 Then
+ SelectListboxItem(DialogModel.lstCurrencies, CurrIndex)
+ End If
+End Sub
+
+
+Sub InitializeProgressbar()
+ CurCellCount = 0
+ If Not IsNull(oStatusLine) Then
+ oStatusline.Start(sStsPROGRESS, 100)
+ Else
+ DialogModel.ProgressBar.ProgressValue = 0
+ End If
+ StatusValue = 0
+End Sub
+
+
+Sub EndStatusLine()
+ If Not IsNull(oStatusLine) Then
+ oStatusline.End
+ Else
+ DialogModel.ProgressBar.ProgressValue = 100
+ End If
+End Sub
+</script:module>
diff --git a/wizards/source/euro/ConvertRun.xba b/wizards/source/euro/ConvertRun.xba
new file mode 100644
index 000000000..e91d12e7a
--- /dev/null
+++ b/wizards/source/euro/ConvertRun.xba
@@ -0,0 +1,334 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ConvertRun" script:language="StarBasic">Option Explicit
+
+Public oPreSelRange as Object
+
+Sub Main()
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ If InitResources(&quot;Euro Converter&quot;) Then
+ bDoUnProtect = False
+ bPreSelected = True
+ oDocument = ThisComponent
+ RetrieveDocumentObjects() &apos; Statusline, SheetsCollection etc.
+ InitializeConverter(oDocument.CharLocale, 1)
+ GetPreSelectedRange()
+ If GoOn Then
+ DialogModel.lstCurrencies.TabIndex = 2
+ DialogConvert.GetControl(&quot;chkComplete&quot;).SetFocus()
+ DialogConvert.Execute
+ End If
+ DialogConvert.Dispose
+ End If
+End Sub
+
+
+Sub SelectListItem()
+Dim Listbox as Object
+Dim oListSheet as Object
+Dim CurStyleName as String
+Dim oCursheet as Object
+Dim oTempRanges as Object
+Dim sCurSheetName as String
+Dim RangeName as String
+Dim oSheetRanges as Object
+Dim ListIndex as Integer
+Dim a as Integer
+Dim i as Integer
+Dim n as Integer
+Dim m as Integer
+Dim MaxIndex as Integer
+ Listbox = DialogModel.lstSelection
+ If Ubound(Listbox.SelectedItems()) &gt; -1 Then
+ EnableStep1DialogControls(False, False, False)
+ oSelRanges = oDocument.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+
+ &apos; Is the sheet the basis, then the sheetobject has to be created
+ If DialogModel.optDocRanges.State = 1 Then
+ &apos; Document is the basis for the conversion
+ ListIndex = Listbox.SelectedItems(0)
+ oCurSheet = RetrieveSheetoutofRangeName(Listbox.StringItemList(ListIndex))
+ oDocument.CurrentController.SetActiveSheet(oCurSheet)
+ Else
+ oCurSheet = oDocument.CurrentController.ActiveSheet
+ End If
+ sCurSheetName = oCurSheet.Name
+ If DialogModel.optCellTemplates.State = 1 Then
+ Dim CurIndex as Integer
+ For i = 0 To Ubound(Listbox.SelectedItems())
+ CurIndex = Listbox.SelectedItems(i)
+ CurStylename = Listbox.StringItemList(CurIndex)
+ oSheetRanges = oCursheet.CellFormatRanges.createEnumeration
+ While oSheetRanges.hasMoreElements
+ oRange = oSheetRanges.NextElement
+ If oRange.getPropertyState(&quot;NumberFormat&quot;) = 1 Then
+ If oRange.CellStyle = CurStyleName Then
+ oSelRanges.InsertbyName(&quot;&quot;,oRange)
+ End If
+ End If
+ Wend
+ Next i
+ Else
+ &apos; Hard Formatation is selected
+ a = -1
+ For n = 0 To Ubound(Listbox.SelectedItems())
+ m = Listbox.SelectedItems(n)
+ RangeName = Listbox.StringItemList(m)
+ oListSheet = RetrieveSheetoutofRangeName(RangeName)
+ a = a + 1
+ MaxIndex = Ubound(SelRangeList())
+ If a &gt; MaxIndex Then
+ Redim Preserve SelRangeList(MaxIndex + SBRANGEUBOUND)
+ End If
+ SelRangeList(a) = RangeName
+ If oListSheet.Name = sCurSheetName Then
+ oRange = RetrieveRangeoutofRangeName(RangeName)
+ oSelRanges.InsertbyName(&quot;&quot;,oRange)
+ End If
+ Next n
+ End If
+ If a &gt; -1 Then
+ ReDim Preserve SelRangeList(a)
+ Else
+ ReDim SelRangeList()
+ End If
+ oDocument.CurrentController.Select(oSelRanges)
+ EnableStep1DialogControls(True, True, True)
+ End If
+End Sub
+
+
+&apos; Procedure that is called by an event
+Sub RetrieveEnableValue()
+Dim EnableValue as Boolean
+ EnableValue = Not DialogModel.lstSelection.Enabled
+ EnableStep1DialogControls(True, EnableValue, True)
+End Sub
+
+
+Sub EnableStep1DialogControls(bCurrEnabled as Boolean, bFrameEnabled as Boolean, bButtonsEnabled as Boolean)
+Dim bCurrIsSelected as Boolean
+Dim bObjectIsSelected as Boolean
+Dim bConvertWholeDoc as Boolean
+Dim bDoEnableFrame as Boolean
+ bConvertWholeDoc = DialogModel.chkComplete.State = 1
+ bDoEnableFrame = bFrameEnabled And (NOT bConvertWholeDoc)
+
+ &apos; Controls around the Selection Listbox
+ With DialogModel
+ .lblCurrencies.Enabled = bCurrEnabled
+ .lstCurrencies.Enabled = bCurrEnabled
+ .lstSelection.Enabled = bDoEnableFrame
+ .lblSelection.Enabled = bDoEnableFrame
+ .hlnSelection.Enabled = bDoEnableFrame
+ .optCellTemplates.Enabled = bDoEnableFrame
+ .optSheetRanges.Enabled = bDoEnableFrame
+ .optDocRanges.Enabled = bDoEnableFrame
+ .optSelRange.Enabled = bDoEnableFrame
+ End With
+ &apos; The CheckBox has the Value &apos;1&apos; when the Controls in the Frame are disabled
+ If bButtonsEnabled Then
+ bCurrIsSelected = Ubound(DialogModel.lstCurrencies.SelectedItems()) &lt;&gt; -1
+ &apos; Enable GoOnButton only when Currency is selected
+ DialogModel.cmdGoOn.Enabled = bCurrIsSelected
+ DialogModel.chkComplete.Enabled = bCurrIsSelected
+ If bDoEnableFrame AND DialogModel.cmdGoOn.Enabled Then
+ &apos; If FrameControls are enabled, check if Listbox is Empty
+ bObjectIsSelected = Ubound(DialogModel.lstSelection.SelectedItems()) &lt;&gt; -1
+ DialogModel.cmdGoOn.Enabled = bObjectIsSelected
+ End If
+ Else
+ DialogModel.cmdGoOn.Enabled = False
+ DialogModel.chkComplete.Enabled = False
+ End If
+End Sub
+
+
+Sub ConvertRangesOrStylesOfDocument()
+Dim i as Integer
+Dim ItemName as String
+Dim SelList() as String
+Dim oSheetRanges as Object
+
+ bDocHasProtectedSheets = CheckSheetProtection(oSheets)
+ If bDocHasProtectedSheets Then
+ bDocHasProtectedSheets = UnprotectSheetsWithPassWord(oSheets, bDoUnProtect)
+ DialogModel.cmdGoOn.Enabled = False
+ End If
+ If Not bDocHasProtectedSheets Then
+ EnableStep1DialogControls(False, False, False)
+ InitializeProgressBar()
+ If DialogModel.optSelRange.State = 1 Then
+ SelectListItem()
+ End If
+ SelList() = DialogConvert.GetControl(&quot;lstSelection&quot;).SelectedItems()
+ If DialogModel.optCellTemplates.State = 1 Then
+ &apos; Option &apos;Soft&apos; Formatation is selected
+ AssignRangestoStyle(DialogModel.lstSelection.StringItemList(), SelList())
+ ConverttheSoftWay(SelList(), True)
+ ElseIf DialogModel.optSelRange.State = 1 Then
+ oSheetRanges = oPreSelRange.CellFormatRanges.createEnumeration
+ While oSheetRanges.hasMoreElements
+ oRange = oSheetRanges.NextElement
+ If CheckFormatType(oRange) Then
+ ConvertCellCurrencies(oRange)
+ SwitchNumberFormat(oRange, oFormats, sEuroSign)
+ End If
+ Wend
+ Else
+ ConverttheHardWay(SelList(), False, True)
+ End If
+ oStatusline.End
+ EnableStep1DialogControls(True, False, True)
+ DialogModel.cmdGoOn.Enabled = True
+ oDocument.CurrentController.Select(oSelRanges)
+ End If
+End Sub
+
+
+Sub ConvertWholeDocument()
+Dim s as Integer
+ DialogModel.cmdGoOn.Enabled = False
+ DialogModel.chkComplete.Enabled = False
+ GoOn = ConvertDocument()
+ EmptyListbox(DialogModel.lstSelection())
+ EnableStep1DialogControls(True, True, True)
+End Sub
+
+
+&apos; Everything previously selected will be deselected
+Sub EmptySelection()
+Dim RangeName as String
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim EmptySelRangeList() as String
+
+ If Not IsNull(oSelRanges) Then
+ If oSelRanges.HasElements Then
+ EmptySelRangeList() = ArrayOutofString(oSelRanges.RangeAddressesasString, &quot;;&quot;, MaxIndex)
+ For i = 0 To MaxIndex
+ oSelRanges.RemovebyName(EmptySelRangeList(i))
+ Next i
+ End If
+ oDocument.CurrentController.Select(oSelRanges)
+ Else
+ oSelRanges = oDocument.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ End If
+End Sub
+
+
+Function AddSelectedRangeToSelRangesEnum() as Object
+Dim oLocRange as Object
+ osheet = oDocument.CurrentController.GetActiveSheet
+ oSelRanges = oDocument.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ &apos; Check if a Currency-Range has been selected
+ oLocRange = oDocument.CurrentController.Selection
+ bPreSelected = oLocRange.SupportsService(&quot;com.sun.star.sheet.SheetCellRange&quot;)
+ If bPreSelected Then
+ oSelRanges.InsertbyName(&quot;&quot;,oLocRange)
+ AddSelectedRangeToSelRangesEnum() = oLocRange
+ End If
+End Function
+
+
+Sub GetPreSelectedRange()
+Dim i as Integer
+Dim OldCurrSymbolList(2) as String
+Dim OldCurrIndex as Integer
+Dim OldCurExtension(2) as String
+ oPreSelRange = AddSelectedRangeToSelRangesEnum()
+
+ DialogModel.chkComplete.State = Abs(Not(bPreSelected))
+ If bPreSelected Then
+ DialogModel.optSelRange.State = 1
+ AddRangeToListbox(oPreSelRange)
+ Else
+ DialogModel.optCellTemplates.State = 1
+ CreateStyleEnumeration()
+ End If
+ EnableStep1DialogControls(True, bPreSelected, True)
+ DialogModel.optSelRange.Enabled = bPreSelected
+End Sub
+
+
+Sub AddRangeToListbox(oLocRange as Object)
+ EmptyListBox(DialogModel.lstSelection)
+ PreName = RetrieveRangeNamefromAddress(oLocRange)
+ AddSingleItemToListbox(DialogModel.lstSelection, Prename)&apos;, 0)
+ SelectListboxItem(DialogModel.lstCurrencies, CurrIndex)
+ TotCellCount = CountRangeCells(oLocRange)
+End Sub
+
+
+Sub CheckRangeSelection(Optional oEvent)
+ EmptySelection()
+ AddRangeToListbox(oPreSelRange)
+ oPreSelRange = AddSelectedRangeToSelRangesEnum()
+End Sub
+
+
+&apos; Checks if a Field (LocField) is already defined in an Array
+&apos; Returns &apos;True&apos; or &apos;False&apos;
+Function FieldInList(LocList(), MaxIndex as integer, ByVal LocField ) As Boolean
+Dim i as integer
+ LocField = UCase(LocField)
+ For i = Lbound(LocList()) to MaxIndex
+ If UCase(LocList(i)) = LocField then
+ FieldInList = True
+ Exit Function
+ End if
+ Next
+ FieldInList = False
+End Function
+
+
+Function CheckLocale(oLocale) as Boolean
+Dim i as Integer
+Dim LocCountry as String
+Dim LocLanguage as String
+ LocCountry = oLocale.Country
+ LocLanguage = oLocale.Language
+ For i = 0 To 1
+ If LocLanguage = LangIDValue(CurrIndex,i,0) AND LocCountry = LangIDValue(CurrIndex,i,1) Then
+ CheckLocale = True
+ Exit Function
+ End If
+ Next i
+ CheckLocale = False
+End Function
+
+
+Sub SetOptionValuestoNull()
+ With DialogModel
+ .optCellTemplates.State = 0
+ .optSheetRanges.State = 0
+ .optDocRanges.State = 0
+ .optSelRange.State = 0
+ End With
+End Sub
+
+
+
+Sub SetStatusLineText(sStsREPROTECT as String)
+ If Not IsNull(oStatusLine) Then
+ oStatusline.SetText(sStsREPROTECT)
+ End If
+End Sub
+</script:module>
diff --git a/wizards/source/euro/DlgConvert.xdl b/wizards/source/euro/DlgConvert.xdl
new file mode 100644
index 000000000..ff3f523a7
--- /dev/null
+++ b/wizards/source/euro/DlgConvert.xdl
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="DialogConvert" dlg:left="96" dlg:top="28" dlg:width="270" dlg:height="210" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_DIALOG" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblCurrencies" dlg:tab-index="1" dlg:left="170" dlg:top="39" dlg:width="92" dlg:height="8" dlg:value="lblCurrencies"/>
+ <dlg:checkbox dlg:id="chkComplete" dlg:tab-index="0" dlg:left="12" dlg:top="43" dlg:width="129" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CHECKBOX1" dlg:value="chkComplete" dlg:checked="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Euro.ConvertRun.RetrieveEnableValue?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:checkbox>
+ <dlg:menulist dlg:id="lstCurrencies" dlg:tab-index="2" dlg:left="170" dlg:top="51" dlg:width="93" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_COMBOBOX1" dlg:spin="true" dlg:linecount="12">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Euro.Common.SelectCurrency?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optCellTemplates" dlg:tab-index="3" dlg:left="12" dlg:top="96" dlg:width="129" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_OPTIONBUTTON1" dlg:value="optCellTemplates">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Soft.CreateStyleEnumeration?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optSheetRanges" dlg:tab-index="4" dlg:left="12" dlg:top="110" dlg:width="130" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_OPTIONBUTTON2" dlg:value="optSheetRanges">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Hard.CreateRangeList?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optDocRanges" dlg:tab-index="5" dlg:left="12" dlg:top="124" dlg:width="130" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_OPTIONBUTTON3" dlg:value="optDocRanges">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Hard.CreateRangeList?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optSelRange" dlg:tab-index="6" dlg:left="12" dlg:top="138" dlg:width="130" dlg:height="10" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_OPTIONBUTTON4" dlg:value="optSelRange">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.ConvertRun.CheckRangeSelection?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:text dlg:id="lblSelection" dlg:tab-index="7" dlg:left="170" dlg:top="84" dlg:width="73" dlg:height="8" dlg:page="1" dlg:value="lblSelection"/>
+ <dlg:menulist dlg:id="lstSelection" dlg:tab-index="8" dlg:left="170" dlg:top="96" dlg:width="90" dlg:height="52" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_LISTBOX1" dlg:multiselection="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Euro.ConvertRun.SelectListItem?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optSingleFile" dlg:tab-index="9" dlg:left="12" dlg:top="51" dlg:width="146" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_OBFILE" dlg:value="optSingleFile">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.AutoPilotRun.SwapExtent?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optWholeDir" dlg:tab-index="10" dlg:left="12" dlg:top="65" dlg:width="146" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_OBDIR" dlg:value="optWholeDir" dlg:checked="true">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.AutoPilotRun.SwapExtent?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:textfield dlg:id="txtConfig" dlg:tab-index="11" dlg:left="6" dlg:top="50" dlg:width="258" dlg:height="55" dlg:page="3" dlg:vscroll="true" dlg:multiline="true" dlg:readonly="true"/>
+ <dlg:textfield dlg:id="txtSource" dlg:tab-index="12" dlg:left="80" dlg:top="82" dlg:width="165" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_TBSOURCE">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:Euro.AutoPilotRun.ToggleGoOnButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:textfield>
+ <dlg:button dlg:id="cmdCallSourceDialog" dlg:tab-index="13" dlg:left="249" dlg:top="81" dlg:width="15" dlg:height="14" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CBSOURCEOPEN" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.AutoPilotRun.CallFilePicker?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:checkbox dlg:id="chkRecursive" dlg:tab-index="14" dlg:left="12" dlg:top="98" dlg:width="252" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CHECKRECURSIVE" dlg:value="chkRecursive" dlg:checked="false"/>
+ <dlg:checkbox dlg:id="chkTextDocuments" dlg:tab-index="15" dlg:left="12" dlg:top="112" dlg:width="251" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CHKTEXTDOCUMENTS" dlg:value="chkTextDocuments" dlg:checked="false"/>
+ <dlg:checkbox dlg:id="chkProtect" dlg:tab-index="16" dlg:left="12" dlg:top="126" dlg:width="251" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CHKPROTECT" dlg:value="chkProtect" dlg:checked="false"/>
+ <dlg:textfield dlg:id="txtTarget" dlg:tab-index="17" dlg:left="80" dlg:top="143" dlg:width="165" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_TBTARGET"/>
+ <dlg:button dlg:id="cmdCallTargetDialog" dlg:tab-index="18" dlg:left="249" dlg:top="142" dlg:width="15" dlg:height="14" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CBTARGETOPEN" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.AutoPilotRun.CallFolderPicker?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:progressmeter dlg:id="ProgressBar" dlg:tab-index="19" dlg:left="85" dlg:top="152" dlg:width="179" dlg:height="10" dlg:page="3"/>
+ <dlg:text dlg:id="lblHint" dlg:tab-index="20" dlg:left="6" dlg:top="166" dlg:width="258" dlg:height="20" dlg:value="lblHint" dlg:multiline="true"/>
+ <dlg:text dlg:id="lblTarget" dlg:tab-index="21" dlg:left="6" dlg:top="145" dlg:width="73" dlg:height="8" dlg:page="2" dlg:value="lblTarget"/>
+ <dlg:text dlg:id="lblSource" dlg:tab-index="22" dlg:left="6" dlg:top="84" dlg:width="73" dlg:height="8" dlg:page="2" dlg:value="lblSource"/>
+ <dlg:text dlg:id="lblCurProgress" dlg:tab-index="23" dlg:left="16" dlg:top="130" dlg:width="208" dlg:height="8" dlg:page="3"/>
+ <dlg:text dlg:id="lblRetrieval" dlg:tab-index="24" dlg:left="9" dlg:top="119" dlg:width="216" dlg:height="8" dlg:page="3" dlg:value="lblRetrieval"/>
+ <dlg:text dlg:id="lblConfig" dlg:tab-index="25" dlg:left="6" dlg:top="39" dlg:width="94" dlg:height="8" dlg:page="3" dlg:value="lblConfig"/>
+ <dlg:text dlg:id="lblCurDocument" dlg:tab-index="26" dlg:left="16" dlg:top="141" dlg:width="208" dlg:height="8" dlg:page="3"/>
+ <dlg:img dlg:id="imgPreview" dlg:tab-index="27" dlg:left="6" dlg:top="6" dlg:width="258" dlg:height="26"/>
+ <dlg:fixedline dlg:id="hlnSelection" dlg:tab-index="28" dlg:left="7" dlg:top="72" dlg:width="258" dlg:height="8" dlg:page="1" dlg:value="hlnSelection"/>
+ <dlg:fixedline dlg:id="hlnExtent" dlg:tab-index="29" dlg:left="6" dlg:top="39" dlg:width="156" dlg:height="8" dlg:page="2" dlg:value="hlnExtent"/>
+ <dlg:fixedline dlg:id="hlnProgress" dlg:tab-index="30" dlg:left="6" dlg:top="108" dlg:width="258" dlg:height="8" dlg:page="3" dlg:value="hlnProgress"/>
+ <dlg:fixedline dlg:id="FixedLine1" dlg:tab-index="31" dlg:left="6" dlg:top="152" dlg:width="258" dlg:height="9" dlg:page="1"/>
+ <dlg:text dlg:id="lblProgress" dlg:tab-index="32" dlg:left="6" dlg:top="153" dlg:width="79" dlg:height="8" dlg:page="3" dlg:value="lblProgress"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="33" dlg:left="6" dlg:top="190" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CBCANCEL" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Common.CancelTask?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdHelp" dlg:tab-index="34" dlg:left="63" dlg:top="190" dlg:width="53" dlg:height="14" dlg:value="cmdHelp" dlg:button-type="help"/>
+ <dlg:button dlg:id="cmdBack" dlg:tab-index="35" dlg:left="155" dlg:top="190" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CBBACK" dlg:value="cmdBack">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.AutoPilotRun.PreviousStep?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="36" dlg:left="211" dlg:top="190" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGCONVERT_CBGOON" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Common.StartConversion?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ </dlg:bulletinboard>
+</dlg:window>
diff --git a/wizards/source/euro/DlgPassword.xdl b/wizards/source/euro/DlgPassword.xdl
new file mode 100644
index 000000000..20beac046
--- /dev/null
+++ b/wizards/source/euro/DlgPassword.xdl
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="DlgPassword" dlg:left="77" dlg:top="93" dlg:width="310" dlg:height="65" dlg:closeable="true" dlg:moveable="true" dlg:title="DlgPassword">
+ <dlg:bulletinboard>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="0" dlg:left="251" dlg:top="6" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGPASSWORD_CMDGOON" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Protect.ReadPassword?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="1" dlg:left="251" dlg:top="24" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGPASSWORD_CMDCANCEL" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Euro.Protect.RejectPassword?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdHelp" dlg:tab-index="2" dlg:left="251" dlg:top="45" dlg:width="53" dlg:height="14" dlg:tag="34692" dlg:value="cmdHelp" dlg:button-type="help"/>
+ <dlg:textfield dlg:id="txtPassword" dlg:tab-index="3" dlg:left="11" dlg:top="18" dlg:width="232" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGPASSWORD_TXTPASSWORD" dlg:echochar="*"/>
+ <dlg:fixedline dlg:id="hlnPassword" dlg:tab-index="4" dlg:left="6" dlg:top="6" dlg:width="238" dlg:height="8" dlg:value="hlnPassword"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/euro/Hard.xba b/wizards/source/euro/Hard.xba
new file mode 100644
index 000000000..467225dec
--- /dev/null
+++ b/wizards/source/euro/Hard.xba
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Hard" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+
+
+Sub CreateRangeList()
+Dim MaxIndex as Integer
+ MaxIndex = -1
+ EnableStep1DialogControls(False, False, False)
+ EmptySelection()
+ DialogModel.lblSelection.Label = sCURRRANGES
+ EmptyListbox(DialogModel.lstSelection)
+ oDocument.CurrentController.Select(oSelRanges)
+ If (DialogModel.optSheetRanges.State = 1) AND (DialogModel.chkComplete.State &lt;&gt; 1) Then
+ &apos; Conversion on a sheet?
+ SetStatusLineText(sStsRELRANGES)
+ osheet = oDocument.CurrentController.GetActiveSheet
+ oRanges = osheet.CellFormatRanges.createEnumeration()
+ MaxIndex = AddSheetRanges(oRanges, MaxIndex, oSheet, False)
+ If MaxIndex &gt; -1 Then
+ ReDim Preserve RangeList(MaxIndex)
+ End If
+ Else
+ CreateRangeEnumeration(False)
+ bRangeListDefined = True
+ End If
+ EnableStep1DialogControls(True, True, True)
+ SetStatusLineText(&quot;&quot;)
+End Sub
+
+
+Sub CreateRangeEnumeration(bAutopilot as Boolean)
+Dim i as Integer
+Dim MaxIndex as integer
+Dim sStatustext as String
+ MaxIndex = -1
+ If Not bRangeListDefined Then
+ &apos; Cellranges are not yet defined
+ oSheets = oDocument.Sheets
+ For i = 0 To oSheets.Count-1
+ oSheet = oSheets.GetbyIndex(i)
+ If bAutopilot Then
+ IncreaseStatusValue(SBRELGET/osheets.Count)
+ Else
+ sStatustext = ReplaceString(sStsRELSHEETRANGES,Str(i+1),&quot;%1Number%1&quot;)
+ sStatustext = ReplaceString(sStatusText,oSheets.Count,&quot;%2TotPageCount%2&quot;)
+ SetStatusLineText(sStatusText)
+ End If
+ oRanges = osheet.CellFormatRanges.createEnumeration
+ MaxIndex = AddSheetRanges(oRanges, MaxIndex, oSheet, bAutopilot)
+ Next i
+ Else
+ If Not bAutoPilot Then
+ SetStatusLineText(sStsRELRANGES)
+ &apos; cellranges already defined
+ For i = 0 To Ubound(RangeList())
+ If RangeList(i) &lt;&gt; &quot;&quot; Then
+ AddSingleItemToListBox(DialogModel.lstSelection, RangeList(i))
+ End If
+ Next
+ End If
+ End If
+ If MaxIndex &gt; -1 Then
+ ReDim Preserve RangeList(MaxIndex)
+ Else
+ ReDim RangeList()
+ End If
+ Rangeindex = MaxIndex
+End Sub
+
+
+Function AddSheetRanges(oRanges as Object, r as Integer, oSheet as Object, bAutopilot)
+Dim RangeName as String
+Dim AddtoList as Boolean
+Dim iCurStep as Integer
+Dim MaxIndex as Integer
+ iCurStep = DialogModel.Step
+ While oRanges.hasMoreElements
+ oRange = oRanges.NextElement
+ AddToList = CheckFormatType(oRange)
+ If AddToList Then
+ RangeName = RetrieveRangeNamefromAddress(oRange)
+ TotCellCount = TotCellCount + CountRangeCells(oRange)
+ If Not bAutoPilot Then
+ AddSingleItemToListbox(DialogModel.lstSelection, RangeName)
+ End If
+ &apos; The Ranges are only passed to an Array when the whole Document is the basis
+ &apos; Redimension the RangeList Array if necessary
+ MaxIndex = Ubound(RangeList())
+ r = r + 1
+ If r &gt; MaxIndex Then
+ MaxIndex = MaxIndex + SBRANGEUBOUND
+ ReDim Preserve RangeList(MaxIndex)
+ End If
+ RangeList(r) = RangeName
+ End If
+ Wend
+ AddSheetRanges = r
+End Function
+
+
+&apos; adds a section to the collection
+Sub SelectRange()
+Dim i as Integer
+Dim RangeName as String
+Dim SelItem as String
+Dim CurRange as String
+Dim SheetRangeName as String
+Dim DescriptionList() as String
+Dim MaxRangeIndex as Integer
+Dim StatusValue as Integer
+ StatusValue = 0
+ MaxRangeIndex = Ubound(SelRangeList())
+ CurSheetName = oSheet.Name
+ For i = 0 To MaxRangeIndex
+ SelItem = SelRangeList(i)
+ &apos; Is the Range already included in the collection?
+ oRange = RetrieveRangeoutOfRangename(SelItem)
+ TotCellCount = TotCellCount + CountRangeCells(oRange)
+ DescriptionList() = ArrayOutofString(SelItem,&quot;.&quot;,1)
+ SheetRangeName = DeleteStr(DescriptionList(0),&quot;&apos;&quot;)
+ If SheetRangeName = CurSheetName Then
+ oSelRanges.InsertbyName(&quot;&quot;,oRange)
+ End If
+ IncreaseStatusValue(SBRELGET/MaxRangeIndex)
+ Next i
+End Sub
+
+
+Sub ConvertThehardWay(ListboxList(), SwitchFormat as Boolean, bRemove as Boolean)
+Dim i as Integer
+Dim AddCells as Long
+Dim OldStatusValue as Single
+Dim RangeName as String
+Dim LastIndex as Integer
+Dim oSelListbox as Object
+
+ oSelListbox = DialogConvert.GetControl(&quot;lstSelection&quot;)
+ Lastindex = Ubound(ListboxList())
+ If TotCellCount &gt; 0 Then
+ OldStatusValue = StatusValue
+ &apos; hard format
+ For i = 0 To LastIndex
+ RangeName = ListboxList(i)
+ oRange = RetrieveRangeoutofRangeName(RangeName)
+ ConvertCellCurrencies(oRange)
+ If bRemove Then
+ If oSelRanges.HasbyName(RangeName) Then
+ oSelRanges.RemovebyName(RangeName)
+ oDocument.CurrentController.Select(oSelRanges)
+ End If
+ End If
+ If SwitchFormat Then
+ If oRange.getPropertyState(&quot;NumberFormat&quot;) &lt;&gt; 1 Then
+ &apos; Range is hard formatted
+ SwitchNumberFormat(oRange, oFormats, sEuroSign)
+ End If
+ Else
+ SwitchNumberFormat(oRange, oFormats, sEuroSign)
+ End If
+ AddCells = CountRangeCells(oRange)
+ CurCellCount = AddCells
+ IncreaseStatusValue((CurCellCount/TotCellCount)*(100-OldStatusValue))
+ If bRemove Then
+ RemoveListBoxItemByName(oSelListbox.Model,Rangename)
+ End If
+ Next
+ End If
+End Sub
+
+
+Sub ConvertCellCurrencies(oRange as Object)
+Dim oValues as Object
+Dim oCells as Object
+Dim oCell as Object
+ oValues = oRange.queryContentCells(com.sun.star.sheet.CellFlags.VALUE)
+ If (oValues.Count &gt; 0) Then
+ oCells = oValues.Cells.createEnumeration
+ While oCells.hasMoreElements
+ oCell = oCells.nextElement
+ ModifyObjectValuewithCurrFactor(oCell)
+ Wend
+ End If
+End Sub
+
+
+Sub ModifyObjectValuewithCurrFactor(oDocObject as Object)
+Dim oDocObjectValue as double
+ oDocObjectValue = oDocObject.Value
+ oDocObject.Value = Round(oDocObjectValue/CurrFactor, 2)
+End Sub
+
+
+Function CheckIfRangeisCurrency(FormatObject as Object)
+Dim oFormatofObject() as Object
+ &apos; Retrieve the Format of the Object
+ On Local Error GoTo NOKEY
+ oFormatofObject() = oFormats.getByKey(FormatObject.NumberFormat)
+ On Local Error GoTo 0
+ CheckIfRangeIsCurrency = INT(oFormatofObject.Type) AND com.sun.star.util.NumberFormat.CURRENCY
+ Exit Function
+NOKEY:
+ CheckIfRangeisCurrency = False
+ Resume CLERROR
+ CLERROR:
+End Function
+
+
+Function CountColumnsForRow(IndexArray() as String, Row as Integer)
+Dim i as Integer
+Dim NoNulls as Boolean
+ For i = 1 To Ubound(IndexArray,2)
+ If IndexArray(Row,i)= &quot;&quot; Then
+ NoNulls = False
+ Exit For
+ End If
+ Next
+ CountColumnsForRow = i
+End Function
+
+
+Function CountRangeCells(oRange as Object) As Long
+Dim oRangeAddress as Object
+Dim LocCellCount as Long
+ oRangeAddress = oRange.RangeAddress
+ LocCellCount = (oRangeAddress.EndColumn - oRangeAddress.StartColumn + 1) * (oRangeAddress.EndRow - oRangeAddress.StartRow + 1)
+ CountRangeCells = LocCellCount
+End Function</script:module> \ No newline at end of file
diff --git a/wizards/source/euro/Init.xba b/wizards/source/euro/Init.xba
new file mode 100644
index 000000000..623a0a53b
--- /dev/null
+++ b/wizards/source/euro/Init.xba
@@ -0,0 +1,667 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Init" script:language="StarBasic">Option Explicit
+REM ***** BASIC *****
+
+Public Const SBRANGEUBOUND = 20
+Public StyleRangeAssignmentList(SBRANGEUBOUND)as String
+Public SelRangeList(SBRANGEUBOUND) as String
+Public RangeList(SBRANGEUBOUND) as String
+Public UnprotectList() as String
+Public FilterNames(2,1) as String
+Public bDoUnProtect as Boolean
+Public bCancelTask as Boolean
+
+Public sREADY as String
+Public sPROTECT as String
+Public sCONTINUE as String
+
+Public sSELTEMPL as String
+Public sSELCELL as String
+Public sCURRRANGES as String
+Public sTEMPLATES as String
+
+Public sSOURCEFILE as String
+Public sSOURCEDIR as String
+Public sTARGETDIR as String
+
+Public sStsPROGRESS as String
+Public sStsCELLPROGRSS as String
+Public sStsRELRANGES as String
+Public sStsRELSHEETRANGES as String
+Public sStsREPROTECT as String
+
+Public sMsgSELDIR as String
+Public sMsgSELFILE as String
+Public sMsgTARGETDIR as String
+Public sMsgNOTTHERE as String
+Public sMsgDLGTITLE as String
+Public sMsgUNPROTECT as String
+Public sMsgPWPROTECT as String
+Public sMsgWRONGPW as String
+Public sMsgSHEETPROTECTED as String
+Public sMsgWARNING as String
+Public sMsgSHEETSNOPROTECT as String
+Public sMsgSHEETNOPROTECT as String
+Public sMsgCHOOSECURRENCY as String
+Public sMsgPASSWORD as String
+Public sMsgOK as String
+Public sMsgCANCEL as String
+Public sMsgFileInvalid as String
+Public sMsgNODIRECTORY as String
+Public sMsgDOCISREADONLY as String
+Public sMsgFileExists as String
+Public sMsgCancelConversion as String
+Public sMsgCancelTitle as String
+Public sCurrPORTUGUESE as String
+Public sCurrDUTCH as String
+Public sCurrFRENCH as String
+Public sCurrSPANISH as String
+Public sCurrITALIAN as String
+Public sCurrGERMAN as String
+Public sCurrBELGIAN as String
+Public sCurrIRISH as String
+Public sCurrLUXEMBOURG as String
+Public sCurrAUSTRIAN as String
+Public sCurrFINNISH as String
+Public sCurrGREEK as String
+Public sCurrSLOVENIAN as String
+Public sCurrCYPRIOT as String
+Public sCurrMALTESE as String
+Public sCurrSLOVAK as String
+Public sCurrESTONIAN as String
+Public sCurrLATVIAN as String
+Public sCurrLITHUANIAN as String
+
+Public sPrgsRETRIEVAL as String
+Public sPrgsCONVERTING as String
+Public sPrgsUNPROTECT as String
+Public sInclusiveSubDir as String
+
+Public Const SBCOUNTRYCOUNT = 19
+Public CurMimeType as String
+Public CurCellCount as Long
+Public oSheets as Object
+Public oStyles as Object
+Public oStyle as Object
+Public oFormats as Object
+Public aSimpleStr as String
+Public nSimpleKey as Long
+Public aFormat() as Variant
+Public oRanges as Object
+Public oRange as Object
+Public nLanguage as integer
+Public nFormatLanguage as integer
+Public aCellFormat as Variant
+Public oDocument as Object
+Public StartCol, StartRow, EndCol, EndRow as String
+Public oSheet as Object
+Public IntStartCol, IntStartRow, IntEndCol, IntEndRow as integer
+Public oSelRanges as Object
+Public nFormatType as Integer
+Public sFormatCurrency as String
+Public sFormatLanguage as String
+Public CurSheetName as String
+Public oStatusLine as Object
+Public Const SBRELGET = 50
+Public StatusValue as Single
+Public TotCellCount as Long
+Public StyleIndex as Integer
+Public RangeIndex as Integer
+Public CurrIndex as Integer
+Public ActLangNumber(1) as Integer
+Public CurExtension(2) as String
+Public Currfactor as Double
+Public CurrSymbolList(2) as String
+Public CurrLanguage as String
+Public CurrValue(18,5)
+Public LangIDValue(18,2,2) as String
+Public PreName as String
+Public Separator as String
+Public BitmapDir as String
+Public TypeIndex as Integer, CSIndex as Integer, LangIndex as Integer, FSIndex as Integer
+Public oLocale as New com.sun.star.lang.Locale
+Public sEuroSign as String
+Public oPointer as Object
+Public sDocType as String
+Public bPreSelected as Boolean
+Public bRecursive as Boolean
+Public bCancelProtection as Boolean
+Public CurrRoundMode as Boolean
+Public bRangeListDefined as Boolean
+Public bDocHasProtectedSheets as Boolean
+Public sGOON as String
+Public sHELP as String
+Public sCANCEL as String
+Dim sEnd as String
+
+Sub InitializeResources()
+Dim LocWorkPath as String
+ With DialogModel
+ &apos; Strings that are also needed by the Password Dialog
+ sGoOn = GetResText(&quot;STEP_ZERO_3&quot;)
+ sHelp = GetResText(&quot;STEP_ZERO_1&quot;)
+ sCANCEL = GetResText(&quot;MESSAGES_18&quot;)
+ sEnd = GetResText(&quot;STEP_ZERO_0&quot;)
+ sPROTECT = GetResText(&quot;STEP_ZERO_5&quot;)
+ sCONTINUE = GetResText(&quot;STEP_ZERO_7&quot;)
+ sSELTEMPL = GetResText(&quot;STEP_CONVERTER_6&quot;)
+ sSELCELL = GetResText(&quot;STEP_CONVERTER_7&quot;)
+ sCURRRANGES = GetResText(&quot;STEP_CONVERTER_8&quot;)
+ sTEMPLATES = GetResText(&quot;STEP_CONVERTER_9&quot;)
+ sStsPROGRESS = GetResText(&quot;STATUSLINE_0&quot;)
+ sStsCELLPROGRSS = GetResText(&quot;STATUSLINE_1&quot;)
+ sStsRELSHEETRANGES = GetResText(&quot;STATUSLINE_2&quot;)
+ sStsRELRANGES = GetResText(&quot;STATUSLINE_3&quot;)
+ sStsREPROTECT = GetResText(&quot;STATUSLINE_4&quot;)
+ sREADY = GetResText(&quot;MESSAGES_0&quot;)
+ sMsgSELDIR = GetResText(&quot;MESSAGES_1&quot;)
+ sMsgSELFILE = GetResText(&quot;MESSAGES_2&quot;)
+ sMsgTARGETDIR = GetResText(&quot;MESSAGES_3&quot;)
+ sMsgNOTTHERE = GetResText(&quot;MESSAGES_4&quot;)
+ sMsgDLGTITLE = GetResText(&quot;MESSAGES_5&quot;)
+ sMsgUNPROTECT = GetResText(&quot;MESSAGES_6&quot;)
+ sMsgPWPROTECT = GetResText(&quot;MESSAGES_7&quot;)
+ sMsgWRONGPW = GetResText(&quot;MESSAGES_8&quot;)
+ sMsgSHEETPROTECTED = GetResText(&quot;MESSAGES_9&quot;)
+ sMsgWARNING = GetResText(&quot;MESSAGES_10&quot;)
+ sMsgSHEETSNOPROTECT = GetResText(&quot;MESSAGES_11&quot;)
+ sMsgSHEETNOPROTECT = GetResText(&quot;MESSAGES_12&quot;)
+ sMsgCHOOSECURRENCY = GetResText(&quot;MESSAGES_15&quot;)
+ sMsgPASSWORD = GetResText(&quot;MESSAGES_16&quot;)
+ sMsgOK = GetResText(&quot;MESSAGES_17&quot;)
+ sMsgCANCEL = GetResText(&quot;MESSAGES_18&quot;)
+ sMsgFILEINVALID = GetResText(&quot;MESSAGES_19&quot;)
+ sMsgFILEINVALID = ReplaceString(sMsgFILEINVALID,&quot;%PRODUCTNAME&quot;, GetProductname())
+ SMsgNODIRECTORY = GetResText(&quot;MESSAGES_20&quot;)
+ sMsgDOCISREADONLY = GetResText(&quot;MESSAGES_21&quot;)
+ sMsgFileExists = GetResText(&quot;MESSAGES_22&quot;)
+ sMsgCancelConversion = GetResText(&quot;MESSAGES_23&quot;)
+ sMsgCancelTitle = GetResText(&quot;MESSAGES_24&quot;)
+ sCurrPORTUGUESE = GetResText(&quot;CURRENCIES_0&quot;)
+ sCurrDUTCH = GetResText(&quot;CURRENCIES_1&quot;)
+ sCurrFRENCH = GetResText(&quot;CURRENCIES_2&quot;)
+ sCurrSPANISH = GetResText(&quot;CURRENCIES_3&quot;)
+ sCurrITALIAN = GetResText(&quot;CURRENCIES_4&quot;)
+ sCurrGERMAN = GetResText(&quot;CURRENCIES_5&quot;)
+ sCurrBELGIAN = GetResText(&quot;CURRENCIES_6&quot;)
+ sCurrIRISH = GetResText(&quot;CURRENCIES_7&quot;)
+ sCurrLUXEMBOURG = GetResText(&quot;CURRENCIES_8&quot;)
+ sCurrAUSTRIAN = GetResText(&quot;CURRENCIES_9&quot;)
+ sCurrFINNISH = GetResText(&quot;CURRENCIES_10&quot;)
+ sCurrGREEK = GetResText(&quot;CURRENCIES_11&quot;)
+ sCurrSLOVENIAN = GetResText(&quot;CURRENCIES_12&quot;)
+ sCurrCYPRIOT = GetResText(&quot;CURRENCIES_13&quot;)
+ sCurrMALTESE = GetResText(&quot;CURRENCIES_14&quot;)
+ sCurrSLOVAK = GetResText(&quot;CURRENCIES_15&quot;)
+ sCurrESTONIAN = GetResText(&quot;CURRENCIES_16&quot;)
+ sCurrLATVIAN = GetResText(&quot;CURRENCIES_17&quot;)
+ sCurrLITHUANIAN = GetResText(&quot;CURRENCIES_18&quot;)
+ .cmdCancel.Label = sCANCEL
+ .cmdHelp.Label = sHELP
+ .cmdBack.Label = GetResText(&quot;STEP_ZERO_2&quot;)
+ .cmdGoOn.Label = sGOON
+ .lblHint.Label = GetResText(&quot;STEP_ZERO_4&quot;)
+ .lblCurrencies.Label = GetResText(&quot;STEP_ZERO_6&quot;)
+ .cmdBack.Enabled = False
+ If .Step = 1 Then
+ .chkComplete.Label = GetResText(&quot;STEP_CONVERTER_0&quot;)
+ .hlnSelection.Label = GetResText(&quot;STEP_CONVERTER_1&quot;)
+ .optCellTemplates.Label = GetResText(&quot;STEP_CONVERTER_2&quot;)
+ .optSheetRanges.Label = GetResText(&quot;STEP_CONVERTER_3&quot;)
+ .optDocRanges.Label = GetResText(&quot;STEP_CONVERTER_4&quot;)
+ .optSelRange.Label = GetResText(&quot;STEP_CONVERTER_5&quot;)
+ sCURRRANGES = GetResText(&quot;STEP_CONVERTER_8&quot;)
+ .lblSelection.Label = sCURRRANGES
+ Else
+ .lblProgress.Label = sStsPROGRESS
+ .hlnExtent.Label = GetResText(&quot;STEP_AUTOPILOT_0&quot;)
+ .optSingleFile.Label = GetResText(&quot;STEP_AUTOPILOT_1&quot;)
+ .optWholeDir.Label = GetResText(&quot;STEP_AUTOPILOT_2&quot;)
+ .chkProtect.Label = GetResText(&quot;STEP_AUTOPILOT_7&quot;)
+ .chkTextDocuments.Label = GetResText(&quot;STEP_AUTOPILOT_10&quot;)
+
+ sSOURCEFILE = GetResText(&quot;STEP_AUTOPILOT_3&quot;)
+ sSOURCEDIR = GetResText(&quot;STEP_AUTOPILOT_4&quot;)
+ .lblSource.Label = sSOURCEDIR
+ sInclusiveSubDir = GetResText(&quot;STEP_AUTOPILOT_5&quot;)
+ .chkRecursive.Label = sInclusiveSubDir
+ sTARGETDIR = GetResText(&quot;STEP_AUTOPILOT_6&quot;)
+ .lblTarget.Label = STARGETDIR
+
+ LocWorkPath = GetPathSettings(&quot;Work&quot;)
+ If Not oUcb.Exists(LocWorkPath) Then
+ ShowNoOfficePathError()
+ Stop
+ End If
+
+ .txtSource.Text = ConvertfromUrl(LocWorkPath)
+
+ SubstDir = .txtSource.Text
+ .txtTarget.Text = .txtSource.Text
+ .hlnProgress.Label = GetResText(&quot;STEP_LASTPAGE_0&quot;)
+ .lblConfig.Label = GetResText(&quot;STEP_LASTPAGE_3&quot;)
+ sPrgsRETRIEVAL = GetResText(&quot;STEP_LASTPAGE_1&quot;)
+ sPrgsCONVERTING = GetResText(&quot;STEP_LASTPAGE_2&quot;)
+ sPrgsUNPROTECT = GetResText(&quot;STEP_LASTPAGE_4&quot;)
+ End If
+ End With
+End Sub
+
+Sub InitializeLanguages()
+ sEuroSign = chr(8364)
+
+&apos; CURRENCIES_PORTUGUESE
+ LangIDValue(0,0,0) = &quot;pt&quot;
+ LangIDValue(0,0,1) = &quot;&quot;
+ LangIDValue(0,0,2) = &quot;-816&quot;
+
+&apos; CURRENCIES_DUTCH
+ LangIDValue(1,0,0) = &quot;nl&quot;
+ LangIDValue(1,0,1) = &quot;&quot;
+ LangIDValue(1,0,2) = &quot;-413&quot;
+
+&apos; CURRENCIES_FRENCH
+ LangIDValue(2,0,0) = &quot;fr&quot;
+ LangIDValue(2,0,1) = &quot;&quot;
+ LangIDValue(2,0,2) = &quot;-40C&quot;
+
+&apos; CURRENCIES_SPANISH
+ LangIDValue(3,0,0) = &quot;es&quot;
+ LangIDValue(3,0,1) = &quot;&quot;
+ LangIDValue(3,0,2) = &quot;-40A&quot;
+
+ &apos;Spanish modern
+ LangIDValue(3,1,0) = &quot;es&quot;
+ LangIDValue(3,1,1) = &quot;&quot;
+ LangIDValue(3,1,2) = &quot;-C0A&quot;
+
+ &apos;Spanish katalanic
+ LangIDValue(3,2,0) = &quot;es&quot;
+ LangIDValue(3,2,1) = &quot;&quot;
+ LangIDValue(3,2,2) = &quot;-403&quot;
+
+&apos; CURRENCIES_ITALIAN
+ LangIDValue(4,0,0) = &quot;it&quot;
+ LangIDValue(4,0,1) = &quot;&quot;
+ LangIDValue(4,0,2) = &quot;-410&quot;
+
+&apos; CURRENCIES_GERMAN
+ LangIDValue(5,0,0) = &quot;de&quot;
+ LangIDValue(5,0,1) = &quot;DE&quot;
+ LangIDValue(5,0,2) = &quot;-407&quot;
+
+&apos; CURRENCIES_BELGIAN
+ LangIDValue(6,0,0) = &quot;fr&quot;
+ LangIDValue(6,0,1) = &quot;BE&quot;
+ LangIDValue(6,0,2) = &quot;-80C&quot;
+
+ LangIDValue(6,1,0) = &quot;nl&quot;
+ LangIDValue(6,1,1) = &quot;BE&quot;
+ LangIDValue(6,1,2) = &quot;-813&quot;
+
+&apos; CURRENCIES_IRISH
+ LangIDValue(7,0,0) = &quot;en&quot;
+ LangIDValue(7,0,1) = &quot;IE&quot;
+ LangIDValue(7,0,2) = &quot;-1809&quot;
+
+ LangIDValue(7,1,0) = &quot;ga&quot;
+ LangIDValue(7,1,1) = &quot;IE&quot;
+ LangIDValue(7,1,2) = &quot;-83C&quot;
+
+&apos; CURRENCIES_LUXEMBOURG
+ LangIDValue(8,0,0) = &quot;fr&quot;
+ LangIDValue(8,0,1) = &quot;LU&quot;
+ LangIDValue(8,0,2) = &quot;-140C&quot;
+
+ LangIDValue(8,1,0) = &quot;de&quot;
+ LangIDValue(8,1,1) = &quot;LU&quot;
+ LangIDValue(8,1,2) = &quot;-1007&quot;
+
+&apos; CURRENCIES_AUSTRIAN
+ LangIDValue(9,0,0) = &quot;de&quot;
+ LangIDValue(9,0,1) = &quot;AT&quot;
+ LangIDValue(9,0,2) = &quot;-C07&quot;
+
+&apos; CURRENCIES_FINNISH
+ LangIDValue(10,0,0) = &quot;fi&quot;
+ LangIDValue(10,0,1) = &quot;FI&quot;
+ LangIDValue(10,0,2) = &quot;-40B&quot;
+
+ LangIDValue(10,1,0) = &quot;sv&quot;
+ LangIDValue(10,1,1) = &quot;FI&quot;
+ LangIDValue(10,1,2) = &quot;-81D&quot;
+
+&apos; CURRENCIES_GREEK
+ LangIDValue(11,0,0) = &quot;el&quot;
+ LangIDValue(11,0,1) = &quot;GR&quot;
+ LangIDValue(11,0,2) = &quot;-408&quot;
+
+&apos; CURRENCIES_SLOVENIAN
+ LangIDValue(12,0,0) = &quot;sl&quot;
+ LangIDValue(12,0,1) = &quot;SI&quot;
+ LangIDValue(12,0,2) = &quot;-424&quot;
+
+&apos; CURRENCIES_CYPRIOT
+ LangIDValue(13,0,0) = &quot;el&quot;
+ LangIDValue(13,0,1) = &quot;CY&quot;
+ LangIDValue(13,0,2) = &quot;-408&quot;
+
+&apos; CURRENCIES_MALTESE
+ LangIDValue(14,0,0) = &quot;mt&quot;
+ LangIDValue(14,0,1) = &quot;MT&quot;
+ LangIDValue(14,0,2) = &quot;-43A&quot;
+
+&apos; CURRENCIES_SLOVAK
+ LangIDValue(15,0,0) = &quot;sk&quot;
+ LangIDValue(15,0,1) = &quot;SK&quot;
+ LangIDValue(15,0,2) = &quot;-41B&quot;
+
+&apos; CURRENCIES_ESTONIAN
+ LangIDValue(16,0,0) = &quot;et&quot;
+ LangIDValue(16,0,1) = &quot;ET&quot;
+ LangIDValue(16,0,2) = &quot;-425&quot;
+
+&apos; CURRENCIES_LATVIAN
+ LangIDValue(17,0,0) = &quot;lv&quot;
+ LangIDValue(17,0,1) = &quot;LV&quot;
+ LangIDValue(17,0,2) = &quot;-426&quot;
+ &apos; and Latgalian
+ LangIDValue(17,1,0) = &quot;ltg&quot;
+ LangIDValue(17,1,1) = &quot;LV&quot;
+ LangIDValue(17,1,2) = &quot;-64B&quot;
+
+&apos; CURRENCIES_LITHUANIAN
+ LangIDValue(18,0,0) = &quot;lt&quot;
+ LangIDValue(18,0,1) = &quot;LT&quot;
+ LangIDValue(18,0,2) = &quot;-427&quot;
+
+End Sub
+
+
+
+Sub InitializeCurrencies()
+Dim i as Integer
+ GoOn = True
+
+ CurrValue(0,0) = sCurrPORTUGUESE
+ &apos; real conversion rate
+ CurrValue(0,1) = 200.482
+ &apos; rounded conversion rate
+ CurrValue(0,2) = 200
+ CurrValue(0,3) = &quot;Esc.&quot;
+ CurrValue(0,4) = &quot;Esc.&quot;
+ CurrValue(0,5) = &quot;PTE&quot;
+
+ CurrValue(1,0) = sCurrDUTCH
+ &apos; real conversion rate
+ CurrValue(1,1) = 2.20371
+ &apos; rounded conversion rate
+ CurrValue(1,2) = 2
+ CurrValue(1,3) = &quot;F&quot;
+ CurrValue(1,4) = &quot;fl&quot;
+ CurrValue(1,5) = &quot;NLG&quot;
+
+ CurrValue(2,0) = sCurrFRENCH
+ &apos; real conversion rate
+ CurrValue(2,1) = 6.55957
+ &apos; rounded conversion rate
+ CurrValue(2,2) = 7
+ CurrValue(2,3) = &quot;F&quot;
+ CurrValue(2,4) = &quot;F&quot;
+ CurrValue(2,5) = &quot;FRF&quot;
+
+ CurrValue(3,0) = sCurrSPANISH
+ &apos; real conversion rate
+ CurrValue(3,1) = 166.386
+ &apos; rounded conversion rate
+ CurrValue(3,2) = 170
+ CurrValue(3,3) = &quot;Pts&quot;
+ CurrValue(3,4) = &quot;Pts&quot;
+ CurrValue(3,5) = &quot;ESP&quot;
+
+ CurrValue(4,0) = sCurrITALIAN
+ &apos; real conversion rate
+ CurrValue(4,1) = 1936.27
+ &apos; rounded conversion rate
+ CurrValue(4,2) = 2000
+ CurrValue(4,3) = &quot;L.&quot;
+ CurrValue(4,4) = &quot;L.&quot;
+ CurrValue(4,5) = &quot;ITL&quot;
+
+ CurrValue(5,0) = sCurrGERMAN
+ &apos; real conversion rate
+ CurrValue(5,1) = 1.95583
+ &apos; rounded conversion rate
+ CurrValue(5,2) = 2
+ CurrValue(5,3) = &quot;DM&quot;
+ CurrValue(5,4) = &quot;DM&quot;
+ CurrValue(5,5) = &quot;DEM&quot;
+
+ CurrValue(6,0) = sCurrBELGIAN
+ &apos; real conversion rate
+ CurrValue(6,1) = 40.3399
+ &apos; rounded conversion rate
+ CurrValue(6,2) = 40
+ CurrValue(6,3) = &quot;FB&quot;
+ CurrValue(6,4) = &quot;BF&quot;
+ CurrValue(6,5) = &quot;BEF&quot;
+
+ CurrValue(7,0) = sCurrIRISH
+ &apos; real conversion rate
+ CurrValue(7,1) = 0.787564
+ &apos; rounded conversion rate
+ CurrValue(7,2) = 0.8
+ CurrValue(7,3) = &quot;IR£&quot;
+ CurrValue(7,4) = &quot;£&quot;
+ CurrValue(7,5) = &quot;IEP&quot;
+
+ CurrValue(8,0) = sCurrLUXEMBOURG
+ &apos; real conversion rate
+ CurrValue(8,1) = 40.3399
+ &apos; rounded conversion rate
+ CurrValue(8,2) = 40
+ CurrValue(8,3) = &quot;F&quot;
+ CurrValue(8,4) = &quot;F&quot;
+ CurrValue(8,5) = &quot;LUF&quot;
+
+ CurrValue(9,0) = sCurrAUSTRIAN
+ &apos; real conversion rate
+ CurrValue(9,1) = 13.7603
+ &apos; rounded conversion rate
+ CurrValue(9,2) = 15
+ CurrValue(9,3) = &quot;öS&quot;
+ CurrValue(9,4) = &quot;S&quot;
+ CurrValue(9,5) = &quot;ATS&quot;
+
+ CurrValue(10,0) = sCurrFINNISH
+ &apos; real conversion rate
+ CurrValue(10,1) = 5.94573
+ &apos; rounded conversion rate
+ CurrValue(10,2) = 6
+ CurrValue(10,3) = &quot;mk&quot;
+ CurrValue(10,4) = &quot;mk&quot;
+ CurrValue(10,5) = &quot;FIM&quot;
+
+ CurrValue(11,0) = sCurrGREEK
+ &apos; real conversion rate
+ CurrValue(11,1) = 340.750
+ &apos; rounded conversion rate
+ CurrValue(11,2) = 400
+ CurrValue(11,3) = chr(916) &amp; chr(961) &amp; chr(967)
+ CurrValue(11,4) = chr(916) &amp; chr(961) &amp; chr(967)
+ CurrValue(11,5) = &quot;GRD&quot;
+
+ CurrValue(12,0) = sCurrSLOVENIAN
+ &apos; real conversion rate
+ CurrValue(12,1) = 239.64
+ &apos; rounded conversion rate
+ CurrValue(12,2) = 240
+ CurrValue(12,3) = &quot;SIT&quot;
+ CurrValue(12,4) = &quot;SIT&quot;
+ CurrValue(12,5) = &quot;SIT&quot;
+
+ CurrValue(13,0) = sCurrCYPRIOT
+ &apos; real conversion rate
+ CurrValue(13,1) = 0.585274
+ &apos; rounded conversion rate
+ CurrValue(13,2) = 0.6
+ CurrValue(13,3) = &quot;£C&quot;
+ CurrValue(13,4) = &quot;£&quot;
+ CurrValue(13,5) = &quot;CYP&quot;
+
+ CurrValue(14,0) = sCurrMALTESE
+ &apos; real conversion rate
+ CurrValue(14,1) = 0.429300
+ &apos; rounded conversion rate
+ CurrValue(14,2) = 0.4
+ CurrValue(14,3) = chr(8356)
+ CurrValue(14,4) = &quot;Lm&quot;
+ CurrValue(14,5) = &quot;MTL&quot;
+
+ CurrValue(15,0) = sCurrSLOVAK
+ &apos; real conversion rate
+ CurrValue(15,1) = 30.1260
+ &apos; rounded conversion rate
+ CurrValue(15,2) = 30
+ CurrValue(15,3) = &quot;Sk&quot;
+ CurrValue(15,4) = &quot;Sk&quot;
+ CurrValue(15,5) = &quot;SKK&quot;
+
+ CurrValue(16,0) = sCurrESTONIAN
+ &apos; real conversion rate
+ CurrValue(16,1) = 15.6466
+ &apos; rounded conversion rate
+ CurrValue(16,2) = 16
+ CurrValue(16,3) = &quot;kr&quot;
+ CurrValue(16,4) = &quot;kr&quot;
+ CurrValue(16,5) = &quot;EEK&quot;
+
+ CurrValue(17,0) = sCurrLATVIAN
+ &apos; real conversion rate
+ CurrValue(17,1) = 0.702804
+ &apos; rounded conversion rate
+ CurrValue(17,2) = 0.7
+ CurrValue(17,3) = &quot;Ls&quot;
+ CurrValue(17,4) = &quot;Ls&quot;
+ CurrValue(17,5) = &quot;LVL&quot;
+
+ CurrValue(18,0) = sCurrLITHUANIAN
+ &apos; real conversion rate
+ CurrValue(18,1) = 3.45280
+ &apos; rounded conversion rate
+ CurrValue(18,2) = 3.5
+ CurrValue(18,3) = &quot;Lt&quot;
+ CurrValue(18,4) = &quot;Lt&quot;
+ CurrValue(18,5) = &quot;LTL&quot;
+
+ i = -1
+ CurrSymbolList(0) = &quot;&quot;
+ CurrSymbolList(1) = &quot;&quot;
+ InitializeCurrencyValues(CurrIndex)
+End Sub
+
+
+Sub InitializeControls()
+ If CurrIndex = -1 Then
+ If DialogModel.Step = 1 Then
+ EnableStep1DialogControls(True, False, False)
+ ElseIf DialogModel.Step = 2 Then
+ EnableStep2DialogControls(True)
+ End If
+ End If
+End Sub
+
+
+Sub InitializeConverter(oLocale, iDialogPage as Integer)
+Dim Isthere as Boolean
+ bCancelProtection = False
+ bRangeListDefined = False
+ PWIndex = -1
+ If iDialogPage = 1 Then
+ ToggleWindow(False)
+ sDocType = Tools.GetDocumentType(ThisComponent)
+ If sDocType = &quot;sCalc&quot; Then
+ bDocHasProtectedSheets = CheckSheetProtection(oSheets)
+ End If
+ oStatusline = ThisComponent.GetCurrentController.GetFrame.CreateStatusIndicator()
+ End If
+ DialogConvert = LoadDialog(&quot;Euro&quot;, &quot;DlgConvert&quot;)
+ DialogModel = DialogConvert.Model
+ DialogPassword = LoadDialog(&quot;Euro&quot;, &quot;DlgPassword&quot;)
+ PasswordModel = DialogPassword.Model
+ DialogModel.Step = iDialogPage
+ InitializeResources()
+ InitializeLanguages()
+ InitializeLocales(oLocale)
+ InitializeCurrencies()
+ InitializeControls()
+ BitmapDir = GetOfficeSubPath(&quot;Template&quot;, &quot;../wizard/bitmap&quot;)
+ If BitmapDir = &quot;&quot; Then
+ Stop
+ End If
+ FillUpCurrencyListbox()
+ DialogModel.imgPreview.ImageUrl = BitmapDir &amp; &quot;euro_&quot; &amp; DialogModel.Step &amp; &quot;.png&quot;
+ DialogConvert.Title = sMsgDLGTITLE
+ DialogModel.cmdGoOn.DefaultButton = True
+ If iDialogPage = 1 Then
+ ToggleWindow(True)
+ End If
+End Sub
+
+
+Sub InitializeCurrencyValues(CurrIndex)
+ If CurrIndex &lt;&gt; -1 Then
+ CurrLanguage = CurrValue(CurrIndex,0)
+ CurrFactor = CurrValue(CurrIndex,1)
+ CurrSymbolList(0) = CurrValue(CurrIndex,3)
+ CurrSymbolList(1) = CurrValue(CurrIndex,4)
+ CurrSymbolList(2) = CurrValue(CurrIndex,5)
+ End If
+End Sub
+
+
+Function InitializeLocales(oLocale) as Boolean
+Dim i as Integer, n as Integer, m as Integer
+Dim sLanguage as String, sCountry as String
+Dim bTakeThisLocale as Boolean
+ sLanguage = oLocale.Language
+ sCountry = oLocale.Country
+ For n = 0 To SBCOUNTRYCOUNT - 1
+ For m = 0 TO 1
+ If DialogModel.Step = 2 Then
+ bTakeThisLocale = LangIDValue(n,m,0) = sLanguage
+ Else
+ bTakeThisLocale = LangIDValue(n,m,0) = sLanguage
+ End If
+ If bTakeThisLocale Then
+ CurrIndex = n
+ For i = 0 To 2
+ CurExtension(i) = LangIDValue(CurrIndex,i,2)
+ Next i
+ InitializeLocales = True
+ Exit Function
+ End If
+ Next m
+ Next n
+ CurrIndex = -1
+ InitializeLocales = False
+End Function
+</script:module>
diff --git a/wizards/source/euro/Protect.xba b/wizards/source/euro/Protect.xba
new file mode 100644
index 000000000..4a9cac577
--- /dev/null
+++ b/wizards/source/euro/Protect.xba
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Protect" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+
+Public PWIndex as Integer
+
+
+Function UnprotectSheetsWithPassWord(oSheets as Object, bDoUnProtect as Boolean)
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim iMsgResult as Integer
+ PWIndex = -1
+ If bDocHasProtectedSheets Then
+ If Not bDoUnprotect Then
+ &apos; At First query if sheets shall generally be unprotected
+ iMsgResult = Msgbox(sMsgUNPROTECT,36,sMsgDLGTITLE)
+ bDoUnProtect = iMsgResult = 6
+ End If
+ If bDoUnProtect Then
+ MaxIndex = oSheets.Count-1
+ For i = 0 To MaxIndex
+ bDocHasProtectedSheets = Not UnprotectSheet(oSheets(i))
+ If bDocHasProtectedSheets Then
+ ReprotectSheets()
+ Exit For
+ End If
+ Next i
+ If PWIndex = -1 Then
+ ReDim UnProtectList() as String
+ Else
+ ReDim Preserve UnProtectList(PWIndex) as String
+ End If
+ Else
+ Msgbox (sMsgSHEETSNOPROTECT, 64, sMsgDLGTITLE)
+ End If
+ End If
+ UnProtectSheetsWithPassword = bDocHasProtectedSheets
+End Function
+
+
+Function UnprotectSheet(oListSheet as Object)
+Dim ListSheetName as String
+Dim sStatustext as String
+Dim i as Integer
+Dim bOneSheetIsUnprotected as Boolean
+ i = -1
+ ListSheetName = oListSheet.Name
+ If oListSheet.IsProtected Then
+ oListSheet.Unprotect(&quot;&quot;)
+ If oListSheet.IsProtected Then
+ &apos; Sheet is protected by a Password
+ bOneSheetIsUnProtected = UnprotectSheetWithDialog(oListSheet, ListSheetName)
+ UnProtectSheet() = bOneSheetIsUnProtected
+ Else
+ &apos; The Sheet could be unprotected without a password
+ AddSheettoUnprotectionlist(ListSheetName,&quot;&quot;)
+ UnprotectSheet() = True
+ End If
+ Else
+ UnprotectSheet() = True
+ End If
+End Function
+
+
+Function UnprotectSheetWithDialog(oListSheet as Object, ListSheetName as String) as Boolean
+Dim PWIsCorrect as Boolean
+Dim QueryText as String
+ oDocument.CurrentController.SetActiveSheet(oListSheet)
+ QueryText = ReplaceString(sMsgPWPROTECT,&quot;&apos;&quot; &amp; ListSheetName &amp; &quot;&apos;&quot;, &quot;%1TableName%1&quot;)
+ &apos;&quot;Please insert the password to unprotect the sheet &apos;&quot; &amp; ListSheetName&apos;&quot;
+ Do
+ ExecutePasswordDialog(QueryText)
+ If bCancelProtection Then
+ bCancelProtection = False
+ Msgbox (sMsgSHEETSNOPROTECT, 64, sMsgDLGTITLE)
+ UnprotectSheetWithDialog() = False
+ exit Function
+ End If
+ oListSheet.Unprotect(Password)
+ If oListSheet.IsProtected Then
+ PWIsCorrect = False
+ Msgbox (sMsgWRONGPW, 64, sMsgDLGTITLE)
+ Else
+ &apos; Sheet could be unprotected
+ AddSheettoUnprotectionlist(ListSheetName,Password)
+ PWIsCorrect = True
+ End If
+ Loop Until PWIsCorrect
+ UnprotectSheetWithDialog() = True
+End Function
+
+
+Sub ExecutePasswordDialog(QueryText as String)
+ With PasswordModel
+ .Title = QueryText
+ .hlnPassword.Label = sMsgPASSWORD
+ .cmdCancel.Label = sMsgCANCEL
+ .cmdHelp.Label = sHELP
+ .cmdGoOn.Label = sMsgOK
+ .cmdGoOn.DefaultButton = True
+ End With
+ DialogPassword.Execute
+End Sub
+
+Sub ReadPassword()
+ Password = PasswordModel.txtPassword.Text
+ DialogPassword.EndExecute
+End Sub
+
+
+Sub RejectPassword()
+ bCancelProtection = True
+ DialogPassword.EndExecute
+End Sub
+
+
+&apos; Reprotects the previously protected sheets
+&apos; The password information is stored in the List &apos;UnProtectList()&apos;
+Sub ReprotectSheets()
+Dim i as Integer
+Dim oProtectSheet as Object
+Dim ProtectList() as String
+Dim SheetName as String
+Dim SheetPassword as String
+ If PWIndex &gt; -1 Then
+ SetStatusLineText(sStsREPROTECT)
+ For i = 0 To PWIndex
+ ProtectList() = ArrayOutOfString(UnProtectList(i),&quot;;&quot;)
+ SheetName = ProtectList(0)
+ If Ubound(ProtectList()) &gt; 0 Then
+ SheetPassWord = ProtectList(1)
+ Else
+ SheetPassword = &quot;&quot;
+ End If
+ oProtectSheet = oSheets.GetbyName(SheetName)
+ If Not oProtectSheet.IsProtected Then
+ oProtectSheet.Protect(SheetPassWord)
+ End If
+ Next i
+ SetStatusLineText(&quot;&quot;)
+ End If
+ PWIndex = -1
+ ReDim UnProtectList()
+End Sub
+
+
+&apos; Add a Sheet to the list of sheets that finally have to be
+&apos; unprotected
+Sub AddSheettoUnprotectionlist(ListSheetName as String, Password as String)
+Dim MaxIndex as Integer
+ MaxIndex = Ubound(UnProtectList())
+ PWIndex = PWIndex + 1
+ If PWIndex &gt; MaxIndex Then
+ ReDim Preserve UnprotectList(MaxIndex + SBRANGEUBOUND)
+ End If
+ UnprotectList(PWIndex) = ListSheetName &amp; &quot;;&quot; &amp; Password
+End Sub
+
+
+Function CheckSheetProtection(oSheets as Object) as Boolean
+Dim MaxIndex as Integer
+Dim i as Integer
+Dim bProtectedSheets as Boolean
+ bProtectedSheets = False
+ MaxIndex = oSheets.Count-1
+ For i = 0 To MaxIndex
+ bProtectedSheets = oSheets(i).IsProtected
+ If bProtectedSheets Then
+ CheckSheetProtection() = True
+ Exit Function
+ End If
+ Next i
+ CheckSheetProtection() = False
+End Function</script:module>
diff --git a/wizards/source/euro/Soft.xba b/wizards/source/euro/Soft.xba
new file mode 100644
index 000000000..eed7bd030
--- /dev/null
+++ b/wizards/source/euro/Soft.xba
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Soft" script:language="StarBasic">Option Explicit
+REM ***** BASIC *****
+
+
+Sub CreateStyleEnumeration()
+ EmptySelection()
+ EmptyListbox(DialogModel.lstSelection)
+ CurSheetName = oDocument.CurrentController.GetActiveSheet.Name
+ MakeStyleEnumeration(False)
+ DialogModel.lblSelection.Label = sTEMPLATES
+End Sub
+
+
+Sub MakeStyleEnumeration(bAddToListbox as Boolean)
+Dim m as integer
+Dim aStyleFormat as Object
+Dim Stylename as String
+ StyleIndex = -1
+ oStyles = oDocument.StyleFamilies.GetbyIndex(0)
+ For m = 0 To oStyles.count-1
+ oStyle = oStyles.GetbyIndex(m)
+ StyleName = oStyle.Name
+ If CheckFormatType(oStyle) Then
+ If Not bAddToListBox Then
+ AddSingleItemToListbox(DialogModel.lstSelection, Stylename)
+ Else
+ SwitchNumberFormat(ostyle, oFormats, sEuroSign)
+ End If
+ StyleIndex = StyleIndex + 1
+ If StyleIndex &gt; Ubound(StyleRangeAssignMentList()) Then
+ Redim Preserve StyleRangeAssignmentList(StyleIndex)
+ End If
+ StyleRangeAssignmentList(StyleIndex) = &quot;&lt;STYLENAME&gt;&quot; &amp; Stylename &amp; &quot;&lt;/STYLENAME&gt;&quot; &amp; _
+ &quot;&lt;DEFINED&gt;FALSE&lt;/DEFINED&gt;&quot; &amp; &quot;&lt;RANGES&gt;&lt;/RANGES&gt;&quot; &amp;_
+ &quot;&lt;CELLCOUNT&gt;0&lt;/CELLCOUNT&gt;&quot; &amp;_
+ &quot;&lt;SELECTED&gt;FALSE&lt;/SELECTED&gt;&quot;
+ End If
+ Next m
+ If StyleIndex &gt; -1 Then
+ Redim Preserve StyleRangeAssignmentList(StyleIndex)
+ Else
+ ReDim StyleRangeAssignmentList()
+ End If
+End Sub
+
+
+Sub AssignRangestoStyle(StyleList(), SelList())
+Dim i as Integer
+Dim n as integer
+Dim LastIndex as Integer
+Dim CurStyleName as String
+Dim AssignString as String
+ LastIndex = Ubound(StyleList())
+ StatusValue = 0
+ SetStatusLineText(sStsRELRANGES)
+ For i = 0 To LastIndex
+ CurStyleName = StyleList(i)
+ n = PartStringInArray(StyleRangeAssignmentList(), CurStyleName, 0)
+ AssignString = StyleRangeAssignmentlist(n)
+ If IndexInArray(CurStyleName, SelList()) &lt;&gt; -1 Then
+ &apos; Style is selected
+ If FindPartString(AssignString, &quot;&lt;DEFINED&gt;&quot;, &quot;&lt;/DEFINED&gt;&quot;, 1) = &quot;FALSE&quot; Then
+ AssignString = ReplaceString(AssignString, &quot;&lt;SELECTED&gt;TRUE&lt;/SELECTED&gt;&quot;, &quot;&lt;SELECTED&gt;FALSE&lt;/SELECTED&gt;&quot;)
+ AssignCellFormatRanges(n, AssignString, CurStyleName)
+ End If
+ Else
+ &apos; Style is not selected
+ If FindPartString(AssignString, &quot;&lt;SELECTED&gt;&quot;, &quot;&lt;/SELECTED&gt;&quot;, 1) = &quot;FALSE&quot; Then
+ DeselectStyle(CurStyleName, n)
+ End If
+ End If
+ IncreaseStatusvalue(SBRELGET/(LastIndex+1))
+ Next i
+End Sub
+
+
+Sub AssignCellFormatRanges(n as Integer, AssignString as String, CurStyleName as String)
+Dim oRanges() as Object
+Dim oRange as Object
+Dim oRangeAddress
+Dim oSheet as Object
+Dim StyleCellCount as Long
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim RangeString as String
+Dim SheetName as String
+Dim RangeName as String
+Dim CellCountString as String
+ StyleCellCount = 0
+ RangeString = &quot;&lt;RANGES&gt;&quot;
+ MaxIndex = oSheets.Count-1
+ For i = 0 To MaxIndex
+ oSheet = oSheets(i)
+ SheetName = oSheet.Name
+ oRanges = osheet.CellFormatRanges.CreateEnumeration
+ While oRanges.hasMoreElements
+ oRange = oRanges.NextElement
+ If oRange.getPropertyState(&quot;NumberFormat&quot;) = 1 Then
+ If oRange.CellStyle = CurStyleName Then
+ oRangeAddress = oRange.RangeAddress
+ RangeName = RetrieveRangeNamefromAddress(oRange)
+ RangeString = RangeString &amp; RangeName &amp; &quot;,&quot;
+ StyleCellCount = StyleCellCount + CountRangeCells(oRange)
+ End If
+ End If
+ Wend
+ Next i
+ If StyleCellCount &gt; 0 Then
+ TotCellCount = TotCellCount + StyleCellCount
+ RangeString = RTrimStr(RangeString,&quot;,&quot;)
+ RangeString = RangeString &amp; &quot;&lt;/RANGES&gt;&quot;
+ CellCountString = &quot;&lt;CELLCOUNT&gt;&quot; &amp; StyleCellCount &amp; &quot;&lt;/CELLCOUNT&quot;
+ AssignString = ReplaceString(AssignString, RangeString,&quot;&lt;RANGES&gt;&lt;/RANGES&gt;&quot;)
+ AssignString = ReplaceString(AssignString, CellCountString,&quot;&lt;CELLCOUNT&gt;0&lt;/CELLCOUNT&gt;&quot;)
+ End If
+ AssignString = ReplaceString(AssignString, &quot;&lt;DEFINED&gt;TRUE&lt;/DEFINED&gt;&quot;, &quot;&lt;DEFINED&gt;FALSE&lt;/DEFINED&gt;&quot;)
+ StyleRangeAssignmentList(n) = AssignString
+End Sub
+
+
+&apos; deletes a styletemplate from the Collection that selects the ranges
+Sub DeselectStyle(DeSelStyleName as String, n as Integer)
+Dim i as Integer
+Dim RangeName as String
+Dim SelectString as String
+Dim AssignString as String
+Dim StyleRangeList() as String
+Dim MaxIndex as Integer
+ SelectString =&quot;&lt;SELECTED&gt;FALSE&lt;/SELECTED&gt;&quot;
+ AssignString = StyleRangeAssignmentList(n)
+ RangeString = FindPartString(AssignString,&quot;&lt;RANGES&gt;&quot;,&quot;&lt;/RANGES&gt;&quot;,1)
+ StyleRangeList() = ArrayoutofString(RangeString,&quot;,&quot;)
+ MaxIndex = Ubound(StyleRangeList())
+ For i = 0 To MaxIndex
+ RangeName = StyleRangeList(i)
+ If oSelRanges.HasbyName(RangeName) Then
+ oSelRanges.RemovebyName(RangeName)
+ End If
+ Next i
+ AssignString = ReplaceString(AssignString, &quot;&lt;SELECTED&gt;FALSE&lt;/SELECTED&gt;&quot;, &quot;&lt;SELECTED&gt;TRUE&lt;/SELECTED&gt;&quot;)
+ StyleRangeAssignmentList(n) = AssignString
+End Sub
+
+
+Function RetrieveRangeNamefromAddress(oRange as Object) as String
+Dim Rangename as String
+Dim oAddressRanges as Object
+ oAddressRanges = oDocument.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ oAddressRanges.InsertbyName(&quot;&quot;,oRange)
+ Rangename = oAddressRanges.RangeAddressesasString
+&apos; Msgbox &quot;Adresse: &quot; &amp; oRangeAddress.StartColumn &amp; &quot; ; &quot; &amp; oRangeAddress.EndColumn &amp; &quot; ; &quot; &amp; oRangeAddress.StartRow &amp; &quot; ; &quot; &amp; oRangeAddress.EndRow &amp; chr(13) &amp; RangeName
+&apos; oAddressRanges.RemovebyName(RangeName)
+ RetrieveRangeNamefromAddress = Rangename
+End Function
+
+
+&apos; creates a sheet object from an according sectionname
+Function RetrieveSheetoutofRangeName(TableText as String)
+Dim DescriptionList() as String
+Dim SheetName as String
+Dim MaxIndex as integer
+ &apos; find out in which sheet the range is
+ DescriptionList() = ArrayOutofString(TableText,&quot;.&quot;,MaxIndex)
+ SheetName = DescriptionList(0)
+ SheetName = DeleteStr(SheetName,&quot;&apos;&quot;)
+ &apos; set the viewcursor on this sheet
+ RetrieveSheetoutofRangeName = oSheets.GetbyName(SheetName)
+End Function
+
+
+&apos; creates a rangeobject from an according rangename
+Function RetrieveRangeoutofRangeName(TableText as String)
+ oSheet = RetrieveSheetoutofRangeName(TableText)
+ oRange = oSheet.GetCellRangebyName(TableText)
+ RetrieveRangeoutofRangeName = oRange
+End Function
+
+
+Sub ConvertTheSoftWay(StyleList(), bDeSelect as Boolean)
+Dim i as Integer
+Dim l as Integer
+Dim s as Integer
+Dim n as Integer
+Dim CurStyleName as String
+Dim RangeName as String
+Dim OldStatusValue as Integer
+Dim LastIndex as Integer
+Dim oSelListbox as Object
+Dim StyleRangeList() as String
+Dim MaxIndex as Integer
+ oSelListbox = DialogConvert.GetControl(&quot;lstSelection&quot;)
+ LastIndex = Ubound(StyleList())
+ OldStatusValue = StatusValue
+ For i = 0 To LastIndex
+ CurStyleName = StyleList(i)
+ oStyle = oStyles.GetbyName(CurStyleName)
+ StyleRangeList() = GetAssignedRanges(CurStyleName, n)
+ MaxIndex = Ubound(StyleRangeList())
+ For s = 0 To MaxIndex
+ RangeName = StyleRangeList(s)
+ oRange = RetrieveRangeoutofRangeName(RangeName)
+ If oRange.getPropertyState(&quot;NumberFormat&quot;) = 1 Then
+ &apos; Range is hard formatted
+ ConvertCellCurrencies(oRange)
+ CurCellCount = CountRangeCells(oRange)
+ End If
+ IncreaseStatusvalue((CurCellCount/TotCellCount)*(95-OldStatusValue))
+ If bDeSelect Then
+ &apos; Note: On Problems see Bug #73157
+ If oSelRanges.HasbyName(RangeName) Then
+ oSelRanges.RemovebyName(RangeName)
+ oDocument.CurrentController.Select(oSelRanges)
+ End If
+ End If
+ Next s
+ SwitchNumberFormat(ostyle, oFormats, sEuroSign)
+ StyleRangeAssignmentList(n) = &quot;&quot;
+ l = GetItemPos(oSelListBox.Model, CurStyleName)
+ oSelListbox.RemoveItems(l,1)
+ Next
+End Sub
+
+
+Function GetAssignedRanges(CurStyleName as String, n as Integer)
+Dim StyleRangeList() as String
+Dim RangeString as String
+Dim AssignString as String
+ n = PartStringInArray(StyleRangeAssignmentList(), CurStyleName, 0)
+ If n &lt;&gt; -1 Then
+ AssignString = StyleRangeAssignmentList(n)
+ RangeString = FindPartString(AssignString,&quot;&lt;RANGES&gt;&quot;, &quot;&lt;/RANGES&gt;&quot;,1)
+ If RangeString &lt;&gt; &quot;&quot; Then
+ StyleRangeList() = ArrayoutofString(RangeString,&quot;,&quot;)
+ End If
+ End If
+ GetAssignedRanges() = StyleRangeList()
+End Function</script:module> \ No newline at end of file
diff --git a/wizards/source/euro/Writer.xba b/wizards/source/euro/Writer.xba
new file mode 100644
index 000000000..bf89135bc
--- /dev/null
+++ b/wizards/source/euro/Writer.xba
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Writer" script:language="StarBasic">REM ***** BASIC *****
+
+
+Sub ConvertWriterTables()
+Dim CellString as String
+Dim oParagraphs as Object
+Dim oPara as Object
+Dim i as integer
+Dim sCellNames()
+Dim oCell as Object
+ oParagraphs = oDocument.Text.CreateEnumeration
+ While oParagraphs.HasMoreElements
+ oPara = oParagraphs.NextElement
+ If NOT oPara.supportsService(&quot;com.sun.star.text.Paragraph&quot;) Then
+ &apos; Note: As cells might be split or merged
+ &apos; you cannot refer to them via their indices
+ sCellNames = oPara.CellNames
+ For i = 0 To Ubound(sCellNames)
+ If sCellNames(i) &lt;&gt; &quot;&quot; Then
+ oCell = oPara.getCellByName(sCellNames(i))
+ If CheckFormatType(oCell) Then
+ SwitchNumberFormat(oCell, oFormats, sEuroSign)
+ ModifyObjectValuewithCurrFactor(oCell)
+ End If
+ End If
+ Next
+ End If
+ Wend
+End Sub
+
+
+Sub ModifyObjectValuewithCurrFactor(oDocObject as Object)
+ oDocObjectValue = oDocObject.Value
+ oDocObject.Value = oDocObjectValue/CurrFactor
+End Sub
+
+
+Sub ConvertTextFields()
+Dim oTextFields as Object
+Dim oTextField as Object
+Dim FieldValue
+Dim oDocObjectValue as double
+Dim InstanceNames(500) as String
+Dim CurInstanceName as String
+Dim MaxIndex as Integer
+ MaxIndex = 0
+ oTextfields = oDocument.getTextfields.CreateEnumeration
+ While oTextFields.hasmoreElements
+ oTextField = oTextFields.NextElement
+ If oTextField.PropertySetInfo.HasPropertybyName(&quot;NumberFormat&quot;) Then
+ If CheckFormatType(oTextField) Then
+ If oTextField.PropertySetInfo.HasPropertybyName(&quot;Value&quot;) Then
+ If Not oTextField.SupportsService(&quot;com.sun.star.text.TextField.GetExpression&quot;) Then
+ oTextField.Content = CStr(Round(oTextField.Value/CurrFactor,2))
+ End If
+ ElseIf oTextField.TextFieldMaster.PropertySetInfo.HasPropertyByName(&quot;Value&quot;) Then
+ CurInstanceName = oTextField.TextFieldMaster.InstanceName
+ If Not FieldInArray(InstanceNames(), MaxIndex, CurInstanceName) Then
+ oTextField.TextFieldMaster.Content = CStr(Round(oTextField.TextFieldMaster.Value/CurrFactor,2))
+ InstanceNames(MaxIndex) = CurInstanceName
+ MaxIndex = MaxIndex + 1
+ End If
+ End If
+ SwitchNumberFormat(oTextField, oFormats, sEuroSign)
+ End If
+ End If
+ Wend
+ oDocument.GetTextFields.refresh()
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/euro/dialog.xlb b/wizards/source/euro/dialog.xlb
new file mode 100644
index 000000000..c461ce54f
--- /dev/null
+++ b/wizards/source/euro/dialog.xlb
@@ -0,0 +1,6 @@
+<?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="Euro" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="DlgConvert"/>
+ <library:element library:name="DlgPassword"/>
+</library:library>
diff --git a/wizards/source/euro/script.xlb b/wizards/source/euro/script.xlb
new file mode 100644
index 000000000..1bc4927c2
--- /dev/null
+++ b/wizards/source/euro/script.xlb
@@ -0,0 +1,12 @@
+<?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="Euro" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="ConvertRun"/>
+ <library:element library:name="AutoPilotRun"/>
+ <library:element library:name="Hard"/>
+ <library:element library:name="Soft"/>
+ <library:element library:name="Init"/>
+ <library:element library:name="Common"/>
+ <library:element library:name="Writer"/>
+ <library:element library:name="Protect"/>
+</library:library>
diff --git a/wizards/source/formwizard/DBMeta.xba b/wizards/source/formwizard/DBMeta.xba
new file mode 100644
index 000000000..b0fa20b7a
--- /dev/null
+++ b/wizards/source/formwizard/DBMeta.xba
@@ -0,0 +1,347 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="DBMeta" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+
+
+Public iCommandTypes() as Integer
+Public CurCommandType as Integer
+Public oDataSource as Object
+Public bEnableBinaryOptionGroup as Boolean
+&apos;Public bSelectContent as Boolean
+
+
+Function GetDatabaseNames(baddFirstListItem as Boolean)
+Dim sDatabaseList()
+ If oDBContext.HasElements Then
+ Dim LocDBList() as String
+ Dim MaxIndex as Integer
+ Dim i as Integer
+ LocDBList = oDBContext.ElementNames()
+ MaxIndex = Ubound(LocDBList())
+ If baddfirstListItem Then
+ ReDim Preserve sDatabaseList(MaxIndex + 1)
+ sDatabaseList(0) = sSelectDatasource
+ a = 1
+ Else
+ ReDim Preserve sDatabaseList(MaxIndex)
+ a = 0
+ End If
+ For i = 0 To MaxIndex
+ sDatabaseList(a) = oDBContext.ElementNames(i)
+ a = a + 1
+ Next i
+ End If
+ GetDatabaseNames() = sDatabaseList()
+End Function
+
+
+Sub GetSelectedDBMetaData(sDBName as String)
+Dim OldsDBname as String
+Dim DBIndex as Integer
+Dim LocList() as String
+&apos; If bStartUp Then
+&apos; bStartUp = false
+&apos; Exit Sub
+&apos; End Sub
+ ToggleDatabasePage(False)
+ With DialogModel
+ If GetConnection(sDBName) Then
+ If GetDBMetaData() Then
+ LocList() = AddListToList(Array(sSelectDBTable), TableNames())
+ .lstTables.StringItemList() = AddListToList(LocList(), QueryNames())
+&apos; bSelectContent = True
+ .lstTables.SelectedItems() = Array(0)
+ iCommandTypes() = CreateCommandTypeList()
+ EmptyFieldsListboxes()
+ End If
+ End If
+ bEnableBinaryOptionGroup = False
+ .lstTables.Enabled = True
+ .lblTables.Enabled = True
+&apos; Else
+&apos; DialogModel.lstTables.StringItemList = Array(sSelectDBTable)
+&apos; EmptyFieldsListboxes()
+&apos; End If
+ ToggleDatabasePage(True)
+ End With
+End Sub
+
+
+Function GetConnection(sDBName as String)
+Dim oInteractionHandler as Object
+Dim bExitLoop as Boolean
+Dim bGetConnection as Boolean
+Dim iMsg as Integer
+Dim Nulllist()
+ If Not IsNull(oDBConnection) Then
+ oDBConnection.Dispose()
+ End If
+ oDataSource = oDBContext.GetByName(sDBName)
+&apos; If Not oDBContext.hasbyName(sDBName) Then
+&apos; GetConnection() = False
+&apos; Exit Function
+&apos; End If
+ If Not oDataSource.IsPasswordRequired Then
+ oDBConnection = oDBContext.GetByName(sDBName).GetConnection(&quot;&quot;,&quot;&quot;)
+ GetConnection() = True
+ Else
+ oInteractionHandler = createUnoService(&quot;com.sun.star.task.InteractionHandler&quot;)
+ oDataSource = oDBContext.GetByName(sDBName)
+ On Local Error Goto NOCONNECTION
+ Do
+ bExitLoop = True
+ oDBConnection = oDataSource.ConnectWithCompletion(oInteractionHandler)
+ NOCONNECTION:
+ bGetConnection = Err = 0
+ If bGetConnection Then
+ bGetConnection = Not IsNull(oDBConnection)
+ If Not bGetConnection Then
+ Exit Do
+ End If
+ End If
+ If Not bGetConnection Then
+ iMsg = Msgbox (sMsgNoConnection,32 + 2, sMsgWizardName)
+ bExitLoop = iMsg = SBCANCEL
+ Resume CLERROR
+ CLERROR:
+ End If
+ Loop Until bExitLoop
+ On Local Error Goto 0
+ If Not bGetConnection Then
+ DialogModel.lstTables.StringItemList() = Array(sSelectDBTable)
+ DialogModel.lstFields.StringItemList() = NullList()
+ DialogModel.lstSelFields.StringItemList() = NullList()
+ End If
+ GetConnection() = bGetConnection
+ End If
+End Function
+
+
+Function GetDBMetaData()
+ If oDBContext.HasElements Then
+ Tablenames() = oDBConnection.Tables.ElementNames()
+ Querynames() = oDBConnection.Queries.ElementNames()
+ GetDBMetaData = True
+ Else
+ MsgBox(sMsgErrNoDatabase, 64, sMsgWizardName)
+ GetDBMetaData = False
+ End If
+End Function
+
+
+Sub GetTableMetaData()
+Dim iType as Long
+Dim m as Integer
+Dim Found as Boolean
+Dim i as Integer
+Dim sFieldName as String
+Dim n as Integer
+Dim WidthIndex as Integer
+Dim oField as Object
+ MaxIndex = Ubound(DialogModel.lstSelFields.StringItemList())
+ Dim ColumnMap(MaxIndex)as Integer
+ FieldNames() = DialogModel.lstSelFields.StringItemList()
+ &apos; Build a structure which maps the position of a selected field (within the selection) to the column position within
+ &apos; the table. So we ensure that the controls are placed in the same order the according fields are selected.
+ For i = 0 To Ubound(FieldNames())
+ sFieldName = FieldNames(i)
+ Found = False
+ n = 0
+ While (n&lt; MaxIndex And (Not Found))
+ If (FieldNames(n) = sFieldName) Then
+ Found = True
+ ColumnMap(n) = i
+ End If
+ n = n + 1
+ Wend
+ Next i
+ For n = 0 to MaxIndex
+ sFieldname = FieldNames(n)
+ oField = oColumns.GetByName(sFieldName)
+ iType = oField.Type
+ FieldMetaValues(n,0) = oField.Type
+ FieldMetaValues(n,1) = AssignFieldLength(oField.Precision)
+ FieldMetaValues(n,2) = GetValueoutofList(iType, WidthList(),1, WidthIndex)
+ FieldMetaValues(n,3) = WidthList(WidthIndex,3)
+ FieldMetaValues(n,4) = oField.FormatKey
+ FieldMetaValues(n,5) = oField.DefaultValue
+ FieldMetaValues(n,6) = oField.IsCurrency
+ FieldMetaValues(n,7) = oField.Scale
+&apos; If oField.Description &lt;&gt; &quot;&quot; Then
+&apos;&apos; Todo: What&apos;s wrong with this line?
+&apos; Msgbox oField.Helptext
+&apos; End If
+ FieldMetaValues(n,8) = oField.Description
+ Next
+ ReDim oDBShapeList(MaxIndex) as Object
+ ReDim oTCShapeList(MaxIndex) as Object
+ ReDim oDBModelList(MaxIndex) as Object
+ ReDim oGroupShapeList(MaxIndex) as Object
+End Sub
+
+
+Function GetSpecificFieldNames() as Integer
+Dim n as Integer
+Dim m as Integer
+Dim s as Integer
+Dim iType as Integer
+Dim oField as Object
+Dim MaxIndex as Integer
+Dim EmptyList()
+ If Ubound(DialogModel.lstTables.StringItemList()) &gt; -1 Then
+ FieldNames() = oColumns.GetElementNames()
+ MaxIndex = Ubound(FieldNames())
+ If MaxIndex &lt;&gt; -1 Then
+ Dim ResultFieldNames(MaxIndex)
+ ReDim ImgFieldNames(MaxIndex)
+ m = 0
+ For n = 0 To MaxIndex
+ oField = oColumns.GetByName(FieldNames(n))
+ iType = oField.Type
+ If GetIndexInMultiArray(WidthList(), iType, 0) &lt;&gt; -1 Then
+ ResultFieldNames(m) = FieldNames(n)
+ m = m + 1
+ End If
+ If GetIndexInMultiArray(ImgWidthList(), iType, 0) &lt;&gt; -1 Then
+ ImgFieldNames(s) = FieldNames(n)
+ s = s + 1
+ End If
+ Next n
+ If s &lt;&gt; 0 Then
+ Redim Preserve ImgFieldNames(s-1)
+ bEnableBinaryOptionGroup = True
+ Else
+ bEnableBinaryOptionGroup = False
+ End If
+ If (DialogModel.optBinariesasGraphics.State = 1) And (s &lt;&gt; 0) Then
+ ResultFieldNames() = AddListToList(ResultFieldNames(), ImgFieldNames())
+ Else
+ Redim Preserve ResultFieldNames(m-1)
+ End If
+ FieldNames() = ResultFieldNames()
+ DialogModel.lstFields.StringItemList = FieldNames()
+ InitializeListboxProcedures(DialogModel, DialogModel.lstFields, DialogModel.lstSelFields)
+ End If
+ GetSpecificFieldNames = MaxIndex
+ Else
+ GetSpecificFieldNames = -1
+ End If
+End Function
+
+
+Sub CreateDBForm()
+ If oDrawPage.Forms.Count = 0 Then
+ oDBForm = oDocument.CreateInstance(&quot;com.sun.star.form.component.Form&quot;)
+ oDrawpage.Forms.InsertByIndex (0, oDBForm)
+ Else
+ oDBForm = oDrawPage.Forms.GetByIndex(0)
+ End If
+ oDBForm.Name = &quot;Standard&quot;
+ oDBForm.DataSourceName = sDBName
+ oDBForm.Command = TableName
+ oDBForm.CommandType = CurCommandType
+End Sub
+
+
+Sub AddOrRemoveBinaryFieldsToWidthList()
+Dim LocWidthList()
+Dim MaxIndex as Integer
+Dim OldMaxIndex as Integer
+Dim s as Integer
+Dim n as Integer
+Dim m as Integer
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ If DialogModel.optBinariesasGraphics.State = 1 Then
+ OldMaxIndex = Ubound(WidthList(),1)
+ If OldMaxIndex = 15 Then
+ MaxIndex = Ubound(WidthList(),1) + Ubound(ImgWidthList(),1) + 1
+ ReDim Preserve WidthList(MaxIndex,4)
+ s = 0
+ For n = OldMaxIndex + 1 To MaxIndex
+ For m = 0 To 3
+ WidthList(n,m) = ImgWidthList(s,m)
+ Next m
+ s = s + 1
+ Next n
+ MergeList(DialogModel.lstFields, ImgFieldNames())
+ End If
+ Else
+ ReDim Preserve WidthList(15, 4)
+ RemoveListItems(DialogModel.lstFields(), DialogModel.lstSelFields(), ImgFieldNames())
+ End If
+ DialogModel.lstSelFields.Tag = True
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+End Sub
+
+
+Function CreateCommandTypeList()
+Dim MaxTableIndex as Integer
+Dim MaxQueryIndex as Integer
+Dim MaxIndex as Integer
+Dim i as Integer
+Dim a as Integer
+ MaxTableIndex = Ubound(TableNames())
+ MaxQueryIndex = Ubound(QueryNames())
+ MaxIndex = MaxTableIndex + MaxQueryIndex + 1
+ If MaxIndex &gt; -1 Then
+ Dim LocCommandTypes(MaxIndex) as Integer
+ For i = 0 To MaxTableIndex
+ LocCommandTypes(i) = com.sun.star.sdb.CommandType.TABLE
+ Next i
+ a = i
+ For i = 0 To MaxQueryIndex
+ LocCommandTypes(a) = com.sun.star.sdb.CommandType.QUERY
+ a = a + 1
+ Next i
+ End If
+ CreateCommandTypeList() = LocCommandTypes()
+End Function
+
+
+Sub GetCurrentMetaValues(Index as Integer)
+ CurFieldType = FieldMetaValues(Index,0)
+ CurFieldLength = FieldMetaValues(Index,1)
+ CurControlType = FieldMetaValues(Index,2)
+ CurControlName = FieldMetaValues(Index,3)
+ CurFormatKey = FieldMetaValues(Index,4)
+ CurDefaultValue = FieldMetaValues(Index,5)
+ CurIsCurrency = FieldMetaValues(Index,6)
+ CurScale = FieldMetaValues(Index,7)
+ CurHelpText = FieldMetaValues(Index,8)
+ CurFieldName = FieldNames(Index)
+End Sub
+
+
+Function AssignFieldLength(FieldLength as Long) as Integer
+ If FieldLength &gt;= 65535 Then
+ AssignFieldLength() = -1
+ Else
+ AssignFieldLength() = FieldLength
+ End If
+End Function
+</script:module>
diff --git a/wizards/source/formwizard/DlgFormDB.xdl b/wizards/source/formwizard/DlgFormDB.xdl
new file mode 100644
index 000000000..debb8bf38
--- /dev/null
+++ b/wizards/source/formwizard/DlgFormDB.xdl
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="DlgFormDB" dlg:left="96" dlg:top="28" dlg:width="270" dlg:height="210" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_DIALOG" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblSelFields" dlg:tab-index="10" dlg:left="154" dlg:top="70" dlg:width="110" dlg:height="8" dlg:page="1" dlg:value="lblSelFields"/>
+ <dlg:menulist dlg:id="lstTables" dlg:tab-index="3" dlg:left="6" dlg:top="51" dlg:width="110" dlg:height="12" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_MASTER_LBTABLES" dlg:spin="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:FormWizard.FormWizard.FormGetFields?language=Basic&amp;location=application" script:language="Script"/>
+ <script:event script:event-name="on-mousedown" script:macro-name="vnd.sun.star.script:FormWizard.FormWizard.DeleteFirstTableListBoxEntry?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:img dlg:id="imgTheme" dlg:tab-index="1" dlg:left="6" dlg:top="6" dlg:width="258" dlg:height="26" dlg:scale-image="false"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="33" dlg:left="6" dlg:top="190" dlg:width="53" dlg:height="14" dlg:help-url="HID:34401" dlg:value="cmdCancel" dlg:button-type="cancel"/>
+ <dlg:button dlg:id="cmdHelp" dlg:tab-index="34" dlg:left="63" dlg:top="190" dlg:width="53" dlg:height="14" dlg:tag="34400" dlg:value="cmdHelp" dlg:button-type="help"/>
+ <dlg:button dlg:id="cmdBack" dlg:tab-index="35" dlg:left="155" dlg:top="190" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGFORM_CMDPREV" dlg:value="cmdBack">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.FormWizard.PreviousStep?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="36" dlg:left="211" dlg:top="190" dlg:width="53" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGFORM_CMDNEXT" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.FormWizard.NextStep?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="lblTables" dlg:tab-index="2" dlg:left="6" dlg:top="40" dlg:width="72" dlg:height="8" dlg:page="1" dlg:value="lblTables"/>
+ <dlg:text dlg:id="lblFields" dlg:tab-index="4" dlg:left="6" dlg:top="70" dlg:width="109" dlg:height="8" dlg:page="1" dlg:value="lblFields"/>
+ <dlg:button dlg:id="cmdMoveSelected" dlg:tab-index="6" dlg:left="122" dlg:top="84" dlg:width="25" dlg:height="14" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_OPTONEXISTINGRELATION" dlg:value="-&gt;">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormMoveSelected?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdMoveAll" dlg:tab-index="7" dlg:left="122" dlg:top="101" dlg:width="25" dlg:height="14" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_OPTSELECTMANUALLY" dlg:value="=&gt;&gt;">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormMoveAll?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdRemoveSelected" dlg:tab-index="8" dlg:left="122" dlg:top="118" dlg:width="25" dlg:height="14" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_lstRELATIONS" dlg:value="&lt;-">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormRemoveSelected?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdRemoveAll" dlg:tab-index="9" dlg:left="122" dlg:top="135" dlg:width="25" dlg:height="14" dlg:page="1" dlg:help-url="HID:34425" dlg:value="&lt;&lt;=">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormRemoveAll?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optIgnoreBinaries" dlg:tab-index="14" dlg:left="122" dlg:top="169" dlg:width="104" dlg:height="10" dlg:page="1" dlg:help-url="HID:34427" dlg:value="optIgnoreBinaries" dlg:checked="true">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.DBMeta.AddOrRemoveBinaryFieldsToWidthList?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optBinariesasGraphics" dlg:tab-index="13" dlg:left="12" dlg:top="169" dlg:width="104" dlg:height="10" dlg:page="1" dlg:help-url="HID:34426" dlg:value="optBinariesasGraphics">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.DBMeta.AddOrRemoveBinaryFieldsToWidthList?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:menulist dlg:id="lstFields" dlg:tab-index="5" dlg:left="6" dlg:top="81" dlg:width="110" dlg:height="70" dlg:page="1" dlg:help-url="HID:34420" dlg:multiselection="true">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormMoveSelected?language=Basic&amp;location=application" script:language="Script"/>
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormSetMoveRights?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:menulist dlg:id="lstSelFields" dlg:tab-index="11" dlg:left="154" dlg:top="81" dlg:width="110" dlg:height="70" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_CHKCREATESUBFORM" dlg:multiselection="true">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormRemoveSelected?language=Basic&amp;location=application" script:language="Script"/>
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Tools.Listbox.FormSetMoveRights?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:text dlg:id="lblStyles" dlg:tab-index="25" dlg:left="150" dlg:top="39" dlg:width="114" dlg:height="8" dlg:page="2" dlg:value="lblStyles"/>
+ <dlg:button dlg:id="cmdArrange1" dlg:tab-index="16" dlg:left="12" dlg:top="50" dlg:width="23" dlg:height="25" dlg:page="2" dlg:tag="1" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_LBTABLES">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeArrangemode?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdArrange2" dlg:tab-index="17" dlg:left="39" dlg:top="50" dlg:width="23" dlg:height="25" dlg:page="2" dlg:tag="2" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_FIELDSAVAILABLE">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeArrangemode?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdArrange3" dlg:tab-index="18" dlg:left="66" dlg:top="50" dlg:width="23" dlg:height="25" dlg:page="2" dlg:tag="3" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_CMDMOVESELECTED">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeArrangemode?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdArrange4" dlg:tab-index="19" dlg:left="93" dlg:top="50" dlg:width="23" dlg:height="25" dlg:page="2" dlg:tag="4" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_CMDMOVEALL">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeArrangemode?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdArrange5" dlg:tab-index="20" dlg:left="120" dlg:top="50" dlg:width="23" dlg:height="25" dlg:page="2" dlg:tag="5" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_CMDREMOVESELECTED">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeArrangemode?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:menulist dlg:id="lstStyles" dlg:tab-index="26" dlg:left="150" dlg:top="50" dlg:width="114" dlg:height="86" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGFORM_LINKER_LSTSLAVELINK2">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:FormWizard.tools.ImportStyles?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optBorder0" dlg:tab-index="22" dlg:left="12" dlg:top="95" dlg:width="131" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_CMDMOVEUP" dlg:value="optBorder0">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeBorderLayouts?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optBorder1" dlg:tab-index="23" dlg:left="12" dlg:top="109" dlg:width="131" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGFORM_SUB_CMDMOVEDOWN" dlg:value="optBorder1">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeBorderLayouts?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optBorder2" dlg:tab-index="24" dlg:left="12" dlg:top="123" dlg:width="131" dlg:height="10" dlg:page="2" dlg:help-url="HID:34440" dlg:value="optBorder2">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeBorderLayouts?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:fixedline dlg:id="hlnBinaries" dlg:tab-index="12" dlg:left="6" dlg:top="158" dlg:width="258" dlg:height="8" dlg:page="1" dlg:value="hlnBinaries"/>
+ <dlg:fixedline dlg:id="hlnBackground" dlg:tab-index="30" dlg:left="150" dlg:top="143" dlg:width="114" dlg:height="8" dlg:page="2" dlg:value="hlnBackground"/>
+ <dlg:fixedline dlg:id="hlnAlign" dlg:tab-index="27" dlg:left="6" dlg:top="143" dlg:width="137" dlg:height="8" dlg:page="2" dlg:value="hlnAlign"/>
+ <dlg:fixedline dlg:id="hlnBorderLayout" dlg:tab-index="21" dlg:left="6" dlg:top="83" dlg:width="137" dlg:height="8" dlg:page="2" dlg:value="hlnBorderLayout"/>
+ <dlg:fixedline dlg:id="hlnArrangements" dlg:tab-index="15" dlg:left="6" dlg:top="39" dlg:width="137" dlg:height="8" dlg:page="2" dlg:value="hlnArrangements"/>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optAlign0" dlg:tab-index="28" dlg:left="12" dlg:top="154" dlg:width="131" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGFORM_LINKER_LSTSLAVELINK1" dlg:value="optAlign0">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeLabelAlignments?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="optAlign2" dlg:tab-index="29" dlg:left="12" dlg:top="168" dlg:width="131" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGFORM_LINKER_LSTMASTERLINK1" dlg:value="optAlign2">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:FormWizard.Layouter.ChangeLabelAlignments?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:fixedline dlg:id="FixedLine1" dlg:tab-index="0" dlg:left="6" dlg:top="180" dlg:width="258" dlg:height="6"/>
+ </dlg:bulletinboard>
+</dlg:window>
diff --git a/wizards/source/formwizard/FormWizard.xba b/wizards/source/formwizard/FormWizard.xba
new file mode 100644
index 000000000..68a80ff88
--- /dev/null
+++ b/wizards/source/formwizard/FormWizard.xba
@@ -0,0 +1,440 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="FormWizard" script:language="StarBasic">Option Explicit
+
+Public DocumentName as String
+Public FormPath as String
+Public WizardPath as String
+Public WorkPath as String
+Public TempPath as String
+Public TexturePath as String
+Public sQueryName as String
+Public oDBConnection as Object
+Public bWithBackGraphic as Boolean
+Public bNeedFieldRefresh as Boolean
+Public oDBForm as Object
+Public oColumns() as Object
+Public sDatabaseList() as String
+Public TableNames() as String
+Public QueryNames() as String
+Public FieldNames() as String
+Public ImgFieldNames() as String
+Public oDBContext as Object
+Public oUcb as Object
+Public oDocInfo as Object
+Public WidthList(15,3)
+Public ImgWidthList(3,3)
+Public sDBName as String
+Public Tablename as String
+Public Const SBSIZETEXT = &quot;The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.&quot;
+Public bDisposeDoc as Boolean
+Public bDebug as Boolean
+&apos;Public bStartUp as Boolean
+Public bConnectionIsovergiven as Boolean
+Public FormName As String
+Public sFormUrl as String
+Public oFormDocuments
+
+
+&apos; The macro can be called in 4 possible scenarios:
+&apos; Scenario 1. No parameters at given
+&apos; Scenario 2: Only Datasourcename is given, but no connection and no Content
+&apos; Scenario 3: a data source and a connection are given
+&apos; Scenario 4: all parameters (data source name, connection, object type and object) are given
+
+Sub Main()
+Dim oLocDBContext as Object
+Dim oLocConnection as Object
+
+&apos; Scenario 1. No parameters at given
+ MainWithDefault()
+
+&apos; Scenario 2: Only Datasourcename is given, but no connection and no Content
+&apos; MainWithDefault(&quot;Bibliography&quot;)
+
+&apos; Scenario 3: a data source and a connection are given
+&apos; oLocDBContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+&apos; oLocConnection = oLocDBContext.GetByName(&quot;Bibliography&quot;).GetConnection(&quot;&quot;,&quot;&quot;)
+&apos; MainWithDefault(&quot;Bibliography&quot;, oLocConnection)
+
+&apos; Scenario 4: all parameters (data source name, connection, object type and object) are given
+&apos; oLocDBContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+&apos; oLocConnection = oLocDBContext.GetByName(&quot;Bibliography&quot;).GetConnection(&quot;&quot;,&quot;&quot;)
+&apos; MainWithDefault(&quot;Bibliography&quot;, oLocConnection, com.sun.star.sdb.CommandType.TABLE, &quot;biblio&quot;)
+End Sub
+
+
+Sub MainWithDefault(Optional DatasourceName as String, Optional oConnection as Object, Optional CommandType as Integer, Optional sContent as String)
+Dim i as Integer
+Dim SelCount as Integer
+Dim RetValue as Integer
+Dim SelList(0) as Integer
+Dim LocList() as String
+ SelList(0) = 0
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ bDebug = False
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ OpenFormDocument()
+ CurArrangement = 0
+ bControlsareCreated = False
+ bEnableBinaryOptionGroup = False
+ bDisposeDoc = True
+ MaxIndex = -1
+ If Not InitResources(&quot;Formwizard&quot;) Then
+ Exit Sub
+ End If
+ oDBContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ If GetFormWizardPaths() = False Then
+ Exit Sub
+ End If
+ oDocument.GetCurrentController().Frame.ComponentWindow.Enable = False
+ oProgressBar.Value = 10
+ LoadLanguage()
+ oProgressBar.Value = 20
+ InitializeWidthList()
+ oProgressBar.Value = 30
+ Styles() = getListBoxArrays(oUcb, &quot;/stl&quot;)
+ CurIndex = GetCurIndex(DialogModel, Styles(), 2)
+ oProgressBar.Value = 40
+ ConfigurePageStyle()
+ oProgressBar.Value = 50
+ InitializeLabelValues()
+ bNeedFieldRefresh = True
+ SetDialogLanguage()
+&apos; bStartUp = true
+ With DialogModel
+ .cmdBack.Enabled = False
+ .cmdGoOn.Enabled = False
+ .lblTables.Enabled = False
+ .lstSelFields.Tag = False
+ .Step = 1
+ End With
+ oProgressBar.Value = 60
+ bConnectionIsovergiven = Not IsMissing(oConnection)
+ If Not IsMissing(DataSourceName) Then
+ sDBName = DataSourceName
+ If Not IsMissing(oConnection) Then
+ &apos; Scenario 3: a data source and a connection are given
+ Set oDBConnection = oConnection
+ oDataSource = oDBContext.GetByName(DataSourceName)
+ DialogModel.lstTables.Enabled = True
+ DialogModel.lblTables.Enabled = True
+ If GetDBMetaData() Then
+ LocList() = AddListToList(TableNames(), QueryNames())
+ iCommandTypes = CreateCommandTypeList()
+ If Not IsMissing(sContent) Then
+ &apos; Scenario 4: all parameters (data source name, connection, object type and object) are given
+ DialogModel.lstTables.StringItemList() = LocList()
+ iCommandTypes() = CreateCommandTypeList()
+ SelCount = CountItemsInArray(DialogModel.lstTables.StringItemList(), sContent)
+ If SelCount = 1 Then
+ DlgFormDB.GetControl(&quot;lstTables&quot;).SelectItem(sContent, True)
+ Else
+ If CommandType = com.sun.star.sdb.CommandType.QUERY Then
+ SelIndex = IndexInArray(sContent, QueryNames())
+ DlgFormDB.GetControl(&quot;lstTables&quot;).SelectItemPos(SelIndex, True)
+ ElseIf CommandType = com.sun.star.sdb.CommandType.TABLE Then
+ SelIndex = IndexInArray(sContent, TableNames())
+ DlgFormDB.GetControl(&quot;lstTables&quot;).SelectItemPos(Ubound(QueryNames()+1 + SelIndex, True))
+ End If
+ End If
+ CurCommandType = CommandType
+ FillUpFieldsListbox(False)
+ Else
+ LocList() = AddListToList(Array(sSelectDBTable), LocList())
+ DialogModel.lstTables.StringItemList() = LocList()
+&apos; bSelectContent = True
+ DialogModel.lstTables.SelectedItems() = Array(0)
+
+ End If
+ End If
+ Else
+ &apos; Scenario 2: Only Datasourcename is given, but no connection and no Content
+ GetSelectedDBMetaData(sDBName)
+ End If
+ Else
+ &apos; Scenario 1: No parameters are given
+ ToggleListboxControls(DialogModel, False)
+ End If
+ oProgressBar.Value = 80
+ bWithBackGraphic = LoadNewStyles(oDocument, DialogModel, CurIndex, Styles(CurIndex, 8), Styles(), TexturePath)
+ DlgFormDB.Title = WizardTitle(1)
+ DialogModel.lstStyles.StringItemList() = ArrayfromMultiArray(Styles, 1)
+ DialogModel.lstStyles.SelectedItems() = SelList()
+ ControlCaptionsToStandardLayout()
+ oDocument.GetCurrentController().Frame.ComponentWindow.Enable = True
+ oProgressBar.Value = 90
+ DialogModel.imgTheme.ImageURL = FormPath &amp; &quot;FormWizard_1.png&quot;
+ DialogModel.imgTheme.BackGroundColor = RGB(0,60,126)
+ ToggleDatabasePage(True)
+ oProgressBar.Value = 100
+ DlgFormDB.GetControl(&quot;lstTables&quot;).SetFocus()
+ oProgressbar.End
+ RetValue = DlgFormDB.Execute()
+ DlgFormDB.Dispose()
+ If bDisposeDoc Then
+ Dim aPropertyValues(2) as new com.sun.star.beans.PropertyValue
+ oFormDocuments = oDataSource.getFormDocuments()
+ DlgFormDB.Dispose()
+ oDocument.dispose()
+ Dim bLinkExists as Boolean
+ i = 1
+ Dim FormBaseName as String
+ FormBaseName = FormName
+ Do
+ bLinkExists = oFormDocuments.HasbyHierarchicalName(FormName)
+ If bLinkExists Then
+ i = i + 1
+ FormName = FormBaseName &amp; &quot;_&quot; &amp; i
+ End If
+ Loop Until Not bLinkExists
+ aPropertyValues(0).Name = &quot;Name&quot;
+ aPropertyValues(0).Value = FormName
+ aPropertyValues(1).Name = &quot;Parent&quot;
+ aPropertyValues(1).Value = oFormDocuments()
+ aPropertyValues(2).Name = &quot;URL&quot;
+ aPropertyValues(2).Value = sFormUrl
+ Dim oDBDocument
+ oDBDocument = oFormDocuments.createInstanceWithArguments(&quot;com.sun.star.sdb.DocumentDefinition&quot;, aPropertyValues())
+ oFormDocuments.insertbyName(FormName, oDBDocument)
+ ElseIf RetValue = 0 Then
+ RemoveNirwanaShapes()
+ End If
+ If ((Not IsNull(oDBConnection)) And (Not bConnectionIsovergiven)) Then
+ oDBConnection.Dispose()
+ End If
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+End Sub
+
+
+Sub FormGetFields()
+Dim i as Integer
+&apos; If bSelectContent Then
+&apos; bSelectContent = False
+&apos; Exit Sub
+&apos; End If
+ DeleteFirstListBoxEntry(&quot;lstTables&quot;, sSelectDBTable)
+ ToggleDatabasePage(False)
+ FillUpFieldsListbox(True)
+ ToggleDatabasePage(True)
+End Sub
+
+
+Sub FillUpFieldsListbox(bGetCommandType as Boolean)
+Dim SelIndex as Integer
+Dim QueryIndex as Integer
+ If Not bDebug Then
+ On Local Error GoTo NOFIELDS
+ End If
+ SelIndex = DlgFormDB.GetControl(&quot;lstTables&quot;).getSelectedItemPos() &apos;.SelectedItems())
+ If SelIndex &gt; -1 Then
+ If bGetCommandType Then
+ CurCommandType = iCommandTypes(SelIndex)
+ End If
+ If CurCommandType = com.sun.star.sdb.CommandType.QUERY Then
+ QueryIndex = SelIndex - Ubound(Tablenames()) - 1
+ Tablename = QueryNames(QueryIndex)
+ oColumns = oDBConnection.Queries.GetByName(TableName).Columns
+ Else
+ Tablename = Tablenames(SelIndex)
+ oColumns = oDBConnection.Tables.GetByName(Tablename).Columns
+ End If
+ If GetSpecificFieldNames() &lt;&gt; -1 Then
+ ToggleListboxControls(DialogModel, True)
+ Exit Sub
+ End If
+ End If
+ EmptyFieldsListboxes()
+NOFIELDS:
+ If Err &lt;&gt; 0 Then
+ MsgBox sMsgErrCouldNotOpenObject, 16, sMsgWizardName
+ End If
+End Sub
+
+
+Sub PreviousStep()
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ With DialogModel
+ .Step = 1
+ .cmdBack.Enabled = False
+ .cmdGoOn.Enabled = True
+ .lstSelFields.Tag = Not bControlsareCreated
+ .cmdGoOn.Label = sGoOn
+ .imgTheme.ImageUrl = FormPath &amp; &quot;FormWizard_1.png&quot;
+ End With
+ FormSetMoveRights()
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+End Sub
+
+
+Sub NextStep()
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ Select Case DialogModel.Step
+ Case 1
+ bControlsAreCreated = Not (cBool(DialogModel.lstSelFields.Tag))
+ If Not bControlsAreCreated Then
+ GetTableMetaData()
+ CreateDBForm()
+ RemoveShapes()
+ InitializeLayoutSettings()
+ oDBForm.Load
+ End If
+ DialogModel.cmdGoOn.Label = sReady
+ DialogModel.cmdBack.Enabled = True
+ DialogModel.Step = 2
+ bDisposeDoc = False
+ Case 2
+ StoreForm()
+ DlgFormDB.EndExecute()
+ exit Sub
+ End Select
+ DialogModel.imgTheme.ImageUrl = FormPath &amp; &quot;FormWizard_&quot; &amp; DialogModel.Step &amp; &quot;.png&quot;
+ DlgFormDB.Title = WizardTitle(DialogModel.Step)
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+End Sub
+
+
+Sub InitializeLayoutSettings()
+ SwitchArrangementButtons(cTabled)
+ SwitchAlignMode(SBALIGNLEFT)
+ SwitchBorderMode(SB3DBORDER)
+ ToggleBorderGroup(bControlsAreCreated)
+ ToggleAlignGroup(bControlsAreCreated)
+ ArrangeControls()
+ If OldAlignMode &lt;&gt; 0 Then
+ DlgFormDB.GetControl(&quot;optAlign2&quot;).Model.State = 0
+ End If
+End Sub
+
+
+Sub ToggleDatabasePage(bDoEnable as Boolean)
+ With DialogModel
+ .cmdBack.Enabled = False
+ .cmdHelp.Enabled = bDoEnable
+ .cmdGoOn.Enabled = Ubound(DialogModel.lstSelFields.StringItemList()) &lt;&gt; -1
+ .hlnBinaries.Enabled = ((bDoEnable = True) And (bEnableBinaryOptionGroup = True))
+ .optIgnoreBinaries.Enabled = ((bDoEnable = True) And (bEnableBinaryOptionGroup = True))
+ .optBinariesasGraphics.Enabled = ((bDoEnable = True) And (bEnableBinaryOptionGroup = True))
+ End With
+End Sub
+
+
+&apos; This Sub is called from the Procedure &quot;StoreDocument&quot; in the &quot;Tools&quot; Library
+Sub CommitLastDocumentChanges(sTargetPath as String)
+Dim i as Integer
+Dim sBookmarkName as String
+Dim oDBBookmarks as Object
+Dim bLinkExists as Boolean
+Dim sBaseBookmarkName as String
+ sBookmarkName = GetFileNamewithoutExtension(FileNameoutofPath(sTargetPath))
+ sBaseBookmarkName = sBookmarkName
+ oDBBookmarks = oDataSource.GetBookmarks()
+ i = 1
+ Do
+ bLinkExists = oDBBookmarks.HasbyName(sBookmarkName)
+ If bLinkExists Then
+ i = i + 1
+ sBookmarkName = sBaseBookmarkName &amp; &quot;_&quot; &amp; i
+ Else
+ oDBBookmarks.insertByName(sBookmarkName, sTargetPath)
+ End If
+ Loop Until Not bLinkExists
+ bDisposeDoc = False
+ GroupShapesTogether()
+ ToggleDesignMode(oDocument)
+ oDBForm.Reload()
+End Sub
+
+
+Sub StoreFormInDatabase()
+ Dim NoArgs() as new com.sun.star.beans.PropertyValue
+ FormName = &quot;Form_&quot; &amp; sDBName &amp; &quot;_&quot; &amp; TableName &amp; &quot;.sxw&quot;
+ sFormUrl = TempPath &amp; &quot;/&quot; &amp; FormName
+ oDocument.StoreAsUrl(sFormUrl, NoArgs())
+ bdisposeDoc = true
+ DlgFormDB.Endexecute()
+End Sub
+
+
+Sub StoreForm()
+Dim sTargetPath as String
+Dim TypeNames(0,2) as String
+Dim oMasterKey as Object
+Dim oTypes() as Object
+ oMasterKey = GetRegistryKeyContent(&quot;org.openoffice.TypeDetection.Types/&quot;)
+ oTypes() = oMasterKey.Types
+ TypeNames(0,0) = GetFilterName(&quot;StarOffice XML (Writer)&quot;)
+ TypeNames(0,1) = &quot;*.sxw&quot;
+ TypeNames(0,2) = &quot;&quot;
+ StoreFormInDatabase()
+&apos; sTargetPath = StoreDocument(oDocument, TypeNames(), &quot;Form_&quot; &amp; sDBName &amp; &quot;_&quot; &amp; TableName &amp; &quot;.sxw&quot;, WorkPath, 1)
+End Sub
+
+
+Sub EmptyFieldsListboxes()
+Dim NullList() as String
+ ToggleListboxControls(DialogModel, False)
+ DialogModel.lstFields.StringItemList() = NullList()
+ DialogModel.lstSelFields.StringItemList() = NullList()
+ bEnableBinaryOptionGroup = False
+End Sub
+
+
+Sub DeleteFirstTableListBoxEntry()
+ DeleteFirstListBoxEntry(&quot;lstTables&quot;, sSelectDBTable)
+End Sub
+
+Sub DeleteFirstListboxEntry(ListBoxName as String, DelEntryName as String)
+Dim oListbox as Object
+Dim sFirstItem as String
+dim iSelPos as Integer
+ oListBox = DlgFormDB.getControl(ListBoxName)
+ sFirstItem = oListBox.getItem(0)
+ If sFirstItem = DelEntryName Then
+ iSelPos = oListBox.getSelectedItemPos()
+ oListBox.removeItems(0, 1)
+ If iSelPos &gt; 0 Then
+ oListBox.selectItemPos(iSelPos-1, True)
+ End If
+ End If
+End Sub
+</script:module>
diff --git a/wizards/source/formwizard/Language.xba b/wizards/source/formwizard/Language.xba
new file mode 100644
index 000000000..6346f8bae
--- /dev/null
+++ b/wizards/source/formwizard/Language.xba
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Language" script:language="StarBasic">Option Explicit
+
+
+Public Const SBCANCEL = 2
+Public Const SBREPEAT = 4
+Public LabelDiffHeight as Long
+Public BasicLabelDiffHeight as Long
+
+Public WizardTitle(1 To 3) as String
+Public DlgFormDB as Object
+Public DialogModel as Object
+
+Dim sMsgWizardName as String
+Dim sMsgErrMsg as String
+Dim sMsgErrNoDatabase as String
+Dim sMsgErrNoTableInDatabase as String
+Dim sMsgErrTitleSuggestedExist as String
+Dim sMsgErrTitleSyntaxError as String
+Dim sMsgErrTitleAsTableExist as String
+Dim sMsgProgressText as String
+Dim sMsgCreatedForm as String
+Dim sMsgErrCouldNotOpenObject as String
+Dim sMsgErrNameToLong as String
+Dim sTimeAppendix as String
+Dim sDateAppendix as String
+Public sGoOn as String
+Public sReady as String
+Public sMsgNoConnection as String
+Public XPixelFactor as Long
+Public YPixelFactor as Long
+Public sSelectDatasource as String
+Public sSelectDBTable as String
+
+
+
+Sub LoadLanguage ()
+ sMsgWizardName = GetResText(&quot;RID_FORM_0&quot;)
+ sMsgErrMsg = GetResText(&quot;RID_DB_COMMON_6&quot;)
+ sMsgErrNoDatabase = GetResText(&quot;RID_DB_COMMON_8&quot;)
+ sMsgErrNoTableInDatabase = GetResText(&quot;RID_DB_COMMON_9&quot;)
+ sMsgErrTitleSuggestedExist = GetResText(&quot;RID_DB_COMMON_10&quot;)
+ sMsgErrTitleAsTableExist = GetResText(&quot;RID_DB_COMMON_10&quot;)
+ sMsgErrTitleSyntaxError = GetResText(&quot;RID_DB_COMMON_11&quot;)
+ sMsgNoConnection = GetResText(&quot;RID_DB_COMMON_14&quot;)
+ sMsgProgressText = GetResText(&quot;RID_FORM_2&quot;)
+ sMsgCreatedForm = GetResText(&quot;RID_FORM_26&quot;)
+ sMsgErrNameToLong = GetResText(&quot;RID_FORM_27&quot;)
+ sMsgErrCouldNotOpenObject = GetResText(&quot;RID_DB_COMMON_13&quot;)
+
+ &apos; Internal Logic
+ sDateAppendix = GetResText(&quot;RID_FORM_4&quot;)
+ sTimeAppendix = GetResText(&quot;RID_FORM_5&quot;)
+
+ sReady = GetResText(&quot;RID_DB_COMMON_0&quot;)
+End Sub
+
+
+Sub SetDialogLanguage ()
+Dim i as Integer
+Dim ButtonHelpText as String
+Dim CmdButton as Object
+Dim IDArray as Variant
+Dim FNameAddOn as String
+Dim slblSelFields as String
+Dim slblFields as String
+
+ DlgFormDB = LoadDialog(&quot;FormWizard&quot;, &quot;DlgFormDB&quot;)
+ DialogModel = DlgFormDB.Model
+
+ With DialogModel
+ .cmdCancel.Label = GetResText(&quot;RID_DB_COMMON_1&quot;)
+ .cmdBack.Label = GetResText(&quot;RID_DB_COMMON_2&quot;)
+ .cmdHelp.Label = GetResText(&quot;RID_DB_COMMON_20&quot;)
+ sGoOn = GetResText(&quot;RID_DB_COMMON_3&quot;)
+ .cmdGoOn.Label = sGoOn
+ .lblTables.Label = GetResText(&quot;RID_FORM_6&quot;)
+
+ slblFields = GetResText(&quot;RID_FORM_12&quot;)
+ slblSelFields = GetResText(&quot;RID_FORM_13&quot;)
+ .lblFields.Label = slblFields
+ .lblSelFields.Label = slblSelFields
+
+ .lblStyles.Label = GetResText(&quot;RID_FORM_21&quot;)
+ .hlnBorderLayout.Label = GetResText(&quot;RID_FORM_28&quot;)
+ .hlnAlign.Label = GetResText(&quot;RID_FORM_32&quot;)
+ .hlnArrangements.Label = GetResText(&quot;RID_FORM_35&quot;)
+
+ WizardTitle(1) = sMsgWizardName &amp; &quot; - &quot; &amp; GetResText(&quot;RID_FORM_45&quot;)
+ WizardTitle(2) = sMsgWizardName &amp; &quot; - &quot; &amp; GetResText(&quot;RID_FORM_46&quot;)
+ WizardTitle(3) = sMsgWizardName &amp; &quot; - &quot; &amp; GetResText(&quot;RID_FORM_47&quot;)
+
+ .hlnBinaries.Label = GetResText(&quot;RID_FORM_50&quot;)
+ .optIgnoreBinaries.Label = GetResText(&quot;RID_FORM_51&quot;)
+ .optBinariesasGraphics.Label = GetResText(&quot;RID_FORM_52&quot;)
+
+ .hlnBackground.Label = GetResText(&quot;RID_FORM_55&quot;)
+ .optTiled.Label = GetResText(&quot;RID_FORM_56&quot;)
+ .optArea.Label = GetResText(&quot;RID_FORM_57&quot;)
+
+ .optBorder0.Label = GetResText(&quot;RID_FORM_29&quot;)
+ .optBorder1.Label = GetResText(&quot;RID_FORM_30&quot;)
+ .optBorder2.Label = GetResText(&quot;RID_FORM_31&quot;)
+ .optBorder1.State = 1
+
+ .optAlign0.Label = GetResText(&quot;RID_FORM_33&quot;)
+ .optAlign2.Label = GetResText(&quot;RID_FORM_34&quot;)
+ .optAlign0.State = 1
+
+ REM//FIXME: Remove this unused FNameAddOn through the file
+ FNameAddOn = &quot;&quot;
+
+ IDArray = Array(&quot;RID_FORM_36&quot;, &quot;RID_FORM_37&quot;, &quot;RID_FORM_40&quot;, &quot;RID_FORM_38&quot;, &quot;RID_FORM_39&quot;)
+ For i = 1 To 5
+ ButtonHelpText = GetResText(IDArray(i-1))
+ cmdButton = DlgFormDB.getControl(&quot;cmdArrange&quot; &amp; i)
+ cmdButton.Model.ImageURL = FormPath &amp; &quot;Arrange_&quot; &amp; i &amp; FNameAddOn &amp; &quot;.gif&quot;
+ cmdButton.Model.HelpText = ButtonHelpText
+ cmdButton.getPeer().setProperty(&quot;AccessibleName&quot;, ButtonHelpText)
+ Next i
+&apos; .cmdArrange1.ImageURL = FormPath &amp; &quot;Arrange_1&quot; &amp; FNameAddOn &amp; &quot;.gif&quot;
+&apos; .cmdArrange1.HelpText = GetResText(&quot;RID_FORM_36&quot;)
+&apos;
+&apos; .cmdArrange2.ImageURL = FormPath &amp; &quot;Arrange_2&quot; &amp; FNameAddOn &amp; &quot;.gif&quot;
+&apos; .cmdArrange2.HelpText = GetResText(&quot;RID_FORM_37&quot;)
+&apos;
+&apos; .cmdArrange3.ImageURL = FormPath &amp; &quot;Arrange_3&quot; &amp; FNameAddOn &amp; &quot;.gif&quot;
+&apos; .cmdArrange3.HelpText = GetResText(&quot;RID_FORM_40&quot;)
+&apos;
+&apos; .cmdArrange4.ImageURL = FormPath &amp; &quot;Arrange_4&quot; &amp; FNameAddOn &amp; &quot;.gif&quot;
+&apos; .cmdArrange4.HelpText = GetResText(&quot;RID_FORM_38&quot;)
+&apos;
+&apos; .cmdArrange5.ImageURL = FormPath &amp; &quot;Arrange_5&quot; &amp; FNameAddOn &amp; &quot;.gif&quot;
+&apos; .cmdArrange5.HelpText = GetResText(&quot;RID_FORM_39&quot;)
+ End With
+ DlgFormDB.GetControl(&quot;cmdMoveSelected&quot;).getPeer().setProperty(&quot;AccessibleName&quot;, GetResText(&quot;RID_DB_COMMON_39&quot;))
+ DlgFormDB.GetControl(&quot;cmdRemoveSelected&quot;).getPeer().setProperty(&quot;AccessibleName&quot;, GetResText(&quot;RID_DB_COMMON_40&quot;))
+ DlgFormDB.GetControl(&quot;cmdMoveAll&quot;).getPeer().setProperty(&quot;AccessibleName&quot;, GetResText(&quot;RID_DB_COMMON_41&quot;))
+ DlgFormDB.GetControl(&quot;cmdRemoveAll&quot;).getPeer().setProperty(&quot;AccessibleName&quot;, GetResText(&quot;RID_DB_COMMON_42&quot;))
+ DlgFormDB.getControl(&quot;lstFields&quot;).getPeer().setProperty(&quot;AccessibleName&quot;, DeleteStr(slblFields, &quot;~&quot;))
+ DlgFormDB.getControl(&quot;lstSelFields&quot;).getPeer().setProperty(&quot;AccessibleName&quot;, DeleteStr(slblSelFields, &quot;~&quot;))
+
+ sSelectDatasource = GetResText(&quot;RID_DB_COMMON_37&quot;)
+ sSelectDBTable = GetResText(&quot;RID_DB_COMMON_38&quot;)
+End Sub
+
+
+
+Sub InitializeWidthList()
+
+ If Ubound(WidthList(),1) &gt; 16 Then
+ ReDim WidthList(16,4)
+ End If
+
+ WidthList(0,0) = com.sun.star.sdbc.DataType.BIT &apos; = -7;
+ WidthList(0,1) = cCheckbox
+ WidthList(0,2) = False
+ WidthList(0,3) = &quot;CheckBox&quot;
+
+ WidthList(1,0) = com.sun.star.sdbc.DataType.TINYINT &apos; = -6;
+ WidthList(1,1) = cNumericBox
+ WidthList(1,2) = False
+ WidthList(1,3) = &quot;FormattedField&quot;
+
+ WidthList(2,0) = com.sun.star.sdbc.DataType.SMALLINT &apos; = 5;
+ WidthList(2,1) = cNumericBox
+ WidthList(2,2) = False
+ WidthList(2,3) = &quot;FormattedField&quot;
+
+ WidthList(3,0) = com.sun.star.sdbc.DataType.INTEGER &apos; = 4;
+ WidthList(3,1) = cNumericBox
+ WidthList(3,2) = False
+ WidthList(3,3) = &quot;FormattedField&quot;
+
+ WidthList(4,0) = com.sun.star.sdbc.DataType.BIGINT &apos; = -5;
+ WidthList(4,1) = cNumericBox
+ WidthList(4,2) = False
+ WidthList(4,3) = &quot;FormattedField&quot;
+
+ WidthList(5,0) = com.sun.star.sdbc.DataType.FLOAT &apos; = 6;
+ WidthList(5,1) = cNumericBox
+ WidthList(5,2) = False
+ WidthList(5,3) = &quot;FormattedField&quot;
+
+ WidthList(6,0) = com.sun.star.sdbc.DataType.REAL &apos; = 7;
+ WidthList(6,1) = cNumericBox
+ WidthList(6,2) = False
+ WidthList(6,3) = &quot;FormattedField&quot;
+
+ WidthList(7,0) = com.sun.star.sdbc.DataType.DOUBLE &apos; = 8;
+ WidthList(7,1) = cNumericBox
+ WidthList(7,2) = False
+ WidthList(7,3) = &quot;FormattedField&quot;
+
+ WidthList(8,0) = com.sun.star.sdbc.DataType.NUMERIC &apos; = 2;
+ WidthList(8,1) = cNumericBox
+ WidthList(8,2) = False
+ WidthList(8,3) = &quot;FormattedField&quot;
+
+ WidthList(9,0) = com.sun.star.sdbc.DataType.DECIMAL &apos; = 3; (including decimal places)
+ WidthList(9,1) = cNumericBox
+ WidthList(9,2) = False
+ WidthList(9,3) = &quot;FormattedField&quot;
+
+ WidthList(10,0) = com.sun.star.sdbc.DataType.CHAR &apos; = 1;
+ WidthList(10,1) = cTextBox
+ WidthList(10,2) = False
+ WidthList(10,3) = &quot;TextField&quot;
+
+ WidthList(11,0) = com.sun.star.sdbc.DataType.VARCHAR &apos; = 12;
+ WidthList(11,1) = cTextBox
+ WidthList(11,2) = True
+ WidthList(11,3) = &quot;TextField&quot;
+
+ WidthList(12,0) = com.sun.star.sdbc.DataType.LONGVARCHAR &apos; = -1;
+ WidthList(12,1) = cTextBox
+ WidthList(12,2) = True
+ WidthList(12,3) = &quot;TextField&quot;
+
+ WidthList(13,0) = com.sun.star.sdbc.DataType.DATE &apos; = 91;
+ WidthList(13,1) = cDateBox
+ WidthList(13,2) = False
+ WidthList(13,3) = &quot;DateField&quot;
+
+ WidthList(14,0) = com.sun.star.sdbc.DataType.TIME &apos; = 92;
+ WidthList(14,1) = cTimeBox
+ WidthList(14,2) = False
+ WidthList(14,3) = &quot;TimeField&quot;
+
+ WidthList(15,0) = com.sun.star.sdbc.DataType.TIMESTAMP &apos; = 93;
+ WidthList(15,1) = cDateBox
+ WidthList(15,2) = False
+ WidthList(15,3) = &quot;DateField&quot;
+
+ WidthList(16,0) = com.sun.star.sdbc.DataType.BOOLEAN &apos; = 16;
+ WidthList(16,1) = cCheckbox
+ WidthList(16,2) = False
+ WidthList(16,3) = &quot;CheckBox&quot;
+
+ ImgWidthList(0,0) = com.sun.star.sdbc.DataType.BINARY &apos; = -2;
+ ImgWidthList(0,1) = cImageControl
+ ImgWidthList(0,2) = False
+ ImgWidthList(0,3) = &quot;ImageControl&quot;
+
+ ImgWidthList(1,0) = com.sun.star.sdbc.DataType.VARBINARY &apos; = -3;
+ ImgWidthList(1,1) = cImageControl
+ ImgWidthList(1,2) = False
+ ImgWidthList(1,3) = &quot;ImageControl&quot;
+
+ ImgWidthList(2,0) = com.sun.star.sdbc.DataType.LONGVARBINARY &apos; = -4;
+ ImgWidthList(2,1) = cImageControl
+ ImgWidthList(2,2) = False
+ ImgWidthList(2,3) = &quot;ImageControl&quot;
+
+ ImgWidthList(3,0) = com.sun.star.sdbc.DataType.BLOB &apos; = 2004;
+ ImgWidthList(3,1) = cImageControl
+ ImgWidthList(3,2) = False
+ ImgWidthList(3,3) = &quot;ImageControl&quot;
+
+&apos; Note: the following Fieldtypes are ignored
+&apos;ExcludeList(0) = com.sun.star.sdbc.DataType.SQLNULL
+&apos;ExcludeList(1) = com.sun.star.sdbc.DataType.OTHER
+&apos;ExcludeList(2) = com.sun.star.sdbc.DataType.OBJECT
+&apos;ExcludeList(3) = com.sun.star.sdbc.DataType.DISTINCT
+&apos;ExcludeList(4) = com.sun.star.sdbc.DataType.STRUCT
+&apos;ExcludeList(5) = com.sun.star.sdbc.DataType.ARRAY
+&apos;ExcludeList(6) = com.sun.star.sdbc.DataType.CLOB
+&apos;ExcludeList(7) = com.sun.star.sdbc.DataType.REF
+
+ oModelService(cLabel) = &quot;com.sun.star.form.component.FixedText&quot;
+ oModelService(cTextBox) = &quot;com.sun.star.form.component.TextField&quot;
+ oModelService(cCheckBox) = &quot;com.sun.star.form.component.CheckBox&quot;
+ oModelService(cDateBox) = &quot;com.sun.star.form.component.DateField&quot;
+ oModelService(cTimeBox) = &quot;com.sun.star.form.component.TimeField&quot;
+ oModelService(cNumericBox) = &quot;com.sun.star.form.component.FormattedField&quot;
+ oModelService(cGridControl) = &quot;com.sun.star.form.component.GridControl&quot;
+ oModelService(cImageControl) = &quot;com.sun.star.form.component.DatabaseImageControl&quot;
+End Sub
+</script:module>
diff --git a/wizards/source/formwizard/Layouter.xba b/wizards/source/formwizard/Layouter.xba
new file mode 100644
index 000000000..24b209ad6
--- /dev/null
+++ b/wizards/source/formwizard/Layouter.xba
@@ -0,0 +1,397 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Layouter" script:language="StarBasic">Option Explicit
+
+Public oProgressbar as Object
+Public ProgressValue as Integer
+Public oDocument as Object
+Public oController as Object
+Public oForm as Object
+Public oDrawPage as Object
+Public oPageStyle as Object
+
+Public nMaxColRightX as Long
+Public nMaxTCWidth as Long
+Public nMaxRowRightX as Long
+Public nMaxRowY as Long
+Public nSecMaxRowY as Long
+Public MaxIndex as Integer
+Public CurIndex as Integer
+
+Public Const cVertDistance = 200
+Public Const cHoriDistance = 300
+
+Public nPageWidth as Long
+Public nPageHeight as Long
+Public nFormWidth as Long
+Public nFormHeight as Long
+Public nMaxHoriPos as Long
+Public nMaxVertPos as Long
+
+Public CONST SBALIGNLEFT = 0
+Public CONST SBALIGNRIGHT = 2
+
+Public Const SBNOBORDER = 0
+Public Const SB3DBORDER = 1
+Public Const SBSIMPLEBORDER = 2
+
+Public CurArrangement as Integer
+Public CurBorderType as Integer
+Public CurAlignmode as Integer
+
+Public OldAlignMode as Integer
+Public OldBorderType as Integer
+Public OldArrangement as Integer
+
+Public Const cColumnarLeft = 1
+Public Const cColumnarTop = 2
+Public Const cTabled = 3
+Public Const cLeftJustified = 4
+Public Const cTopJustified = 5
+
+Public Const cXOffset = 1000
+Public Const cYOffset = 700
+&apos; This is the viewed space that we lose because of the symbol bars
+Public Const cSymbolMargin = 2000
+Public Const MaxFieldIndex = 200
+
+Public Const cControlCollectionCount = 9
+Public Const cLabel = 1
+Public Const cTextBox = 2
+Public Const cCheckBox = 3
+Public Const cDateBox = 4
+Public Const cTimeBox = 5
+Public Const cNumericBox = 6
+Public Const cCurrencyBox = 7
+Public Const cGridControl = 8
+Public Const cImageControl = 9
+
+Public Styles(100, 8) as String
+
+Public CurControlType as Integer
+Public CurFieldlength as Double
+Public CurFieldType as Integer
+Public CurFieldName as String
+Public CurControlName as String
+Public CurFormatKey as Long
+Public CurDefaultValue
+Public CurIsCurrency as Boolean
+Public CurScale as Integer
+Public CurHelpText as String
+
+Public FieldMetaValues(MaxFieldIndex, 8)
+&apos; Description of this List:
+&apos; CurFieldType = FieldMetaValues(Index,0)
+&apos; CurFieldLength = FieldMetaValues(Index,1)
+&apos; CurControlType = FieldMetaValues(Index,2) (ControlType, e.g., cLabel, cTextbox, etc.)
+&apos; CurControlName = FieldMetaValues(Index,3)
+&apos; CurFormatKey = FieldMetaValues(Index,4)
+&apos; CurDefaultValue = FieldMetaValues(Index,5)
+&apos; CurIsCurrency = FieldMetaValues(Index,6)
+&apos; CurScale = FieldMetaValues(Index,7)
+&apos; CurHelpText = FieldMetaValues(Index,8)
+
+Public FieldNames(MaxFieldIndex) as string
+Public oModelService(cControlCollectionCount) as String
+Public oGridModel as Object
+
+
+Function InsertControl(oContainer as Object, oControlObject as object, aPoint as Object, aSize as Object)
+Dim oShape as object
+ oShape = oDocument.CreateInstance (&quot;com.sun.star.drawing.ControlShape&quot;)
+ oShape.Size = aSize
+ oShape.Position = aPoint
+ oShape.AnchorType = com.sun.star.text.TextContentAnchorType.AT_PARAGRAPH
+ oShape.control = oControlObject
+ oContainer.Add(oShape)
+ InsertControl() = oShape
+End Function
+
+
+Function ArrangeControls()
+Dim oShape as Object
+Dim i as Integer
+ oProgressbar = oDocument.GetCurrentController.GetFrame.CreateStatusIndicator
+ oProgressbar.Start(&quot;&quot;, MaxIndex)
+ If oDBForm.HasbyName(&quot;Grid1&quot;) Then
+ RemoveShapes()
+ End If
+ ToggleLayoutPage(False)
+ Select Case CurArrangement
+ Case cTabled
+ PositionGridControl(MaxIndex)
+ Case Else
+ PositionControls(MaxIndex)
+ End Select
+ ToggleLayoutPage(True)
+ oProgressbar.End
+End Function
+
+
+Sub OpenFormDocument()
+Dim NoArgs() as new com.sun.star.beans.PropertyValue
+Dim oViewSettings as Object
+ oDocument = CreateNewDocument(&quot;swriter&quot;)
+ oProgressbar = oDocument.GetCurrentController.GetFrame.CreateStatusIndicator()
+ oProgressbar.Start(&quot;&quot;, 100)
+ oDocument.ApplyFormDesignMode = False
+ oController = oDocument.GetCurrentController
+ oViewSettings = oDocument.CurrentController.ViewSettings
+ oViewSettings.ShowTableBoundaries = False
+ oViewSettings.ShowOnlineLayout = True
+ oDrawPage = oDocument.DrawPage
+ oPageStyle = oDocument.StyleFamilies.GetByName(&quot;PageStyles&quot;).GetByName(&quot;Standard&quot;)
+End Sub
+
+
+Sub InitializeLabelValues()
+Dim oLabelModel as Object
+Dim oTBModel as Object
+Dim oLabelShape as Object
+Dim oTBShape as Object
+Dim aTBSize As New com.sun.star.awt.Size
+Dim aLabelSize As New com.sun.star.awt.Size
+Dim aPoint As New com.sun.star.awt.Point
+Dim aSize As New com.sun.star.awt.Size
+Dim oLocControl as Object
+Dim oLocPeer as Object
+ oLabelModel = CreateUnoService(&quot;com.sun.star.form.component.FixedText&quot;)
+ oTBModel = CreateUnoService(&quot;com.sun.star.form.component.TextField&quot;)
+
+ Set oLabelShape = InsertControl(oDrawPage, oLabelModel, aPoint, aLabelSize)
+ Set oTBShape = InsertControl(oDrawPage, oTBModel, aPoint, aSize)
+
+ oLocPeer = oController.GetControl(oLabelModel).Peer
+ XPixelFactor = 100000/oLocPeer.GetInfo.PixelPerMeterX
+ YPixelFactor = 100000/oLocPeer.GetInfo.PixelPerMeterY
+ aLabelSize = GetPeerSize(oLabelModel, oLocControl, &quot;The quick brown fox...&quot;)
+ nTCHeight = (aLabelSize.Height+1) * YPixelFactor
+ aTBSize = GetPeerSize(oTBModel, oLocControl, &quot;The quick brown fox...&quot;)
+ nDBRefHeight = (aTBSize.Height+1) * YPixelFactor
+ BasicLabelDiffHeight = Clng((nDBRefHeight - nTCHeight)/2)
+ oDrawPage.Remove(oLabelShape)
+ oDrawPage.Remove(oTBShape)
+End Sub
+
+
+Sub ConfigurePageStyle()
+Dim aPageSize As New com.sun.star.awt.Size
+Dim aSize As New com.sun.star.awt.Size
+ oPageStyle.IsLandscape = True
+ aPageSize = oPageStyle.Size
+ nPageWidth = aPageSize.Width
+ nPageHeight = aPageSize.Height
+ aSize.Width = nPageHeight
+ aSize.Height = nPageWidth
+ oPageStyle.Size = aSize
+ nPageWidth = nPageHeight
+ nPageHeight = oPageStyle.Size.Height
+ nFormWidth = nPageWidth - oPageStyle.RightMargin - oPageStyle.LeftMargin - 2 * cXOffset
+ nFormHeight = nPageHeight - oPageStyle.TopMargin - oPageStyle.BottomMargin - 2 * cYOffset - cSymbolMargin
+End Sub
+
+
+&apos; Modify the Borders of the Controls
+Sub ChangeBorderLayouts(oEvent as Object)
+Dim oModel as Object
+Dim i as Integer
+Dim oCurModel as Object
+Dim sLocText as String
+Dim oGroupShape as Object
+Dim s as Integer
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ oModel = oEvent.Source.Model
+ SwitchBorderMode(Val(Right(oModel.Name,1)))
+ ToggleLayoutPage(False)
+ If CurArrangement = cTabled Then
+ oGridModel.Border = CurBorderType
+ Else
+ If OldBorderType &lt;&gt; CurBorderType Then
+ For i = 0 To MaxIndex
+ If oDBShapeList(i).SupportsService(&quot;com.sun.star.drawing.GroupShape&quot;) Then
+ oGroupShape = oDBShapeList(i)
+ For s = 0 To oGroupShape.Count-1
+ oGroupShape(s).Control.Border = CurBorderType
+ Next s
+ Else
+ If oDBModelList(i).PropertySetInfo.HasPropertyByName(&quot;Border&quot;) Then
+ oDBModelList(i).Border = CurBorderType
+ End If
+ End If
+ Next i
+ End If
+ End If
+ ToggleLayoutPage(True)
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ DlgFormDB.Dispose()
+ End If
+End Sub
+
+
+Sub ChangeLabelAlignments(oEvent as Object)
+Dim i as Integer
+Dim oSize as New com.sun.star.awt.Size
+Dim oModel as Object
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ oModel = oEvent.Source.Model
+ SwitchAlignMode(Val(Right(oModel.Name,1)))
+ ToggleLayoutPage(False)
+ If OldAlignMode &lt;&gt; CurAlignMode Then
+ For i = 0 To MaxIndex
+ oTCShapeList(i).GetControl.Align = CurAlignmode
+ Next i
+ End If
+ If CurAlignmode = com.sun.star.awt.TextAlign.RIGHT Then
+ For i = 0 To Ubound(oTCShapeList())
+ oSize = oTCShapeList(i).Size
+ oSize.Width = oDBShapeList(i).Position.X - oTCShapeList(i).Position.X - cHoriDistance
+ oTCShapeList(i).Size = oSize
+ Next i
+ End If
+
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+ ToggleLayoutPage(True)
+End Sub
+
+
+Sub ChangeArrangemode(oEvent as Object)
+Dim oModel as Object
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ oModel = oEvent.Source.Model
+ SwitchArrangementButtons(Val(Right(oModel.Name,1)))
+ oModel.State = 1
+ DlgFormDB.GetControl(&quot;cmdArrange&quot; &amp; OldArrangement).Model.State = 0
+ If CurArrangement &lt;&gt; OldArrangement Then
+ ArrangeControls()
+ Select Case CurArrangement
+ Case cTabled
+ ToggleBorderGroup(False)
+ ToggleAlignGroup(False)
+ Case Else &apos; cColumnarTop,cLeftJustified, cTopJustified
+ ToggleAlignGroup(CurArrangement = cColumnarLeft)
+ If CurArrangement = cColumnarTop Then
+ If CurAlignMode = com.sun.star.awt.TextAlign.RIGHT Then
+ DialogModel.optAlign0.State = 1
+ CurAlignMode = com.sun.star.awt.TextAlign.LEFT
+ OldAlignMode = com.sun.star.awt.TextAlign.RIGHT
+ End If
+ End If
+ ControlCaptionstoStandardLayout()
+ oDBForm.Load
+ End Select
+ End If
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+End Sub
+
+
+Sub ToggleBorderGroup(bDoEnable as Boolean)
+ With DialogModel
+ .hlnBorderLayout.Enabled = bDoEnable
+ .optBorder0.Enabled = bDoEnable &apos; 0: No border
+ .optBorder1.Enabled = bDoEnable &apos; 1: 3D border
+ .optBorder2.Enabled = bDoEnable &apos; 2: simple border
+ End With
+End Sub
+
+
+Sub ToggleAlignGroup(ByVal bDoEnable as Boolean)
+ With DialogModel
+ If bDoEnable Then
+ bDoEnable = CurArrangement = cColumnarLeft
+ End If
+ .hlnAlign.Enabled = bDoEnable
+ .optAlign0.Enabled = bDoEnable
+ .optAlign2.Enabled = bDoEnable
+ End With
+End Sub
+
+
+Sub ToggleLayoutPage(bDoEnable as Boolean, Optional FocusControlName as String)
+ DialogModel.Enabled = bDoEnable
+ If bDoEnable Then
+ If Not bDebug Then
+ oDocument.UnlockControllers()
+ End If
+ ToggleOptionButtons(DialogModel,(bWithBackGraphic = True))
+ ToggleAlignGroup(bDoEnable)
+ ToggleBorderGroup(bDoEnable)
+ Else
+ If Not bDebug Then
+ oDocument.LockControllers()
+ End If
+ End If
+ If Not IsMissing(FocusControlName) Then
+ DlgFormDB.GetControl(FocusControlName).SetFocus()
+ End If
+End Sub
+
+
+Sub DestroyControlShapes(oDrawPage as Object)
+Dim i as Integer
+Dim oShape as Object
+ For i = oDrawPage.Count-1 To 0 Step -1
+ oShape = oDrawPage.GetByIndex(i)
+ If oShape.ShapeType = &quot;com.sun.star.drawing.ControlShape&quot; Then
+ oShape.Dispose()
+ End If
+ Next i
+End Sub
+
+
+Sub SwitchArrangementButtons(ByVal LocArrangement as Integer)
+ OldArrangement = CurArrangement
+ CurArrangement = LocArrangement
+ If OldArrangement &lt;&gt; 0 Then
+ DlgFormDB.GetControl(&quot;cmdArrange&quot; &amp; OldArrangement).Model.State = 0
+ End If
+ DlgFormDB.GetControl(&quot;cmdArrange&quot; &amp; CurArrangement).Model.State = 1
+End Sub
+
+
+Sub SwitchBorderMode(ByVal LocBorderType as Integer)
+ OldBorderType = CurBorderType
+ CurBorderType = LocBorderType
+End Sub
+
+
+Sub SwitchAlignMode(ByVal LocAlignMode as Integer)
+ OldAlignMode = CurAlignMode
+ CurAlignMode = LocAlignMode
+End Sub</script:module> \ No newline at end of file
diff --git a/wizards/source/formwizard/develop.xba b/wizards/source/formwizard/develop.xba
new file mode 100644
index 000000000..ce5730f58
--- /dev/null
+++ b/wizards/source/formwizard/develop.xba
@@ -0,0 +1,550 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="develop" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+
+Public oDBShapeList() as Object
+Public oTCShapeList() as Object
+Public oDBModelList() as Object
+Public oGroupShapeList() as Object
+
+Public oGridShape as Object
+Public a as Integer
+Public StartA as Integer
+Public bIsFirstRun as Boolean
+Public bIsVeryFirstRun as Boolean
+Public bControlsareCreated as Boolean
+Public nDBRefHeight as Long
+Public nXTCPos&amp;, nYTCPos&amp;, nXDBPos&amp;, nYDBPos&amp;, nTCHeight&amp;, nTCWidth&amp;, nDBHeight&amp;, nDBWidth&amp;
+
+Dim iReduceWidth as Integer
+
+Function PositionControls(Maxindex as Integer)
+Dim oTCModel as Object
+Dim oDBModel as Object
+Dim i as Integer
+ InitializePosSizes()
+ bIsFirstRun = True
+ bIsVeryFirstRun = True
+ a = 0
+ StartA = 0
+ nMaxRowY = 0
+ nSecMaxRowY = 0
+ If CurArrangement = cLeftJustified Or cTopJustified Then
+ DialogModel.optAlign0.State = 1
+ End If
+ For i = 0 To MaxIndex
+ GetCurrentMetaValues(i)
+ oTCModel = InsertTextControl(i)
+ If CurFieldType = com.sun.star.sdbc.DataType.TIMESTAMP Then
+ InsertTimeStampShape(i)
+ Else
+ InsertDBControl(i)
+ bIsVeryFirstRun = False
+ oDBModelList(i).LabelControl = oTCModel
+ End If
+ GetLabelDiffHeight(i+1)
+ ResetPosSizes(i)
+ oProgressbar.Value = i
+ Next i
+ ControlCaptionstoStandardLayout()
+ bControlsareCreated = True
+End Function
+
+
+Sub ResetPosSizes(LastIndex as Integer)
+ Select Case CurArrangement
+ Case cColumnarLeft
+ nYDBPos = nYDBPos + nDBHeight + cVertDistance
+ If (nYDBPos &gt; cYOffset + nFormHeight) Or (LastIndex = MaxIndex) Then
+ RepositionColumnarLeftControls(LastIndex)
+ nXTCPos = nMaxColRightX + 2 * cHoriDistance
+ nXDBPos = nXTCPos + cHoriDistance + nMaxTCWidth
+ nYDBPos = cYOffset
+ bIsFirstRun = True
+ StartA = LastIndex + 1
+ a = 0
+ Else
+ a = a + 1
+ End If
+ nYTCPos = nYDBPos + LABELDIFFHEIGHT
+ Case cColumnarTop
+ nYTCPos = nYDBPos + nDBHeight + cVertDistance
+ If nYTCPos &gt; cYOffset + nFormHeight Then
+ nXDBPos = nMaxColRightX + cHoriDistance
+ nXTCPos = nXDBPos
+ nYDBPos = cYOffset + nTCHeight + cVertDistance
+ nYTCPos = cYOffset
+ bIsFirstRun = True
+ StartA = LastIndex + 1
+ a = 0
+ Else
+ a = a + 1
+ End If
+ Case cLeftJustified,cTopJustified
+ If nMaxColRightX &gt; cXOffset + nFormWidth Then
+ Dim nOldYTCPos as Long
+ nOldYTCPos = nYTCPos
+ CheckJustifiedPosition()
+ Else
+ nXTCPos = nMaxColRightX + CHoriDistance
+ If CurArrangement = cLeftJustified Then
+ nYTCPos = nYDBPos + LabelDiffHeight
+ End If
+ End If
+ a = a + 1
+ End Select
+End Sub
+
+
+Sub RepositionColumnarLeftControls(LastIndex as Integer)
+Dim aSize As New com.sun.star.awt.Size
+Dim aPoint As New com.sun.star.awt.Point
+Dim i as Integer
+ aSize = GetSize(nMaxTCWidth, nTCHeight)
+ bIsFirstRun = True
+ For i = StartA To LastIndex
+ If i = StartA Then
+ nXTCPos = oTCShapeList(i).Position.X
+ nXDBPos = nXTCPos + nMaxTCWidth + cHoriDistance
+ End If
+ ResetDBShape(oDBShapeList(i), nXDBPos)
+ CheckOuterPoints(nXDBPos, nDBWidth, nYDBPos, nDBHeight, True)
+ Next i
+End Sub
+
+
+Sub ResetDBShape(oLocDBShape as Object, iXPos as Long)
+Dim aSize As New com.sun.star.awt.Size
+Dim aPoint As New com.sun.star.awt.Point
+ nYDBPos = oLocDBShape.Position.Y
+ nDBWidth = oLocDBShape.Size.Width
+ nDBHeight = oLocDBShape.Size.Height
+ aPoint = GetPoint(iXPos,nYDBPos)
+ oLocDBShape.SetPosition(aPoint)
+End Sub
+
+
+Sub InitializePosSizes()
+ nXTCPos = cXOffset
+ nTCWidth = 2000
+ nDBWidth = 2000
+ nDBHeight = nDBRefHeight
+ iReduceWidth = 0
+ Select Case CurArrangement
+ Case cColumnarLeft, cLeftJustified
+ GetLabelDiffHeight(0)
+ nYTCPos = cYOffset + LABELDIFFHEIGHT
+ nXDBPos = cXOffset + 3050
+ nYDBPos = cYOffset
+ Case cColumnarTop, cTopJustified
+ nXDBPos = cXOffset
+ nYTCPos = cYOffset
+ End Select
+End Sub
+
+
+Function InsertTextControl(i as Integer) as Object
+Dim oShape as Object
+Dim oModel as Object
+Dim aPoint as New com.sun.star.awt.Point
+Dim aSize As New com.sun.star.awt.Size
+ If bControlsareCreated Then
+ Set oShape = oTCShapeList(i)
+ Set oModel = oShape.GetControl
+ If CurArrangement = cLeftJustified Then
+ nTCWidth = GetPreferredWidth(oModel, True, CurFieldname)
+ Else
+ nTCWidth = oShape.Size.Width
+ End If
+ oShape.Position = GetPoint(nXTCPos, nYTCPos)
+ If CurArrangement = cColumnarTop Then
+ oModel.Align = com.sun.star.awt.TextAlign.LEFT
+ End If
+ Else
+ oModel = CreateUnoService(oModelService(cLabel))
+ aPoint = GetPoint(nXTCPos, nYTCPos)
+ aSize = GetSize(nTCWidth,nTCHeight)
+ Set oShape = InsertControl(oDrawPage, oModel, aPoint, aSize)
+ Set oTCShapeList(i)= oShape
+ If bIsVeryFirstRun Then
+ If CurArrangement = cColumnarTop Then
+ nYDBPos = nYTCPos + nTCHeight
+ End If
+ End If
+ nTCWidth = GetPreferredWidth(oModel, True, CurFieldName)
+ End If
+ If CurArrangement = cColumnarLeft Then
+ &apos; Note This If Sequence must be called before retrieving the outer Points
+ If bIsFirstRun Then
+ nMaxTCWidth = nTCWidth
+ bIsFirstRun = False
+ ElseIf nTCWidth &gt; nMaxTCWidth Then
+ nMaxTCWidth = nTCWidth
+ End If
+ End If
+ CheckOuterPoints(oShape.Position.X, nTCWidth, nYTCPos, nTCHeight, False)
+ Select Case CurArrangement
+ Case cLeftJustified
+ nXDBPos = nMaxColRightX
+ Case cColumnarTop,cTopJustified
+ oModel.Align = com.sun.star.awt.TextAlign.LEFT
+ nXDBPos = nXTCPos
+ nYDBPos = nYTCPos + nTCHeight
+ If CurFieldLength = 20 And nDBWidth &gt; 2 * nTCWidth Then
+ iReduceWidth = iReduceWidth + 1
+ End If
+ End Select
+ oShape.SetSize(GetSize(nTCWidth,nTCHeight))
+ If CurHelpText &lt;&gt; &quot;&quot; Then
+ oModel.HelpText = CurHelptext
+ End If
+ InsertTextControl = oModel
+End Function
+
+
+Sub InsertDBControl(i as Integer)
+Dim aPoint as New com.sun.star.awt.Point
+Dim aSize As New com.sun.star.awt.Size
+Dim oControl as Object
+Dim iColRightX as Long
+
+ aPoint = GetPoint(nXDBPos, nYDBPos)
+ If bControlsAreCreated Then
+ oDBShapeList(i).Position = aPoint
+ Else
+ oDBModelList(i) = CreateUnoService(oModelService(CurControlType))
+ oDBShapeList(i) = InsertControl(oDrawPage, oDBModelList(i), aPoint, aSize)
+ SetNumerics(oDBModelList(i), CurFieldType)
+ If CurControlType = cCheckBox Then
+ oDBModelList(i).Label = &quot;&quot;
+ End If
+ oDBModelList(i).DataField = CurFieldName
+ End If
+ nDBHeight = GetDBHeight(oDBModelList(i))
+ nDBWidth = GetPreferredWidth(oDBModelList(i),True)
+ aSize = GetSize(nDBWidth,nDBHeight)
+ oDBShapeList(i).SetSize(aSize)
+ CheckOuterPoints(nXDBPos, nDBWidth, nYDBPos, nDBHeight, True)
+End Sub
+
+
+Function InsertTimeStampShape(i as Integer) as Object
+Dim oDateModel as Object
+Dim oTimeModel as Object
+Dim oDateShape as Object
+Dim oTimeShape as Object
+Dim oDateTimeShape as Object
+Dim aPoint as New com.sun.star.awt.Point
+Dim aSize as New com.sun.star.awt.Size
+Dim nDateWidth as Long
+Dim nTimeWidth as Long
+Dim oGroupShape as Object
+ aPoint = GetPoint(nXDBPos, nYDBPos)
+ If bControlsAreCreated Then
+ oDBShapeList(i).Position = aPoint
+ nDBWidth = oDBShapeList(i).Size.Width
+ nDBHeight = oDBShapeList(i).Size.Height
+ Else
+ oGroupShape = oDocument.CreateInstance(&quot;com.sun.star.drawing.GroupShape&quot;)
+ oGroupShape.AnchorType = com.sun.star.text.TextContentAnchorType.AT_PARAGRAPH
+ oDrawPage.Add(oGroupShape)
+ CurFieldType = com.sun.star.sdbc.DataType.DATE
+ oDateModel = CreateUnoService(&quot;com.sun.star.form.component.DateField&quot;)
+ oDateModel.DataField = CurFieldName
+ oDateShape = InsertControl(oGroupShape, oDateModel, aPoint, aSize)
+ SetNumerics(oDateModel, CurFieldType)
+ nDBHeight = GetDBHeight(oDateModel)
+ nDateWidth = GetPreferredWidth(oDateModel,True)
+ aSize = GetSize(nDateWidth,nDBHeight)
+ oDateShape.SetSize(aSize)
+
+ CurFieldType = com.sun.star.sdbc.DataType.TIME
+ oTimeModel = CreateUnoService(&quot;com.sun.star.form.component.TimeField&quot;)
+ oTimeModel.DataField = CurFieldName
+ oTimeShape = InsertControl(oGroupShape, oTimeModel, aPoint, aSize)
+ oTimeShape.Position = GetPoint(nXDBPos + 10 + nDateWidth,nYDBPos)
+ nTimeWidth = GetPreferredWidth(oTimeModel)
+ aSize = GetSize(nTimeWidth,nDBHeight)
+ oTimeShape.SetSize(aSize)
+ nDBWidth = nDateWidth + nTimeWidth + 10
+ oGroupShape.Position = aPoint
+ oGroupShape.Size = GetSize(nDBWidth, nDBHeight)
+ Set oDBShapeList(i)= oGroupShape
+ End If
+ CheckOuterPoints(nXDBPos, nDBWidth, nYDBPos, nDBHeight, True)
+ InsertTimeStampShape() = oDBShapeList(i)
+End Function
+
+
+&apos; Note: on all Controls except for the checkbox the Label has to be set
+&apos; a bit under the DBControl because its Height is also smaller
+Sub GetLabelDiffHeight(Index as Integer)
+ If (CurArrangement = cLeftJustified) Or (CurArrangement = cColumnarLeft) Then
+ If Index &lt;= Ubound(FieldMetaValues()) Then
+ If FieldMetaValues(Index,2) = cCheckBox Then
+ LabelDiffHeight = 0
+ Else
+ LabelDiffHeight = BasicLabelDiffHeight
+ End If
+ End If
+ End If
+End Sub
+
+
+Sub CheckJustifiedPosition()
+Dim nLeftDist as Long
+Dim nRightDist as Long
+Dim oLocDBShape as Object
+Dim oLocTextShape as Object
+Dim nBaseWidth as Long
+ nBaseWidth = nFormWidth + cXOffset
+ nLeftDist = nMaxColRightX - nBaseWidth
+ nRightDist = nBaseWidth - nXTCPos + cHoriDistance
+ If nLeftDist &lt; 0.5 * nRightDist and iReduceWidth &gt; 2 Then
+ &apos; Fieldwidths in the line can be made smaller
+ AdjustLineWidth(StartA, a, nLeftDist, - 1)
+ If CurArrangement = cLeftjustified Then
+ nYDBPos = nMaxRowY + cVertDistance
+ nYTCPos = nYDBPos + LABELDIFFHEIGHT
+ nXTCPos = cXOffset
+ Else
+ nYTCPos = nMaxRowY + cVertDistance
+ nYDBPos = nYTCPos + nTCHeight
+ nXTCPos = cXOffset
+ nXDBPos = cXOffset
+ End If
+ bIsFirstRun = True
+ StartA = a + 1
+ Else
+ Set oLocDBShape = oDBShapeList(a)
+ Set oLocTextShape = oTCShapeList(a)
+ If CurArrangement = cLeftJustified Then
+ If nYDBPos + nDBHeight = nMaxRowY Then
+ &apos; The last Control was the highest in the row
+ nYDBPos = nSecMaxRowY + cVertDistance
+ Else
+ nYDBPos = nMaxRowY + cVertDistance
+ End If
+ nYTCPos = nYDBPos + LABELDIFFHEIGHT
+ nXDBPos = cXOffset + nTCWidth
+ oLocTextShape.Position = GetPoint(cXOffset, nYTCPos)
+ oLocDBShape.Position = GetPoint(nXDBPos, nYDBPos)
+ &apos; PosSizes for the next two Controls
+ nXTCPos = oLocDBShape.Position.X + oLocDBShape.Size.Width + cHoriDistance
+ bIsFirstRun = True
+ CheckOuterPoints(nXDBPos, nDBWidth, nYDBPos, nDBHeight, True)
+ nXDBPos = nMaxColRightX + cHoriDistance
+ Else &apos; cTopJustified
+ If nYDBPos + nDBHeight = nMaxRowY Then
+ &apos; The last Control was the highest in the row
+ nYTCPos = nSecMaxRowY + cVertDistance
+ Else
+ nYTCPos = nMaxRowY + cVertDistance
+ End If
+ nYDBPos = nYTCPOS + nTCHeight
+ nXDBPos = cXOffset
+ nXTCPos = cXOffset
+ oLocTextShape.Position = GetPoint(cXOffset, nYTCPos)
+ oLocDBShape.Position = GetPoint(cXOffset, nYDBPos)
+ bIsFirstRun = True
+ If nDBWidth &gt; nTCWidth Then
+ CheckOuterPoints(nXDBPos, nDBWidth, nYDBPos, nDBHeight, True)
+ Else
+ CheckOuterPoints(nXDBPos, nTCWidth, nYDBPos, nDBHeight, True)
+ End If
+ nXTCPos = nMaxColRightX + cHoriDistance
+ nXDBPos = nXTCPos
+ End If
+ AdjustLineWidth(StartA, a-1, nRightDist, 1)
+ StartA = a
+ End If
+ iReduceWidth = 0
+End Sub
+
+
+
+Function GetCorrWidth(StartIndex as Integer, EndIndex as Integer, nDist as Long, Widthfactor as Integer) as Integer
+Dim ShapeCount as Integer
+ If WidthFactor &gt; 0 Then
+ ShapeCount = EndIndex-StartIndex + 1
+ Else
+ ShapeCount = iReduceWidth
+ End If
+ GetCorrWidth() = (nDist)/ShapeCount
+End Function
+
+
+Sub AdjustLineWidth(StartIndex as Integer, EndIndex as Integer, nDist as Long, Widthfactor as Integer)
+Dim i as Integer
+Dim oLocDBShape as Object
+Dim oLocTCShape as Object
+Dim CorrWidth as Integer
+Dim bAdjustPos as Boolean
+Dim iLocTCPosX as Long
+Dim iLocDBPosX as Long
+ CorrWidth = GetCorrWidth(StartIndex, EndIndex, nDist, Widthfactor)
+ bAdjustPos = False
+ iLocTCPosX = cXOffset
+ For i = StartIndex To EndIndex
+ Set oLocDBShape = oDBShapeList(i)
+ Set oLocTCShape = oTCShapeList(i)
+ If bAdjustPos Then
+ oLocTCShape.Position = GetPoint(iLocTCPosX, oLocTCShape.Position.Y)
+ If CurArrangement = cLeftJustified Then
+ iLocDBPosX = oLocTCShape.Position.X + oLocTCShape.Size.Width
+ oLocDBShape.Position = GetPoint(iLocDBPosX, oLocDBShape.Position.Y)
+ Else
+ oLocDBShape.Position = GetPoint(iLocTCPosX, oLocTCShape.Position.Y + nTCHeight)
+ End If
+ Else
+ bAdjustPos = True
+ End If
+ If CDbl(FieldMetaValues(i,1)) &gt; 20 or WidthFactor &gt; 0 Then
+ If (CurArrangement = cTopJustified) And (oLocTCShape.Size.Width &gt; oLocDBShape.Size.Width) Then
+ oLocDBShape.Size = GetSize(oLocTCShape.Size.Width + WidthFactor * CorrWidth, oLocDBShape.Size.Height)
+ Else
+ oLocDBShape.Size = GetSize(oLocDBShape.Size.Width + WidthFactor * CorrWidth, oLocDBShape.Size.Height)
+ End If
+ End If
+ iLocTCPosX = oLocDBShape.Position.X + oLocDBShape.Size.Width + cHoriDistance
+ If CurArrangement = cTopJustified Then
+ If oLocTCShape.Size.Width &gt; oLocDBShape.Size.Width Then
+ iLocTCPosX = oLocDBShape.Position.X + oLocTCShape.Size.Width + cHoriDistance
+ End If
+ End If
+ Next i
+End Sub
+
+
+Sub CheckOuterPoints(nXPos, nWidth, nYPos, nHeight, bIsDBField as Boolean)
+Dim nColRightX as Long
+Dim nRowY as Long
+Dim nOldMaxRowY as Long
+ If CurArrangement = cLeftJustified Or CurArrangement = cTopJustified Then
+ If bIsDBField Then
+ &apos; Only at DBControls you can measure the Value of nMaxRowY
+ If bIsFirstRun Then
+ nMaxRowY = nYPos + nHeight
+ nSecMaxRowY = nMaxRowY
+ Else
+ nRowY = nYPos + nHeight
+ If nRowY &gt;= nMaxRowY Then
+ nOldMaxRowY = nMaxRowY
+ nSecMaxRowY = nOldMaxRowY
+ nMaxRowY = nRowY
+ End If
+ End If
+ End If
+ End If
+ &apos; Find the outer right point
+ If bIsFirstRun Then
+ nMaxColRightX = nXPos + nWidth
+ bIsFirstRun = False
+ Else
+ nColRightX = nXPos + nWidth
+ If nColRightX &gt; nMaxColRightX Then
+ nMaxColRightX = nColRightX
+ End If
+ End If
+End Sub
+
+
+Function PositionGridControl(MaxIndex as Integer)
+Dim oControl as Object
+Dim n as Integer
+Dim oColumn as Object
+Dim aPoint as New com.sun.star.awt.Point
+Dim aSize as New com.sun.star.awt.Size
+ If bControlsareCreated Then
+ ShapesToNirwana()
+ End If
+ oGridModel = CreateUnoService(oModelService(cGridControl))
+ oGridModel.Name = &quot;Grid1&quot;
+ aPoint = GetPoint(cXOffset, cYOffset)
+ aSize = GetSize(nFormWidth, nFormHeight)
+ oDBForm.InsertByName (oGridModel.Name, oGridModel)
+ oGridShape = InsertControl(oDrawPage, oGridModel, aPoint, aSize)
+ For n = 0 to MaxIndex
+ GetCurrentMetaValues(n)
+ If CurFieldType = com.sun.star.sdbc.DataType.TIMESTAMP Then
+ oColumn = SetupGridColumn(oGridModel,&quot;DateField&quot;, False, com.sun.star.sdbc.DataType.DATE, CurFieldName &amp; &quot; &quot; &amp; sDateAppendix)
+ oColumn = SetupGridColumn(oGridModel,&quot;TimeField&quot;, False, com.sun.star.sdbc.DataType.TIME, CurFieldName &amp; &quot; &quot; &amp; sTimeAppendix)
+ Else
+ If CurControlType = cImageControl Then
+ oColumn = SetupGridColumn(oGridModel,&quot;TextField&quot;, True, CurFieldType, CurFieldName)
+ Else
+ oColumn = SetupGridColumn(oGridModel, CurControlName, False, CurFieldType, CurFieldName)
+ End If
+ End If
+ oProgressbar.Value = n
+ next n
+End Function
+
+
+Function SetupGridColumn(oGridModel as Object, ControlName as String, bHidden as Boolean, iLocFieldType as Integer, ColName as String) as Object
+Dim oColumn as Object
+ CurControlName = ControlName
+ oColumn = oGridModel.CreateColumn(CurControlName)
+ oColumn.Name = CalcUniqueContentName(oGridModel, CurControlName)
+ oColumn.Hidden = bHidden
+ SetNumerics(oColumn, iLocFieldType)
+ oColumn.DataField = CurFieldName
+ oColumn.Label = ColName
+ oColumn.Width = 0 &apos; Width of column is adjusted to Columname
+ oGridModel.insertByName(oColumn.Name, oColumn)
+End Function
+
+
+Sub ControlCaptionstoStandardLayout()
+Dim i as Integer
+Dim iBorderType as Integer
+Dim oCurModel as Object
+Dim oStyle as Object
+Dim iStandardColor as Long
+ If CurArrangement &lt;&gt; cTabled Then
+ oStyle = oDocument.StyleFamilies.GetByName(&quot;ParagraphStyles&quot;).GetByName(&quot;Standard&quot;)
+ iStandardColor = oStyle.CharColor
+ For i = 0 To MaxIndex
+ oCurModel = oTCShapeList(i).GetControl
+ If i = 0 Then
+ If oCurModel.TextColor = iStandardColor Then
+ Exit Sub
+ End If
+ End If
+ oCurModel.TextColor = iStandardColor
+ Next i
+ End If
+End Sub
+
+
+Sub GroupShapesTogether()
+Dim i as Integer
+ If CurArrangement &lt;&gt; cTabled Then
+ For i = 0 To MaxIndex
+ oGroupShapeList(i) = CreateUnoService(&quot;com.sun.star.drawing.ShapeCollection&quot;)
+ oGroupShapeList(i).Add(oTCShapeList(i))
+ oGroupShapeList(i).Add(oDBShapeList(i))
+ oDrawPage.Group(oGroupShapeList(i))
+ Next i
+ Else
+ RemoveNirwanaShapes()
+ End If
+End Sub</script:module>
diff --git a/wizards/source/formwizard/dialog.xlb b/wizards/source/formwizard/dialog.xlb
new file mode 100644
index 000000000..d680f2929
--- /dev/null
+++ b/wizards/source/formwizard/dialog.xlb
@@ -0,0 +1,5 @@
+<?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="FormWizard" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="DlgFormDB"/>
+</library:library>
diff --git a/wizards/source/formwizard/script.xlb b/wizards/source/formwizard/script.xlb
new file mode 100644
index 000000000..0b79b7f07
--- /dev/null
+++ b/wizards/source/formwizard/script.xlb
@@ -0,0 +1,10 @@
+<?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="FormWizard" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="FormWizard"/>
+ <library:element library:name="Layouter"/>
+ <library:element library:name="Language"/>
+ <library:element library:name="DBMeta"/>
+ <library:element library:name="tools"/>
+ <library:element library:name="develop"/>
+</library:library>
diff --git a/wizards/source/formwizard/tools.xba b/wizards/source/formwizard/tools.xba
new file mode 100644
index 000000000..881552717
--- /dev/null
+++ b/wizards/source/formwizard/tools.xba
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="tools" script:language="StarBasic">REM ***** BASIC *****
+Option Explicit
+Public Const SBMAXTEXTSIZE = 50
+
+
+Function SetProgressValue(iValue as Integer)
+ If iValue = 0 Then
+ oProgressbar.End
+ End If
+ ProgressValue = iValue
+ oProgressbar.Value = iValue
+End Function
+
+
+Function GetPreferredWidth(oModel as Object, bGetMaxWidth as Boolean, Optional LocText)
+Dim aPeerSize as new com.sun.star.awt.Size
+Dim nWidth as Integer
+Dim oControl as Object
+ If Not IsMissing(LocText) Then
+ &apos; Label
+ aPeerSize = GetPeerSize(oModel, oControl, LocText)
+ ElseIf CurControlType = cImageControl Then
+ GetPreferredWidth() = 2000
+ Exit Function
+ Else
+ aPeerSize = GetPeerSize(oModel, oControl)
+ End If
+ nWidth = aPeerSize.Width
+ &apos; We increase the preferred Width a bit so that the control does not become too small
+ &apos; when we change the border from &quot;3D&quot; to &quot;Flat&quot;
+ GetPreferredWidth = (nWidth + 10) * XPixelFactor &apos; PixelTo100thmm(nWidth)
+End Function
+
+
+Function GetPreferredHeight(oModel as Object, Optional LocText)
+Dim aPeerSize as new com.sun.star.awt.Size
+Dim nHeight as Integer
+Dim oControl as Object
+ If Not IsMissing(LocText) Then
+ &apos; Label
+ aPeerSize = GetPeerSize(oModel, oControl, LocText)
+ ElseIf CurControlType = cImageControl Then
+ GetPreferredHeight() = 2000
+ Exit Function
+ Else
+ aPeerSize = GetPeerSize(oModel, oControl)
+ End If
+ nHeight = aPeerSize.Height
+ &apos; We increase the preferred Height a bit so that the control does not become too small
+ &apos; when we change the border from &quot;3D&quot; to &quot;Flat&quot;
+ GetPreferredHeight = (nHeight+1) * YPixelFactor &apos; PixelTo100thmm(nHeight)
+End Function
+
+
+Function GetPeerSize(oModel as Object, oControl as Object, Optional LocText)
+Dim oPeer as Object
+Dim aPeerSize as new com.sun.star.awt.Size
+Dim NullValue
+ oControl = oController.GetControl(oModel)
+ oPeer = oControl.GetPeer()
+ If oControl.Model.PropertySetInfo.HasPropertybyName(&quot;EffectiveMax&quot;) Then
+ If oControl.Model.EffectiveMax = 0 Then
+ &apos; This is relevant for decimal fields
+ oControl.Model.EffectiveValue = 999.9999
+ Else
+ oControl.Model.EffectiveValue = oControl.Model.EffectiveMax
+ End If
+ GetPeerSize() = oPeer.PreferredSize()
+ oControl.Model.EffectiveValue = NullValue
+ ElseIf Not IsMissing(LocText) Then
+ oControl.Text = LocText
+ GetPeerSize() = oPeer.PreferredSize()
+ ElseIf CurFieldType = com.sun.star.sdbc.DataType.BIT Then
+ GetPeerSize() = oPeer.PreferredSize()
+ ElseIf CurFieldType = com.sun.star.sdbc.DataType.BOOLEAN Then
+ GetPeerSize() = oPeer.PreferredSize()
+ ElseIf CurFieldType = com.sun.star.sdbc.DataType.DATE Then
+ oControl.Model.Date = Date
+ GetPeerSize() = oPeer.PreferredSize()
+ oControl.Model.Date = NullValue
+ ElseIf CurFieldType = com.sun.star.sdbc.DataType.TIME Then
+ oControl.Time = Time
+ GetPeerSize() = oPeer.PreferredSize()
+ oControl.Time = NullValue
+ Else
+ If oControl.MaxTextLen &gt; SBMAXTEXTSIZE Then
+ oControl.Text = Mid(SBSIZETEXT,1, SBMAXTEXTSIZE)
+ Else
+ oControl.Text = Mid(SBSIZETEXT,1, oControl.MaxTextLen)
+ End If
+ GetPeerSize() = oPeer.PreferredSize()
+ oControl.Text = &quot;&quot;
+ End If
+End Function
+
+
+Function TwipToCM(ByVal nValue as long) as String
+ TwipToCM = trim(str(nValue / 567)) + &quot;cm&quot;
+End function
+
+
+Function TwipTo100telMM(ByVal nValue as long) as long
+ TwipTo100telMM = nValue / 0.567
+End function
+
+
+Function TwipToPixel(ByVal nValue as long) as long &apos; not an exact calculation
+ TwipToPixel = nValue / 15
+End function
+
+
+Function PixelTo100thMMX(oControl as Object) as long
+ oPeer = oControl.GetPeer()
+ PixelTo100mmX = Clng(Peer.GetInfo.PixelPerMeterX/100000)
+
+&apos; PixelTo100thMM = nValue * 28 &apos; not an exact calculation
+End function
+
+
+Function PixelTo100thMMY(oControl as Object) as long
+ oPeer = oControl.GetPeer()
+ PixelTo100mmX = Clng(Peer.GetInfo.PixelPerMeterY/100000)
+
+&apos; PixelTo100thMM = nValue * 28 &apos; not an exact calculation
+End function
+
+
+Function GetPoint(xPos, YPos) as New com.sun.star.awt.Point
+Dim aPoint as New com.sun.star.awt.Point
+ aPoint.X = xPos
+ aPoint.Y = yPos
+ GetPoint() = aPoint
+End Function
+
+
+Function GetSize(iWidth, iHeight) As New com.sun.star.awt.Size
+Dim aSize As New com.sun.star.awt.Size
+ aSize.Width = iWidth
+ aSize.Height = iHeight
+ GetSize() = aSize
+End Function
+
+
+Sub ImportStyles()
+Dim OldIndex as Integer
+ If Not bDebug Then
+ On Local Error GoTo WIZARDERROR
+ End If
+ OldIndex = CurIndex
+ CurIndex = GetCurIndex(DialogModel.lstStyles, Styles(),8)
+ If CurIndex &lt;&gt; OldIndex Then
+ ToggleLayoutPage(False)
+ Dim sImportPath as String
+ sImportPath = Styles(CurIndex, 8)
+ bWithBackGraphic = LoadNewStyles(oDocument, DialogModel, CurIndex, sImportPath, Styles(), TexturePath)
+ ControlCaptionsToStandardLayout()
+ ToggleLayoutPage(True, &quot;lstStyles&quot;)
+ End If
+WIZARDERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sMsgErrMsg, 16, GetProductName())
+ Resume LOCERROR
+ LOCERROR:
+ End If
+End Sub
+
+
+
+Function SetNumerics(ByVal oLocObject as Object, iLocFieldType as Integer) as Object
+ If CurControlType = cNumericBox Then
+ oLocObject.TreatAsNumber = True
+ Select Case iLocFieldType
+ Case com.sun.star.sdbc.DataType.BIGINT
+ oLocObject.EffectiveMax = 2147483647 * 2147483647
+ oLocObject.EffectiveMin = -(-2147483648 * -2147483648)
+&apos; oLocObject.DecimalAccuracy = 0
+ Case com.sun.star.sdbc.DataType.INTEGER
+ oLocObject.EffectiveMax = 2147483647
+ oLocObject.EffectiveMin = -2147483648
+ Case com.sun.star.sdbc.DataType.SMALLINT
+ oLocObject.EffectiveMax = 32767
+ oLocObject.EffectiveMin = -32768
+ Case com.sun.star.sdbc.DataType.TINYINT
+ oLocObject.EffectiveMax = 127
+ oLocObject.EffectiveMin = -128
+ Case com.sun.star.sdbc.DataType.FLOAT, com.sun.star.sdbc.DataType.REAL, com.sun.star.sdbc.DataType.DOUBLE, com.sun.star.sdbc.DataType.DECIMAL, com.sun.star.sdbc.DataType.NUMERIC
+&apos;Todo: oLocObject.DecimalAccuracy = ...
+ oLocObject.EffectiveDefault = CurDefaultValue
+&apos; Todo: HelpText???
+ End Select
+ If oLocObject.PropertySetinfo.HasPropertyByName(&quot;Width&quot;)Then &apos; Note: an Access AutoincrementField does not provide this property Width
+ oLocObject.Width = CurFieldLength + CurScale + 1
+ End If
+ If CurIsCurrency Then
+&apos;Todo: How do you set currencies?
+ End If
+ ElseIf CurControlType = cTextBox Then &apos;com.sun.star.sdbc.DataType.CHAR, com.sun.star.sdbc.DataType.VARCHAR, com.sun.star.sdbc.DataType.LONGVARCHAR
+ If CurFieldLength = 0 Then &apos;Or oLocObject.MaxTextLen &gt; SBMAXTEXTSIZE
+ oLocObject.MaxTextLen = SBMAXTEXTSIZE
+ CurFieldLength = SBMAXTEXTSIZE
+ Else
+ oLocObject.MaxTextLen = CurFieldLength
+ End If
+ oLocObject.DefaultText = CurDefaultValue
+ ElseIf CurControlType = cDateBox Then
+&apos; Todo Why does this not work?: oLocObject.DefaultDate = CurDefaultValue
+ ElseIf CurControlType = cTimeBox Then &apos; com.sun.star.sdbc.DataType.DATE, com.sun.star.sdbc.DataType.TIME
+ oLocObject.DefaultTime = CurDefaultValue
+&apos; Todo: Property TimeFormat? from where?
+ ElseIf CurControlType = cCheckBox Then
+&apos; Todo Why does this not work?: oLocObject.DefaultState = CurDefaultValue
+ End If
+ If oLocObject.PropertySetInfo.HasPropertybyName(&quot;FormatKey&quot;) Then
+ On Local Error Resume Next
+ oLocObject.FormatKey = CurFormatKey
+ End If
+End Function
+
+
+&apos; Destroy all Shapes in Nirwana
+Sub RemoveShapes()
+Dim n as Integer
+Dim oControl as Object
+Dim oShape as Object
+ For n = oDrawPage.Count-1 To 0 Step -1
+ oShape = oDrawPage(n)
+ If oShape.Position.Y &gt; -2000 Then
+ oDrawPage.Remove(oShape)
+ End If
+ Next n
+End Sub
+
+
+&apos; Destroy all Shapes in Nirwana
+Sub RemoveNirwanaShapes()
+Dim n as Integer
+Dim oControl as Object
+Dim oShape as Object
+ For n = oDrawPage.Count-1 To 0 Step -1
+ oShape = oDrawPage(n)
+ If oShape.Position.Y &lt; -2000 Then
+ oDrawPage.Remove(oShape)
+ End If
+ Next n
+End Sub
+
+
+
+&apos; Note: as Shapes cannot be removed from the DrawPage without destroying
+&apos; the object we have to park them somewhere beyond the visible area of the page
+Sub ShapesToNirwana()
+Dim n as Integer
+Dim oControl as Object
+ For n = 0 To oDrawPage.Count-1
+ oDrawPage(n).Position = GetPoint(-20, -10000)
+ Next n
+End Sub
+
+
+Function CalcUniqueContentName(ByVal oContainer as Object, sBaseName as String) as String
+
+Dim nPostfix as Integer
+Dim sReturn as String
+ nPostfix = 2
+ sReturn = sBaseName
+ while (oContainer.hasByName(sReturn))
+ sReturn = sBaseName &amp; nPostfix
+ nPostfix = nPostfix + 1
+ Wend
+ CalcUniqueContentName = sReturn
+End Function
+
+
+Function CountItemsInArray(BigArray(), SearchItem)
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim ResCount as Integer
+ ResCount = 0
+ MaxIndex = Ubound(BigArray())
+ For i = 0 To MaxIndex
+ If SearchItem = BigArray(i) Then
+ ResCount = ResCount + 1
+ End If
+ Next i
+ CountItemsInArray() = ResCount
+End Function
+
+
+Function GetDBHeight(oDBModel as Object)
+ If CurControlType = cImageControl Then
+ nDBHeight = 2000
+ Else
+ If CurFieldType = com.sun.star.sdbc.DataType.LONGVARCHAR Then
+ oDBModel.MultiLine = True
+ nDBHeight = nDBRefHeight * 4
+ Else
+ nDBHeight = nDBRefHeight
+ End If
+ End If
+ GetDBHeight() = nDBHeight
+End Function
+
+
+Function GetFormWizardPaths() as Boolean
+ FormPath = GetOfficeSubPath(&quot;Template&quot;,&quot;../wizard/bitmap&quot;)
+ If FormPath &lt;&gt; &quot;&quot; Then
+ WizardPath = GetOfficeSubPath(&quot;Template&quot;,&quot;wizard/&quot;)
+ If Wizardpath &lt;&gt; &quot;&quot; Then
+ TexturePath = GetOfficeSubPath(&quot;Gallery&quot;, &quot;backgrounds/&quot;)
+ If TexturePath &lt;&gt; &quot;&quot; Then
+ WorkPath = GetPathSettings(&quot;Work&quot;)
+ If WorkPath &lt;&gt; &quot;&quot; Then
+ TempPath = GetPathSettings(&quot;Temp&quot;)
+ If TempPath &lt;&gt; &quot;&quot; Then
+ GetFormWizardPaths = True
+ Exit Function
+ End If
+ End If
+ End If
+ End If
+ End If
+ DisposeDocument(oDocument)
+ GetFormWizardPaths() = False
+End Function
+
+
+Function GetFilterName(sApplicationKey as String) as String
+Dim oArgs()
+Dim oFactory
+Dim i as Integer
+Dim Maxindex as Integer
+Dim UIName as String
+ oFactory = createUnoService(&quot;com.sun.star.document.FilterFactory&quot;)
+ oArgs() = oFactory.getByName(sApplicationKey)
+ MaxIndex = Ubound(oArgs())
+ For i = 0 to MaxIndex
+ If (oArgs(i).Name=&quot;UIName&quot;) Then
+ UIName = oArgs(i).Value
+ Exit For
+ End If
+ next i
+ GetFilterName() = UIName
+End Function
+</script:module>
diff --git a/wizards/source/gimmicks/AutoText.xba b/wizards/source/gimmicks/AutoText.xba
new file mode 100644
index 000000000..a25d1eed9
--- /dev/null
+++ b/wizards/source/gimmicks/AutoText.xba
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="AutoText" script:language="StarBasic">&apos; BASIC
+Option Explicit
+Dim oDocument as Object
+Dim sDocumentTitle as String
+
+
+Sub Main()
+Dim oTable as Object
+Dim oRows as Object
+Dim oDocuText as Object
+Dim oAutoTextCursor as Object
+Dim oAutoTextContainer as Object
+Dim oAutogroup as Object
+Dim oAutoText as Object
+Dim oCharStyles as Object
+Dim oContentStyle as Object
+Dim oHeaderStyle as Object
+Dim oGroupTitleStyle as Object
+Dim n, m, iAutoCount as Integer
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ sDocumentTitle = &quot;Installed AutoTexts&quot;
+
+ &apos; Open a new empty document
+ oDocument = CreateNewDocument(&quot;swriter&quot;)
+ If Not IsNull(oDocument) Then
+ oDocument.DocumentProperties.Title = sDocumentTitle
+ oDocuText = oDocument.Text
+
+ &apos; Create The Character-templates
+ oCharStyles = oDocument.StyleFamilies.GetByName(&quot;CharacterStyles&quot;)
+
+ &apos; The Characterstyle for the Header that describes the Title of Autotextgroups
+ oGroupTitleStyle = oDocument.createInstance(&quot;com.sun.star.style.CharacterStyle&quot;)
+ oCharStyles.InsertbyName(&quot;AutoTextGroupTitle&quot;, oGroupTitleStyle)
+
+ oGroupTitleStyle.CharWeight = com.sun.star.awt.FontWeight.BOLD
+ oGroupTitleStyle.CharHeight = 14
+
+ &apos; The Characterstyle for the Header that describes the Title of Autotextgroups
+ oHeaderStyle = oDocument.createInstance(&quot;com.sun.star.style.CharacterStyle&quot;)
+ oCharStyles.InsertbyName(&quot;AutoTextHeading&quot;, oHeaderStyle)
+ oHeaderStyle.CharWeight = com.sun.star.awt.FontWeight.BOLD
+
+ &apos; &quot;Ordinary&quot; Table Content
+ oContentStyle = oDocument.createInstance(&quot;com.sun.star.style.CharacterStyle&quot;)
+ oCharStyles.InsertbyName(&quot;TableContent&quot;, oContentStyle)
+
+ oAutoTextContainer = CreateUnoService(&quot;com.sun.star.text.AutoTextContainer&quot;)
+
+ oAutoTextCursor = oDocuText.CreateTextCursor()
+
+ oAutoTextCursor.CharStyleName = &quot;AutoTextGroupTitle&quot;
+ &apos; Link the Title with the following table
+ oAutoTextCursor.ParaKeepTogether = True
+
+ For n = 0 To oAutoTextContainer.Count - 1
+ oAutoGroup = oAutoTextContainer.GetByIndex(n)
+
+ oAutoTextCursor.SetString(oAutoGroup.Title)
+ oAutoTextCursor.CollapseToEnd()
+ oDocuText.insertControlCharacter(oAutoTextCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+ oTable = oDocument.CreateInstance(&quot;com.sun.star.text.TextTable&quot;)
+ &apos; Divide the table if necessary
+ oTable.Split = True
+&apos; oTable.KeepTogether = False
+ oTable.RepeatHeadLine = True
+ oAutoTextCursor.Text.InsertTextContent(oAutoTextCursor,oTable,False)
+ InsertStringToCell(&quot;AutoText Name&quot;,oTable.GetCellbyPosition(0,0), &quot;AutoTextHeading&quot;)
+ InsertStringToCell(&quot;AutoText Shortcut&quot;,oTable.GetCellbyPosition(1,0), &quot;AutoTextHeading&quot;)
+ &apos; Insert one row at the bottom of the table
+ oRows = oTable.Rows
+ iAutoCount = oAutoGroup.Count
+ For m = 0 To iAutoCount-1
+ &apos; Insert the name and the title of all Autotexts
+ oAutoText = oAutoGroup.GetByIndex(m)
+ InsertStringToCell(oAutoGroup.Titles(m), oTable.GetCellbyPosition(0, m + 1), &quot;TableContent&quot;)
+ InsertStringToCell(oAutoGroup.ElementNames(m), oTable.GetCellbyPosition(1, m + 1), &quot;TableContent&quot;)
+ If m &lt; iAutoCount-1 Then
+ oRows.InsertbyIndex(m + 2,1)
+ End If
+ Next m
+ oDocuText.insertControlCharacter(oAutoTextCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+ oAutoTextCursor.CollapseToEnd()
+ Next n
+ End If
+End Sub
+
+
+Sub InsertStringToCell(sCellString as String, oCell as Object, sCellStyle as String)
+Dim oCellCursor as Object
+ oCellCursor = oCell.CreateTextCursor()
+ oCellCursor.CharStyleName = sCellStyle
+ oCell.Text.insertString(oCellCursor,sCellString,False)
+ oDocument.CurrentController.Select(oCellCursor)
+End Sub</script:module>
diff --git a/wizards/source/gimmicks/ChangeAllChars.xba b/wizards/source/gimmicks/ChangeAllChars.xba
new file mode 100644
index 000000000..cdcbc9623
--- /dev/null
+++ b/wizards/source/gimmicks/ChangeAllChars.xba
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ChangeAllChars" script:language="StarBasic">&apos; This macro replaces all characters in a writer-document through &quot;x&quot; or &quot;X&quot; signs.
+&apos; It works on the currently activated document.
+Private const UPPERREPLACECHAR = &quot;X&quot;
+Private const LOWERREPLACECHAR = &quot;x&quot;
+
+Private MSGBOXTITLE
+Private NOTSAVEDTEXT
+Private WARNING
+
+Sub ChangeAllChars &apos; Change all chars in the active document
+Dim oSheets, oPages as Object
+Dim i as Integer
+Const MBYES = 6
+Const MBABORT = 2
+Const MBNO = 7
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ MSGBOXTITLE = &quot;Change All Characters to an &apos;&quot; &amp; UPPERREPLACECHAR &amp; &quot;&apos;&quot;
+ NOTSAVEDTEXT = &quot;This document has already been modified: All characters will be changed to an &quot; &amp; UPPERREPLACECHAR &amp; &quot;&apos;. Should the document be saved now?&quot;
+ WARNING = &quot;This macro changes all characters and numbers to an &apos;&quot; &amp; UPPERREPLACECHAR &amp; &quot;&apos; in this document.&quot;
+
+ On Local Error GoTo NODOCUMENT
+ oDocument = StarDesktop.ActiveFrame.Controller.Model
+ NODOCUMENT:
+ If Err &lt;&gt; 0 Then
+ Msgbox(WARNING &amp; chr(13) &amp; &quot;First, activate a Writer document.&quot; , 16, GetProductName())
+ Exit Sub
+ End If
+ On Local Error Goto 0
+
+ sDocType = GetDocumentType(oDocument)
+
+ If oDocument.IsModified And oDocument.Url &lt;&gt; &quot;&quot; Then
+ Status = MsgBox(NOTSAVEDTEXT, 3+32, MSGBOXTITLE)
+ Select Case Status
+ Case MBYES
+ oDocument.Store
+ Case MBABORT, MBNO
+ End
+ End Select
+ Else
+ Status = MsgBox(WARNING, 3+32, MSGBOXTITLE)
+ If Status = MBNO Or Status = MBABORT Then &apos; No, Abort
+ End
+ End If
+ End If
+
+ Select Case sDocType
+ Case &quot;swriter&quot;
+ ReplaceAllStrings(oDocument)
+
+ Case Else
+ Msgbox(&quot;This macro only works with Writer documents.&quot;, 16, GetProductName())
+ End Select
+End Sub
+
+
+Sub ReplaceAllStrings(oContainer as Object)
+ ReplaceStrings(oContainer, &quot;[a-z]&quot;, LOWERREPLACECHAR)
+ ReplaceStrings(oContainer, &quot;[à-þ]&quot;, LOWERREPLACECHAR)
+ ReplaceStrings(oContainer, &quot;[A-Z]&quot;, UPPERREPLACECHAR)
+ ReplaceStrings(oContainer, &quot;[À-ß]&quot;, UPPERREPLACECHAR)
+ ReplaceStrings(oContainer, &quot;[0-9]&quot;, UPPERREPLACECHAR)
+End Sub
+
+
+Sub ReplaceStrings(oContainer as Object, sSearchString, sReplaceString as String)
+ oReplaceDesc = oContainer.createReplaceDescriptor()
+ oReplaceDesc.SearchCaseSensitive = True
+ oReplaceDesc.SearchRegularExpression = True
+ oReplaceDesc.Searchstring = sSearchString
+ oReplaceDesc.ReplaceString = sReplaceString
+ oReplCount = oContainer.ReplaceAll(oReplaceDesc)
+End Sub</script:module>
diff --git a/wizards/source/gimmicks/GetTexts.xba b/wizards/source/gimmicks/GetTexts.xba
new file mode 100644
index 000000000..af93738fd
--- /dev/null
+++ b/wizards/source/gimmicks/GetTexts.xba
@@ -0,0 +1,536 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="GetTexts" script:language="StarBasic">Option Explicit
+&apos; Description:
+&apos; This macro extracts the strings out of the currently active document and inserts them into a log document.
+&apos; The aim of the macro is to provide the programmer an insight into the OpenOffice API.
+&apos; It focuses on how document objects are accessed.
+&apos; Therefore not only texts of the document body are retrieved but also texts of general
+&apos; document objects like, annotations, charts and general document information.
+
+Public oLogDocument, oLogText, oLogCursor, oLogHeaderStyle, oLogBodyTextStyle as Object
+Public oDocument as Object
+Public LogArray(1000) as String
+Public LogIndex as Integer
+Public oLocHeaderStyle as Object
+
+Sub Main
+Dim sDocType as String
+Dim oHyperCursor as Object
+Dim oCharStyles as Object
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ On Local Error GoTo NODOCUMENT
+ oDocument = StarDesktop.ActiveFrame.Controller.Model
+ sDocType = GetDocumentType(oDocument)
+ NODOCUMENT:
+ If Err &lt;&gt; 0 Then
+ Msgbox(&quot;This macro extracts all data from the active Writer, Calc or Draw/Impress document.&quot; &amp; chr(13) &amp;_
+ &quot;To start this macro you have to activate a document first.&quot; , 16, GetProductName)
+ Exit Sub
+ End If
+ On Local Error Goto 0
+
+ &apos; Open a new document where all the texts are inserted
+ oLogDocument = CreateNewDocument(&quot;swriter&quot;)
+ If Not IsNull(oLogDocument) Then
+ oLogText = oLogDocument.Text
+
+ &apos; create and define the character styles of the log document
+ oCharStyles = oLogDocument.StyleFamilies.GetByName(&quot;CharacterStyles&quot;)
+ oLogHeaderStyle = oLogDocument.createInstance(&quot;com.sun.star.style.CharacterStyle&quot;)
+ oCharStyles.InsertbyName(&quot;Log Header&quot;, oLogHeaderStyle)
+
+ oLogHeaderStyle.charWeight = com.sun.star.awt.FontWeight.BOLD
+ oLogBodyTextStyle = oLogDocument.createInstance(&quot;com.sun.star.style.CharacterStyle&quot;)
+ oCharStyles.InsertbyName(&quot;Log Body&quot;, oLogBodyTextStyle)
+
+ &apos; Insert the title of the activated document as a hyperlink
+ oHyperCursor = oLogText.createTextCursor()
+ oHyperCursor.CharWeight = com.sun.star.awt.FontWeight.BOLD
+ oHyperCursor.gotoStart(False)
+ oHyperCursor.HyperLinkURL = oDocument.URL
+ oHyperCursor.HyperLinkTarget = oDocument.URL
+ If oDocument.DocumentProperties.Title &lt;&gt; &quot;&quot; Then
+ oHyperCursor.HyperlinkName = oDocument.DocumentProperties.Title
+ End If
+ oLogText.insertString(oHyperCursor, oDocument.DocumentProperties.Title, False)
+ oLogText.insertControlCharacter(oHyperCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+
+ oLogCursor = oLogText.createTextCursor()
+ oLogCursor.GotoEnd(False)
+ &apos; &quot;Switch off&quot; the Hyperlink - Properties
+ oLogCursor.SetPropertyToDefault(&quot;HyperLinkURL&quot;)
+ oLogCursor.SetPropertyToDefault(&quot;HyperLinkTarget&quot;)
+ oLogCursor.SetPropertyToDefault(&quot;HyperLinkName&quot;)
+ LogIndex = 0
+
+ &apos; Get the Properties of the document
+ GetDocumentProps()
+
+ Select Case sDocType
+ Case &quot;swriter&quot;
+ GetWriterStrings()
+ Case &quot;scalc&quot;
+ GetCalcStrings()
+ Case &quot;sdraw&quot;, &quot;simpress&quot;
+ GetDrawStrings()
+ Case Else
+ Msgbox(&quot;This macro only works with a Writer, Calc or Draw/Impress document.&quot;, 16, GetProductName())
+ End Select
+ End If
+End Sub
+
+
+&apos; ***********************************************Calc documents**************************************************
+
+Sub GetCalcStrings()
+Dim i, n as integer
+Dim oSheet as Object
+Dim SheetName as String
+Dim oSheets as Object
+ &apos; Create a sequence of all sheets within the document
+ oSheets = oDocument.Sheets
+
+ For i = 0 to osheets.Count - 1
+ oSheet = osheets.GetbyIndex(i)
+ SheetName = oSheet.Name
+ MakeLogHeadLine(&quot;Sheet No. &quot; &amp; i &amp; &quot; (&quot; &amp; SheetName &amp; &quot;)&quot; )
+
+ &apos; Check the &quot;body&quot; of the sheet
+ GetCellTexts(oSheet)
+
+ If oSheet.IsScenario then
+ MakeLogHeadLine(&quot;Scenario Comments from &quot; &amp; SheetName &amp; &quot;&apos;&quot;)
+ WriteStringtoLogFile(osheet.ScenarioComment)
+ End if
+
+ GetAnnotations(oSheet, &quot;Annotations from &apos;&quot; &amp; SheetName &amp; &quot;&apos;&quot;)
+
+ GetChartStrings(oSheet, &quot;Charts from &apos;&quot; &amp; SheetName &amp; &quot;&apos;&quot;)
+
+ GetControlStrings(oSheet.DrawPage, &quot;Controls from &apos;&quot; &amp; SheetName &amp; &quot;&apos;&quot;)
+ Next
+
+ &apos; Pictures
+ GetCalcGraphicNames()
+
+ GetNamedRanges()
+End Sub
+
+
+Sub GetCellTexts(oSheet as Object)
+Dim BigRange, BigEnum, oCell as Object
+ BigRange = oDocument.CreateInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ BigRange.InsertbyName(&quot;&quot;,oSheet)
+ BigEnum = BigRange.GetCells.CreateEnumeration
+ While BigEnum.hasmoreElements
+ oCell = BigEnum.NextElement
+ If oCell.String &lt;&gt; &quot;&quot; And Val(oCell.String) = 0then
+ WriteStringtoLogFile(oCell.String)
+ End If
+ Wend
+End Sub
+
+
+Sub GetAnnotations(oSheet as Object, HeaderLine as String)
+Dim oNotes as Object
+Dim n as Integer
+ oNotes = oSheet.getAnnotations
+ If oNotes.hasElements() then
+ MakeLogHeadLine(HeaderLine)
+ For n = 0 to oNotes.Count-1
+ WriteStringtoLogFile(oNotes.GetbyIndex(n).String)
+ Next
+ End if
+End Sub
+
+
+Sub GetNamedRanges()
+Dim i as integer
+ MakeLogHeadLine(&quot;Named Ranges&quot;)
+ For i = 0 To oDocument.NamedRanges.Count - 1
+ WriteStringtoLogFile(oDocument.NamedRanges.GetbyIndex(i).Name)
+ Next
+End Sub
+
+
+Sub GetCalcGraphicNames()
+Dim n,m as integer
+ MakeLogHeadLine(&quot;Graphics&quot;)
+ For n = 0 To oDocument.Drawpages.count-1
+ For m = 0 To oDocument.Drawpages.GetbyIndex(n).Count - 1
+ WriteStringtoLogFile(oDocument.DrawPages.GetbyIndex(n).GetbyIndex(m).Text.String)
+ Next m
+ Next n
+End Sub
+
+
+&apos; ***********************************************Writer documents**************************************************
+
+Sub GetParagraphTexts(oParaObject as Object, HeadLine as String)
+Dim ParaEnum as Object
+Dim oPara as Object
+Dim oTextPortEnum as Object
+Dim oTextPortion as Object
+Dim i as integer
+Dim oCellNames()
+Dim oCell as Object
+
+ MakeLogHeadLine(HeadLine)
+ ParaEnum = oParaObject.Text.CreateEnumeration
+
+ While ParaEnum.HasMoreElements
+ oPara = ParaEnum.NextElement
+
+ &apos; Note: The enumeration ParaEnum lists all tables and paragraphs.
+ &apos; Therefore we have to find out what kind of object &quot;oPara&quot; actually is
+ If oPara.supportsService(&quot;com.sun.star.text.Paragraph&quot;) Then
+ &apos; &quot;oPara&quot; is a Paragraph
+ oTextPortEnum = oPara.createEnumeration
+ While oTextPortEnum.hasmoreElements
+ oTextPortion = oTextPortEnum.nextElement()
+ WriteStringToLogFile(oTextPortion.String)
+ Wend
+ Else
+ &apos; &quot;oPara&quot; is a table
+ oCellNames = oPara.CellNames
+ For i = 0 To Ubound(oCellNames())
+ If oCellNames(i) &lt;&gt; &quot;&quot; Then
+ oCell = oPara.getCellByName(oCellNames(i))
+ WriteStringToLogFile(oCell.String)
+ End If
+ Next
+ End If
+ Wend
+End Sub
+
+
+Sub GetChartStrings(oSheet as Object, HeaderLine as String)
+Dim i as Integer
+Dim aChartObject as Object
+Dim aChartDiagram as Object
+
+ MakeLogHeadLine(HeaderLine)
+
+ For i = 0 to oSheet.Charts.Count-1
+ aChartObject = oSheet.Charts.GetByIndex(i).EmbeddedObject
+ If aChartObject.HasSubTitle then
+ WriteStringToLogFile(aChartObject.SubTitle.String)
+ End If
+
+ If aChartObject.HasMainTitle then
+ WriteStringToLogFile(aChartObject.Title.String)
+ End If
+
+ aChartDiagram = aChartObject.Diagram
+
+ If aChartDiagram.hasXAxisTitle Then
+ WriteStringToLogFile(aChartDiagram.XAxisTitle)
+ End If
+
+ If aChartDiagram.hasYAxisTitle Then
+ WriteStringToLogFile(aChartDiagram.YAxisTitle)
+ End If
+
+ If aChartDiagram.hasZAxisTitle Then
+ WriteStringToLogFile(aChartDiagram.ZAxisTitle)
+ End If
+ Next i
+End Sub
+
+
+Sub GetFrameTexts()
+Dim i as integer
+Dim oTextFrame as object
+Dim oFrameEnum as Object
+Dim oFramePort as Object
+Dim oFrameTextEnum as Object
+Dim oFrameTextPort as Object
+
+ MakeLogHeadLine(&quot;Text Frames&quot;)
+ For i = 0 to oDocument.TextFrames.Count-1
+ oTextFrame = oDocument.TextFrames.GetbyIndex(i)
+ WriteStringToLogFile(oTextFrame.Name)
+
+ &apos; Is the frame bound to the page?
+ If oTextFrame.AnchorType = com.sun.star.text.TextContentAnchorType.AT_PAGE Then
+ GetParagraphTexts(oTextFrame, &quot;Text Frame Contents&quot;)
+ End If
+
+ oFrameEnum = oTextFrame.CreateEnumeration
+ While oFrameEnum.HasMoreElements
+ oFramePort = oFrameEnum.NextElement
+ If oFramePort.supportsService(&quot;com.sun.star.text.Paragraph&quot;) then
+ oFrameTextEnum = oFramePort.createEnumeration
+ While oFrameTextEnum.HasMoreElements
+ oFrameTextPort = oFrameTextEnum.NextElement
+ If oFrameTextPort.SupportsService(&quot;com.sun.star.text.TextFrame&quot;) Then
+ WriteStringtoLogFile(oFrameTextPort.String)
+ End If
+ Wend
+ Else
+ WriteStringtoLogFile(oFramePort.Name)
+ End if
+ Wend
+ Next
+End Sub
+
+
+Sub GetTextFieldStrings()
+Dim aTextField as Object
+Dim i as integer
+Dim CurElement as Object
+ MakeLogHeadLine(&quot;Text Fields&quot;)
+ aTextfield = oDocument.getTextfields.CreateEnumeration
+ While aTextField.hasmoreElements
+ CurElement = aTextField.NextElement
+ If CurElement.PropertySetInfo.hasPropertybyName(&quot;Content&quot;) Then
+ WriteStringtoLogFile(CurElement.Content)
+ ElseIf CurElement.PropertySetInfo.hasPropertybyName(&quot;PlaceHolder&quot;) Then
+ WriteStringtoLogFile(CurElement.PlaceHolder)
+ WriteStringtoLogFile(CurElement.Hint)
+ ElseIf Curelement.TextFieldMaster.PropertySetInfo.HasPropertybyName(&quot;Content&quot;) then
+ WriteStringtoLogFile(CurElement.TextFieldMaster.Content)
+ End If
+ Wend
+End Sub
+
+
+Sub GetLinkedFileNames()
+Dim oDocSections as Object
+Dim LinkedFileName as String
+Dim i as Integer
+ If Right(oDocument.URL,3) = &quot;sgl&quot; Then
+ MakeLogHeadLine(&quot;Sub-documents&quot;)
+ oDocSections = oDocument.TextSections
+ For i = 0 to oDocSections.Count - 1
+ LinkedFileName = oDocSections.GetbyIndex(i).FileLink.FileURL
+ If LinkedFileName &lt;&gt; &quot;&quot; Then
+ WriteStringToLogFile(LinkedFileName)
+ End If
+ Next i
+ End If
+End Sub
+
+
+Sub GetSectionNames()
+Dim i as integer
+Dim oDocSections as Object
+ MakeLogHeadLine(&quot;Sections&quot;)
+ oDocSections = oDocument.TextSections
+ For i = 0 to oDocSections.Count-1
+ WriteStringtoLogFile(oDocSections.GetbyIndex(i).Name)
+ Next
+End Sub
+
+
+Sub GetWriterStrings()
+ GetParagraphTexts(oDocument, &quot;Document Body&quot;)
+ GetGraphicNames()
+ GetStyles()
+ GetControlStrings(oDocument.DrawPage, &quot;Controls&quot;)
+ GetTextFieldStrings()
+ GetSectionNames()
+ GetFrameTexts()
+ GetHyperLinks
+ GetLinkedFileNames()
+End Sub
+
+
+&apos; ***********************************************Draw/Impress documents**************************************************
+
+Sub GetDrawPageTitles(LocObject as Object)
+Dim n as integer
+Dim oPage as Object
+
+ For n = 0 to LocObject.Count - 1
+ oPage = LocObject.GetbyIndex(n)
+ WriteStringtoLogFile(oPage.Name)
+ &apos; Is the page a DrawPage and not a MasterPage?
+ If oPage.supportsService(&quot;com.sun.star.drawing.DrawPage&quot;)then
+ &apos; Get the name of the NotesPage (only relevant for Impress documents)
+ If oDocument.supportsService(&quot;com.sun.star.presentation.PresentationDocument&quot;) then
+ WriteStringtoLogFile(oPage.NotesPage.Name)
+ End If
+ End If
+ Next
+End Sub
+
+
+Sub GetPageStrings(oPages as Object)
+Dim m, n, s as Integer
+Dim oPage, oPageElement, oShape as Object
+ For n = 0 to oPages.Count-1
+ oPage = oPages.GetbyIndex(n)
+ If oPage.HasElements then
+ For m = 0 to oPage.Count-1
+ oPageElement = oPage.GetByIndex(m)
+ If HasUnoInterfaces(oPageElement,&quot;com.sun.star.container.XIndexAccess&quot;) Then
+ &apos; The Object &quot;oPageElement&quot; a group of Shapes, that can be accessed by their index
+ For s = 0 To oPageElement.Count - 1
+ WriteStringToLogFile(oPageElement.GetByIndex(s).String)
+ Next s
+ ElseIf HasUnoInterfaces(oPageElement, &quot;com.sun.star.text.XText&quot;) Then
+ WriteStringtoLogFile(oPageElement.String)
+ End If
+ Next
+ End If
+ Next
+End Sub
+
+
+Sub GetDrawStrings()
+Dim oDPages, oMPages as Object
+
+ oDPages = oDocument.DrawPages
+ oMPages = oDocument.Masterpages
+
+ MakeLogHeadLine(&quot;Titles&quot;)
+ GetDrawPageTitles(oDPages)
+ GetDrawPageTitles(oMPages)
+
+ MakeLogHeadLine(&quot;Document Body&quot;)
+ GetPageStrings(oDPages)
+ GetPageStrings(oMPages)
+End Sub
+
+
+&apos; ***********************************************Misc**************************************************
+
+Sub GetDocumentProps()
+Dim oDocuProps as Object
+ MakeLogHeadLine(&quot;Document Properties&quot;)
+ oDocuProps = oDocument.DocumentProperties
+ WriteStringToLogFile(oDocuProps.Title)
+ WriteStringToLogFile(oDocuProps.Description)
+ WriteStringToLogFile(oDocuProps.Subject)
+ WriteStringToLogFile(oDocuProps.Author)
+ &apos; WriteStringToLogFile(oDocuProps.UserDefinedProperties.ReplyTo)
+ &apos; WriteStringToLogFile(oDocuProps.UserDefinedProperties.Recipient)
+ &apos; WriteStringToLogFile(oDocuProps.UserDefinedProperties.References)
+ &apos; WriteStringToLogFile(oDocuProps.Keywords)
+End Sub
+
+
+Sub GetHyperlinks()
+Dim i as integer
+Dim oCrsr as Object
+Dim oAllHyperLinks as Object
+Dim SrchAttributes(0) as new com.sun.star.beans.PropertyValue
+Dim oSearchDesc as Object
+
+ MakeLogHeadLine(&quot;Hyperlinks&quot;)
+ &apos; create a Search-Descriptor
+ oSearchDesc = oDocument.CreateSearchDescriptor
+ oSearchDesc.Valuesearch = False
+
+ &apos; define the Search-attributes
+ srchattributes(0).Name = &quot;HyperLinkURL&quot;
+ srchattributes(0).Value = &quot;&quot;
+ oSearchDesc.SetSearchAttributes(SrchAttributes())
+
+ oAllHyperLinks = oDocument.findAll(oSearchDesc())
+
+ For i = 0 to oAllHyperLinks.Count - 1
+ oFound = oAllHyperLinks(i)
+ oCrsr = oFound.Text.createTextCursorByRange(oFound)
+ WriteStringToLogFile(oCrs.HyperLinkURL) &apos;Url
+ WriteStringToLogFile(oCrs.HyperLinkTarget) &apos;Name
+ WriteStringToLogFile(oCrs.HyperLinkName) &apos;Frame
+ Next i
+End Sub
+
+
+Sub GetGraphicNames()
+Dim i as integer
+Dim oDocGraphics as Object
+ MakeLogHeadLine(&quot;Graphics&quot;)
+ oDocGraphics = oDocument.GraphicObjects
+ For i = 0 to oDocGraphics.count - 1
+ WriteStringtoLogFile(oDocGraphics.GetbyIndex(i).Name)
+ Next
+End Sub
+
+
+Sub GetStyles()
+Dim m,n as integer
+ MakeLogHeadLine(&quot;User-defined Templates&quot;)
+
+ &apos; Check all StyleFamilies(i.e. PageStyles, ParagraphStyles, CharacterStyles, cellStyles)
+ For n = 0 to oDocument.StyleFamilies.Count - 1
+ For m = 0 to oDocument.StyleFamilies.getbyIndex(n).Count-1
+ If oDocument.StyleFamilies.GetbyIndex(n).getbyIndex(m).IsUserDefined then
+ WriteStringtoLogFile(oDocument.StyleFamilies.GetbyIndex(n).getbyIndex(m).Name)
+ End If
+ Next
+ Next
+End Sub
+
+
+Sub GetControlStrings(oDPage as Object, HeaderLine as String)
+Dim aForm as Object
+Dim m,n as integer
+ MakeLogHeadLine(HeaderLine)
+ &apos;SearchFor all possible Controls
+ For n = 0 to oDPage.Forms.Count - 1
+ aForm = oDPage.Forms(n)
+ For m = 0 to aForm.Count-1
+ GetControlContent(aForm.GetbyIndex(m))
+ Next
+ Next
+End Sub
+
+
+Sub GetControlContent(LocControl as Object)
+Dim i as integer
+
+ If LocControl.PropertySetInfo.HasPropertybyName(&quot;Label&quot;) then
+ WriteStringtoLogFile(LocControl.Label)
+
+ ElseIf LocControl.SupportsService(&quot;com.sun.star.form.component.ListBox&quot;) then
+ For i = 0 to Ubound(LocControl.StringItemList())
+ WriteStringtoLogFile(LocControl.StringItemList(i))
+ Next
+ End If
+ If LocControl.PropertySetInfo.HasPropertybyName(&quot;HelpText&quot;) then
+ WriteStringtoLogFile(LocControl.Helptext)
+ End If
+End Sub
+
+&apos; ***********************************************Log document**************************************************
+
+Sub WriteStringtoLogFile( sString as String)
+ If (Not FieldInArray(LogArray(),LogIndex,sString))AND (NOT ISNULL(sString)) Then
+ LogArray(LogIndex) = sString
+ LogIndex = LogIndex + 1
+ oLogText.insertString(oLogCursor,sString,False)
+ oLogText.insertControlCharacter(oLogCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+ End If
+End Sub
+
+
+Sub MakeLogHeadLine(HeadText as String)
+ oLogCursor.CharStyleName = &quot;Log Header&quot;
+ oLogText.insertControlCharacter(oLogCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+ oLogText.insertString(oLogCursor,HeadText,False)
+ oLogText.insertControlCharacter(oLogCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+ oLogCursor.CharStyleName = &quot;Log Body&quot;
+End Sub
+</script:module>
diff --git a/wizards/source/gimmicks/ReadDir.xba b/wizards/source/gimmicks/ReadDir.xba
new file mode 100644
index 000000000..b60469508
--- /dev/null
+++ b/wizards/source/gimmicks/ReadDir.xba
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ReadDir" script:language="StarBasic">Option Explicit
+Public Const SBPAGEX = 800
+Public Const SBPAGEY = 800
+Public Const SBRELDIST = 1.3
+
+&apos; Names of the second Dimension of the Array iLevelPos
+Public Const SBBASEX = 0
+Public Const SBBASEY = 1
+
+Public Const SBOLDSTARTX = 2
+Public Const SBOLDSTARTY = 3
+
+Public Const SBOLDENDX = 4
+Public Const SBOLDENDY = 5
+
+Public Const SBNEWSTARTX = 6
+Public Const SBNEWSTARTY = 7
+
+Public Const SBNEWENDX = 8
+Public Const SBNEWENDY = 9
+
+Public ConnectLevel As Integer
+Public iLevelPos(1,9) As Long
+Public Source as String
+Public iCurLevel as Integer
+Public nConnectLevel as Integer
+Public nOldWidth, nOldHeight As Long
+Public nOldX, nOldY, nOldLevel As Integer
+Public oOldLeavingLine As Object
+Public oOldArrivingLine As Object
+Public DlgReadDir as Object
+Dim oProgressBar as Object
+Dim oDocument As Object
+Dim oPage As Object
+
+
+Sub Main()
+Dim oStandardTemplate as Object
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ oDocument = CreateNewDocument(&quot;sdraw&quot;)
+ If Not IsNull(oDocument) Then
+ oPage = oDocument.DrawPages(0)
+ oStandardTemplate = oDocument.StyleFamilies.GetByName(&quot;graphics&quot;).GetByName(&quot;standard&quot;)
+ oStandardTemplate.CharHeight = 10
+ oStandardTemplate.TextLeftDistance = 100
+ oStandardTemplate.TextRightDistance = 100
+ oStandardTemplate.TextUpperDistance = 50
+ oStandardTemplate.TextLowerDistance = 50
+ DlgReadDir = LoadDialog(&quot;Gimmicks&quot;,&quot;ReadFolderDlg&quot;)
+ oProgressBar = DlgReadDir.Model.ProgressBar1
+ DlgReadDir.Model.TextField1.Text = ConvertFromUrl(GetPathSettings(&quot;Work&quot;))
+ DlgReadDir.Model.cmdGoOn.DefaultButton = True
+ DlgReadDir.GetControl(&quot;TextField1&quot;).SetFocus()
+ DlgReadDir.Execute
+ End If
+End Sub
+
+
+Sub TreeInfo()
+Dim oCurTextShape As Object
+Dim i as Integer
+Dim bStartUpRun As Boolean
+Dim CurFilename as String
+Dim BaseLevel as Integer
+Dim oController as Object
+Dim MaxFileIndex as Integer
+Dim FileNames() as String
+ ToggleDialogControls(False)
+ oProgressBar.ProgressValueMin = 0
+ oProgressBar.ProgressValueMax = 100
+ bStartUpRun = True
+ nOldHeight = 200
+ nOldY = SBPAGEY
+ nOldX = SBPAGEX
+ nOldWidth = SBPAGEX
+ oController = oDocument.GetCurrentController
+ Source = ConvertToURL(DlgReadDir.Model.TextField1.Text)
+ BaseLevel = CountCharsInString(Source, &quot;/&quot;, 1)
+ oProgressBar.ProgressValue = 5
+ DlgReadDir.Model.Label3.Enabled = True
+ FileNames() = ReadSourceDirectory(Source)
+ DlgReadDir.Model.Label4.Enabled = True
+ DlgReadDir.Model.Label3.Enabled = False
+ oProgressBar.ProgressValue = 12
+ FileNames() = BubbleSortList(FileNames())
+ DlgReadDir.Model.Label5.Enabled = True
+ DlgReadDir.Model.Label4.Enabled = False
+ oProgressBar.ProgressValue = 20
+ MaxFileIndex = Ubound(FileNames(),1)
+ For i = 0 To MaxFileIndex
+ oProgressBar.ProgressValue = 20 + (i/MaxFileIndex * 80)
+ CurFilename = FileNames(i,1)
+ SetNewLevels(FileNames(i,0), BaseLevel)
+ oCurTextShape = CreateTextShape(oPage, CurFilename)
+ CheckPageWidth(oCurTextShape.Size.Width)
+ iLevelPos(iCurLevel,SBBASEY) = oCurTextShape.Position.Y
+ If i = 0 Then
+ AdjustPageHeight(oCurTextShape.Size.Height, MaxFileIndex + 1)
+ End If
+ &apos; The Current TextShape has To be connected with a TextShape one Level higher
+ &apos; except for a TextShape In Level 0:
+ If Not bStartUpRun Then
+ &apos; A leaving Line Is only drawn when level is not 0
+ If iCurLevel&lt;&gt; 0 Then
+ &apos; Determine the Coordinates of the arriving Line
+ iLevelPos(iCurLevel,SBOLDSTARTX) = iLevelPos(nConnectLevel,SBNEWSTARTX)
+ iLevelPos(iCurLevel,SBOLDSTARTY) = oCurTextShape.Position.Y + 0.5 * oCurTextShape.Size.Height
+
+ iLevelPos(iCurLevel,SBOLDENDX) = iLevelPos(iCurLevel,SBBASEX)
+ iLevelPos(iCurLevel,SBOLDENDY) = oCurTextShape.Position.Y + 0.5 * oCurTextShape.Size.Height
+
+ oOldArrivingLine = DrawLine(iCurLevel, SBOLDSTARTX, SBOLDSTARTY, SBOLDENDX, SBOLDENDY, oPage)
+
+ &apos; Determine the End-Coordinates of the last leaving Line
+ iLevelPos(nConnectLevel,SBNEWENDX) = iLevelPos(nConnectLevel,SBNEWSTARTX)
+ iLevelPos(nConnectLevel,SBNEWENDY) = oCurTextShape.Position.Y + 0.5 * oCurTextShape.Size.Height
+ Else
+ &apos; On Level 0 the last Leaving Line&apos;s Endpoint is the upper edge of the TextShape
+ iLevelPos(nConnectLevel,SBNEWENDY) = oCurTextShape.Position.Y
+ iLevelPos(nConnectLevel,SBNEWENDX) = iLevelPos(nConnectLevel,SBNEWSTARTX)
+ End If
+ &apos; Draw the Connectors To the previous TextShapes
+ oOldLeavingLine = DrawLine(nConnectLevel, SBNEWSTARTX, SBNEWSTARTY, SBNEWENDX, SBNEWENDY, oPage)
+ Else
+ &apos; StartingPoint of the leaving Edge
+ bStartUpRun = FALSE
+ End If
+
+ &apos; Determine the beginning Coordinates of the leaving Line
+ iLevelPos(iCurLevel,SBNEWSTARTX) = iLevelPos(iCurLevel,SBBASEX) + 0.5 * oCurTextShape.Size.Width
+ iLevelPos(iCurLevel,SBNEWSTARTY) = iLevelPos(iCurLevel,SBBASEY) + oCurTextShape.Size.Height
+
+ &apos; Save the values For the Next run
+ nOldHeight = oCurTextShape.Size.Height
+ nOldX = oCurTextShape.Position.X
+ nOldWidth = oCurTextShape.Size.Width
+ nOldLevel = iCurLevel
+ Next i
+ ToggleDialogControls(True)
+ DlgReadDir.Model.cmdGoOn.Enabled = False
+End Sub
+
+
+Function CreateTextShape(oPage as Object, Filename as String)
+Dim oTextShape As Object
+Dim aPoint As New com.sun.star.awt.Point
+
+ aPoint.X = CalculateXPoint()
+ aPoint.Y = nOldY + SBRELDIST * nOldHeight
+ nOldY = aPoint.Y
+
+ oTextShape = oDocument.createInstance(&quot;com.sun.star.drawing.TextShape&quot;)
+ oTextShape.LineStyle = 1
+ oTextShape.Position = aPoint
+
+ oPage.add(oTextShape)
+ oTextShape.TextAutoGrowWidth = TRUE
+ oTextShape.TextAutoGrowHeight = TRUE
+ oTextShape.String = FileName
+
+ &apos; Configure Size And Position of the TextShape according to its Scripting
+ aPoint.X = iLevelPos(iCurLevel,SBBASEX)
+ oTextShape.Position = aPoint
+ CreateTextShape() = oTextShape
+End Function
+
+
+Function CalculateXPoint()
+ &apos; The current level Is lower than the Old one
+ If (iCurLevel&lt; nOldLevel) And (iCurLevel&lt;&gt; 0) Then
+ &apos; ClearArray(iLevelPos(),iCurLevel+1)
+ Elseif iCurLevel= 0 Then
+ iLevelPos(iCurLevel,SBBASEX) = SBPAGEX
+ &apos; The current level Is higher than the old one
+ Elseif iCurLevel&gt; nOldLevel Then
+ iLevelPos(iCurLevel,SBBASEX) = iLevelPos(iCurLevel-1,SBBASEX) + nOldWidth + 100
+ End If
+ CalculateXPoint = iLevelPos(iCurLevel,SBBASEX)
+End Function
+
+
+Function DrawLine(nLevel, nStartX, nStartY, nEndX, nEndY As Integer, oPage as Object)
+Dim oConnect As Object
+Dim aPoint As New com.sun.star.awt.Point
+Dim aSize As New com.sun.star.awt.Size
+ aPoint.X = iLevelPos(nLevel,nStartX)
+ aPoint.Y = iLevelPos(nLevel,nStartY)
+ aSize.Width = iLevelPos(nLevel,nEndX) - iLevelPos(nLevel,nStartX)
+ aSize.Height = iLevelPos(nLevel,nEndY) - iLevelPos(nLevel,nStartY)
+ oConnect = oDocument.createInstance(&quot;com.sun.star.drawing.LineShape&quot;)
+ oConnect.Position = aPoint
+ oConnect.Size = aSize
+ oPage.Add(oConnect)
+ DrawLine() = oConnect
+End Function
+
+
+Sub GetSourceDirectory()
+ GetFolderName(DlgReadDir.Model.TextField1)
+End Sub
+
+
+Function ReadSourceDirectory(ByVal Source As String)
+Dim i as Integer
+Dim m as Integer
+Dim n as Integer
+Dim s as integer
+Dim FileName as string
+Dim FileNameList(100,1) as String
+Dim DirList(0) as String
+Dim oUCBobject as Object
+Dim DirContent() as String
+Dim SystemPath as String
+Dim PathSeparator as String
+Dim MaxFileIndex as Integer
+ PathSeparator = GetPathSeparator()
+ oUcbobject = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ m = 0
+ s = 0
+ DirList(0) = Source
+ FileNameList(n,0) = Source
+ SystemPath = ConvertFromUrl(Source)
+ FileNameList(n,1) = FileNameoutofPath(SystemPath, PathSeparator)
+ n = 1
+ Do
+ Source = DirList(m)
+ m = m + 1
+ DirContent() = oUcbObject.GetFolderContents(Source,True)
+ If Ubound(DirContent()) &lt;&gt; -1 Then
+ MaxFileIndex = Ubound(DirContent())
+ For i = 0 to MaxFileIndex
+ FileName = DirContent(i)
+ FileNameList(n,0) = FileName
+ SystemPath = ConvertFromUrl(FileName)
+ FileNameList(n,1) = FileNameOutofPath(SystemPath, PathSeparator)
+ n = n + 1
+ If n &gt; Ubound(FileNameList(),1) Then
+ ReDim Preserve FileNameList(n + 10,1) as String
+ End If
+ If oUcbObject.IsFolder(FileName) Then
+ s = s + 1
+ ReDim Preserve DirList(s) as String
+ DirList(s) = FileName
+ End If
+ Next i
+ End If
+ Loop Until m &gt; Ubound(DirList())
+ ReDim Preserve FileNameList(n-1,1) as String
+ ReadSourceDirectory() = FileNameList()
+End Function
+
+
+Sub CloseDialog
+ DlgReadDir.EndExecute
+End Sub
+
+
+Sub AdjustPageHeight(lShapeHeight, FileCount)
+Dim lNecHeight as Long
+Dim lBorders as Long
+ oDocument.LockControllers
+ lBorders = oPage.BorderTop + oPage.BorderBottom
+ lNecHeight = SBPAGEY + (FileCount * SBRELDIST * lShapeHeight)
+ If lNecHeight &gt; (oPage.Height - lBorders) Then
+ oPage.Height = lNecHeight + lBorders + 500
+ End If
+ oDocument.UnlockControllers
+End Sub
+
+
+Sub SetNewLevels(FileName as String, BaseLevel as Integer)
+ iCurLevel= CountCharsInString(FileName, &quot;/&quot;, 1) - BaseLevel
+ If iCurLevel &lt;&gt; 0 Then
+ nConnectLevel = iCurLevel- 1
+ Else
+ nConnectLevel = iCurLevel
+ End If
+ If iCurLevel &gt; Ubound(iLevelPos(),1) Then
+ ReDim Preserve iLevelPos(iCurLevel,9) as Long
+ End If
+End Sub
+
+
+Sub CheckPageWidth(TextWidth as Long)
+Dim PageWidth as Long
+Dim BaseX as Long
+ PageWidth = oPage.Width
+ BaseX = iLevelPos(iCurLevel,SBBASEX)
+ If BaseX + TextWidth &gt; PageWidth - 1000 Then
+ oPage.Width = 1000 + BaseX + TextWidth
+ End If
+End Sub
+
+
+Sub ToggleDialogControls(bDoEnable as Boolean)
+ With DlgReadDir.Model
+ .cmdGoOn.Enabled = bDoEnable
+ .cmdGetDir.Enabled = bDoEnable
+ .Label1.Enabled = bDoEnable
+ .Label2.Enabled = bDoEnable
+ .TextField1.Enabled = bDoEnable
+ End With
+End Sub</script:module>
diff --git a/wizards/source/gimmicks/ReadFolderDlg.xdl b/wizards/source/gimmicks/ReadFolderDlg.xdl
new file mode 100644
index 000000000..797e97755
--- /dev/null
+++ b/wizards/source/gimmicks/ReadFolderDlg.xdl
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="ReadFolderDlg" dlg:left="161" dlg:top="81" dlg:width="180" dlg:height="136" dlg:closeable="true" dlg:moveable="true" dlg:title="Read and Design Recursively">
+ <dlg:bulletinboard>
+ <dlg:button dlg:id="cmdGetDir" dlg:tab-index="0" dlg:left="161" dlg:top="49" dlg:width="14" dlg:height="14" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.ReadDir.GetSourceDirectory?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:textfield dlg:id="TextField1" dlg:tab-index="1" dlg:left="6" dlg:top="50" dlg:width="147" dlg:height="12"/>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="2" dlg:left="49" dlg:top="115" dlg:width="35" dlg:height="14" dlg:value="~Cancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.ReadDir.CloseDialog?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="3" dlg:left="95" dlg:top="115" dlg:width="35" dlg:height="14" dlg:value="~GoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.ReadDir.TreeInfo?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="Label1" dlg:tab-index="4" dlg:left="6" dlg:top="38" dlg:width="122" dlg:height="8" dlg:value="Top level path"/>
+ <dlg:text dlg:id="Label2" dlg:tab-index="5" dlg:left="6" dlg:top="4" dlg:width="168" dlg:height="26" dlg:value="This macro will create a drawing document and design a complete tree view of all subdirectories from a given path." dlg:multiline="true"/>
+ <dlg:progressmeter dlg:id="ProgressBar1" dlg:tab-index="6" dlg:left="6" dlg:top="101" dlg:width="170" dlg:height="10"/>
+ <dlg:text dlg:id="Label3" dlg:tab-index="7" dlg:disabled="true" dlg:left="6" dlg:top="69" dlg:width="170" dlg:height="8" dlg:value="Getting the files and subdirectories..."/>
+ <dlg:text dlg:id="Label4" dlg:tab-index="8" dlg:disabled="true" dlg:left="6" dlg:top="80" dlg:width="170" dlg:height="8" dlg:value="Sorting the files and subdirectories..."/>
+ <dlg:text dlg:id="Label5" dlg:tab-index="9" dlg:disabled="true" dlg:left="6" dlg:top="91" dlg:width="170" dlg:height="8" dlg:value="Drawing the filestructure..."/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/gimmicks/UserfieldDlg.xdl b/wizards/source/gimmicks/UserfieldDlg.xdl
new file mode 100644
index 000000000..efa0eff7e
--- /dev/null
+++ b/wizards/source/gimmicks/UserfieldDlg.xdl
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="UserfieldDlg" dlg:left="161" dlg:top="57" dlg:width="281" dlg:height="214" dlg:closeable="true" dlg:moveable="true" dlg:title="Modify User Data">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="Label1" dlg:tab-index="0" dlg:left="6" dlg:top="48" dlg:width="57" dlg:height="8" dlg:value="Label1"/>
+ <dlg:text dlg:id="Label2" dlg:tab-index="1" dlg:left="6" dlg:top="64" dlg:width="57" dlg:height="8" dlg:value="Label2"/>
+ <dlg:text dlg:id="Label3" dlg:tab-index="2" dlg:left="6" dlg:top="80" dlg:width="57" dlg:height="8" dlg:value="Label3"/>
+ <dlg:text dlg:id="Label4" dlg:tab-index="3" dlg:left="6" dlg:top="96" dlg:width="57" dlg:height="8" dlg:value="Label4"/>
+ <dlg:text dlg:id="Label5" dlg:tab-index="4" dlg:left="6" dlg:top="112" dlg:width="57" dlg:height="8" dlg:value="Label5"/>
+ <dlg:text dlg:id="Label6" dlg:tab-index="5" dlg:left="6" dlg:top="128" dlg:width="57" dlg:height="8" dlg:value="Label6"/>
+ <dlg:text dlg:id="Label7" dlg:tab-index="6" dlg:left="6" dlg:top="144" dlg:width="57" dlg:height="8" dlg:value="Label7"/>
+ <dlg:text dlg:id="Label8" dlg:tab-index="7" dlg:left="6" dlg:top="160" dlg:width="57" dlg:height="8" dlg:value="Label8"/>
+ <dlg:text dlg:id="Label9" dlg:tab-index="8" dlg:left="6" dlg:top="176" dlg:width="57" dlg:height="8" dlg:value="Label9"/>
+ <dlg:textfield dlg:id="TextField1" dlg:tab-index="9" dlg:left="65" dlg:top="46" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField2" dlg:tab-index="10" dlg:left="65" dlg:top="62" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField3" dlg:tab-index="11" dlg:left="65" dlg:top="78" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField4" dlg:tab-index="12" dlg:left="65" dlg:top="94" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField5" dlg:tab-index="13" dlg:left="65" dlg:top="110" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField6" dlg:tab-index="14" dlg:left="65" dlg:top="126" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField7" dlg:tab-index="15" dlg:left="65" dlg:top="142" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField8" dlg:tab-index="16" dlg:left="65" dlg:top="158" dlg:width="193" dlg:height="12"/>
+ <dlg:textfield dlg:id="TextField9" dlg:tab-index="17" dlg:left="65" dlg:top="174" dlg:width="193" dlg:height="12"/>
+ <dlg:scrollbar dlg:id="ScrollBar1" dlg:tab-index="18" dlg:left="263" dlg:top="46" dlg:width="12" dlg:height="140" dlg:align="vertical">
+ <script:event script:event-name="on-adjustmentvaluechange" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.ScrollControls?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:scrollbar>
+ <dlg:button dlg:id="cmdQuit" dlg:tab-index="19" dlg:left="6" dlg:top="193" dlg:width="35" dlg:height="14" dlg:help-text="Exit Macro" dlg:value="Exit">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.StopMacro?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdSave" dlg:tab-index="20" dlg:left="45" dlg:top="193" dlg:width="35" dlg:height="14" dlg:help-text="Save All Data of All Users to File" dlg:value="~Save">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.SaveSettings?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdSelect" dlg:tab-index="21" dlg:left="84" dlg:top="193" dlg:width="35" dlg:height="14" dlg:help-text="Replace the User Data in &lt;PRODUCTNAME&gt; With the User Data Above" dlg:value="Se~lect">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.SelectCurrentFields?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdNextUser" dlg:tab-index="22" dlg:left="162" dlg:top="193" dlg:width="35" dlg:height="14" dlg:tag="1" dlg:help-text="Show Data of Next User" dlg:value="Next &gt;&gt;">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.StepToRecord?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdPrevUser" dlg:tab-index="23" dlg:left="123" dlg:top="193" dlg:width="35" dlg:height="14" dlg:tag="-1" dlg:help-text="Show Data of Previous User" dlg:value="&lt;&lt;Previous">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.StepToRecord?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="CommandButton1" dlg:tab-index="24" dlg:left="201" dlg:top="193" dlg:width="35" dlg:height="14" dlg:help-text="Add Data for New User" dlg:value="~New">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.AddRecord?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="Label10" dlg:tab-index="25" dlg:left="6" dlg:top="6" dlg:width="269" dlg:height="34" dlg:value="This macro lets you easily administrate several user profiles.&#x0a;The user data of several users may be stored in a single file in the directory &lt;ConfigDir&gt;. From there, you can select a particular user whose data is then the current user data in &lt;PRODUCTNAME&gt;." dlg:multiline="true"/>
+ <dlg:button dlg:id="cmdDelete" dlg:tab-index="26" dlg:left="240" dlg:top="193" dlg:width="35" dlg:height="14" dlg:help-text="Delete Data of Current User" dlg:value="Delete">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Gimmicks.Userfields.DeleteCurrentSettings?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/gimmicks/Userfields.xba b/wizards/source/gimmicks/Userfields.xba
new file mode 100644
index 000000000..17426cb49
--- /dev/null
+++ b/wizards/source/gimmicks/Userfields.xba
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Userfields" script:language="StarBasic">Option Explicit
+&apos;Todo: Controlling Scrollbar via Keyboard
+
+Public Const SBMAXFIELDINDEX = 14
+
+Public DlgUserFields as Object
+Public oDocument as Object
+Public UserFieldDataType(SBMAXFIELDINDEX,1) as String
+Public ScrollBarValue as Integer
+Public UserFieldFamily(0, SBMAXfIELDINDEX) as String
+Public Const SBTBCOUNT = 9
+Public oUserDataAccess as Object
+Public CurFieldIndex as Integer
+Public FilePath as String
+
+Sub StartChangesUserfields
+Dim SystemPath as String
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ UserFieldDatatype(0,0) = &quot;COMPANY&quot;
+ UserFieldDatatype(0,1) = &quot;o&quot;
+ UserFieldDatatype(1,0) = &quot;FIRSTNAME&quot;
+ UserFieldDatatype(1,1) = &quot;givenname&quot;
+ UserFieldDatatype(2,0) = &quot;LASTNAME&quot;
+ UserFieldDatatype(2,1) = &quot;sn&quot;
+ UserFieldDatatype(3,0) = &quot;INITIALS&quot;
+ UserFieldDatatype(3,1) = &quot;initials&quot;
+ UserFieldDatatype(4,0) = &quot;STREET&quot;
+ UserFieldDatatype(4,1) = &quot;street&quot;
+ UserFieldDatatype(5,0) = &quot;COUNTRY&quot;
+ UserFieldDatatype(5,1) = &quot;c&quot;
+ UserFieldDatatype(6,0) = &quot;ZIP&quot;
+ UserFieldDatatype(6,1) = &quot;postalcode&quot;
+ UserFieldDatatype(7,0) = &quot;CITY&quot;
+ UserFieldDatatype(7,1) = &quot;l&quot;
+ UserFieldDatatype(8,0) = &quot;TITLE&quot;
+ UserFieldDatatype(8,1) = &quot;title&quot;
+ UserFieldDatatype(9,0) = &quot;POSITION&quot;
+ UserFieldDatatype(9,1) = &quot;position&quot;
+ UserFieldDatatype(10,0) = &quot;PHONE_HOME&quot;
+ UserFieldDatatype(10,1) = &quot;homephone&quot;
+ UserFieldDatatype(11,0) = &quot;PHONE_WORK&quot;
+ UserFieldDatatype(11,1) = &quot;telephonenumber&quot;
+ UserFieldDatatype(12,0) = &quot;FAX&quot;
+ UserFieldDatatype(12,1) = &quot;facsimiletelephonenumber&quot;
+ UserFieldDatatype(13,0) = &quot;E-MAIL&quot;
+ UserFieldDatatype(13,1) = &quot;mail&quot;
+ UserFieldDatatype(14,0) = &quot;STATE&quot;
+ UserFieldDatatype(14,1) = &quot;st&quot;
+ FilePath = GetPathSettings(&quot;Config&quot;, False) &amp; &quot;/&quot; &amp; &quot;UserData.dat&quot;
+ DlgUserFields = LoadDialog(&quot;Gimmicks&quot;,&quot;UserfieldDlg&quot;)
+ SystemPath = ConvertFromUrl(FilePath)
+ DlgUserFields.Model.Label10.Label = ReplaceString(DlgUserFields.Model.Label10.Label, &quot;&apos;&quot; &amp; SystemPath &amp; &quot;&apos;&quot;, &quot;&lt;ConfigDir&gt;&quot;)
+ DlgUserFields.Model.Label10.Label = ReplaceString(DlgUserFields.Model.Label10.Label, GetProductName(), &quot;&lt;PRODUCTNAME&gt;&quot;)
+ DlgUserFields.Model.cmdSelect.HelpText = ReplaceString(DlgUserFields.Model.cmdSelect.HelpText, GetProductName(), &quot;&lt;PRODUCTNAME&gt;&quot;)
+ ScrollBarValue = 0
+ oUserDataAccess = GetRegistryKeyContent(&quot;org.openoffice.UserProfile/Data&quot;, True)
+ InitializeUserFamily()
+ FillDialog()
+ DlgUserFields.Execute
+ DlgUserFields.Dispose()
+End Sub
+
+
+Sub FillDialog()
+Dim a as Integer
+ With DlgUserFields
+ For a = 1 To SBTBCount
+ .GetControl(&quot;Label&quot; &amp; a).Model.Label = UserFieldDataType(a-1,0)
+ .GetControl(&quot;TextField&quot; &amp; a).Model.Text = UserFieldFamily(CurFieldIndex, a-1)
+ Next a
+ .Model.ScrollBar1.ScrollValueMax = (SBMAXFIELDINDEX+1) - SBTBCOUNT
+ .Model.ScrollBar1.BlockIncrement = SBTBCOUNT
+ .Model.ScrollBar1.LineIncrement = 1
+ .Model.ScrollBar1.ScrollValue = ScrollBarValue
+ End With
+End Sub
+
+
+Sub ScrollControls()
+ ScrollTextFieldInfo(ScrollBarValue)
+ ScrollBarValue = DlgUserFields.Model.ScrollBar1.ScrollValue
+ If (ScrollBarValue + SBTBCOUNT) &gt;= SBMAXFIELDINDEX + 1 Then
+ ScrollBarValue = (SBMAXFIELDINDEX + 1) - SBTBCOUNT
+ End If
+ FillupTextFields()
+End Sub
+
+
+Sub ScrollTextFieldInfo(ByVal iScrollValue as Integer)
+Dim a as Integer
+Dim CurIndex as Integer
+ For a = 1 To SBTBCOUNT
+ CurIndex = (a-1) + iScrollValue
+ UserFieldFamily(CurFieldIndex,CurIndex) = DlgUserFields.GetControl(&quot;TextField&quot; &amp; a).Model.Text
+ Next a
+End Sub
+
+
+Sub StopMacro()
+ DlgUserFields.EndExecute
+End Sub
+
+
+Sub SaveSettings()
+Dim n as Integer
+Dim m as Integer
+Dim MaxIndex as Integer
+ ScrollTextFieldInfo(DlgUserFields.Model.ScrollBar1.ScrollValue)
+ MaxIndex = Ubound(UserFieldFamily(), 1)
+ Dim FileStrings(MaxIndex) as String
+ For n = 0 To MaxIndex
+ FileStrings(n) = &quot;&quot;
+ For m = 0 To SBMAXFIELDINDEX
+ FileStrings(n) = FileStrings(n) &amp; UserFieldFamily(n,m) &amp; &quot;;&quot;
+ Next m
+ Next n
+ SaveDataToFile(FilePath, FileStrings(), True)
+End Sub
+
+
+Sub ToggleButtons(ByVal Index as Integer)
+Dim i as Integer
+ CurFieldIndex = Index
+ DlgUserFields.Model.cmdNextUser.Enabled = CurFieldIndex &lt;&gt; Ubound(UserFieldFamily(), 1)
+ DlgUserFields.Model.cmdPrevUser.Enabled = CurFieldIndex &lt;&gt; 0
+End Sub
+
+
+Sub InitializeUserFamily()
+Dim FirstIndex as Integer
+Dim UserFieldstrings() as String
+Dim LocStrings() as String
+Dim bFileExists as Boolean
+Dim n as Integer
+Dim m as Integer
+ bFileExists = LoadDataFromFile(GetPathSettings(&quot;Config&quot;, False) &amp; &quot;/&quot; &amp; &quot;UserData.dat&quot;, UserFieldStrings())
+ If bFileExists Then
+ FirstIndex = Ubound(UserFieldStrings())
+ ReDim Preserve UserFieldFamily(FirstIndex, SBMAXFIELDINDEX) as String
+ For n = 0 To FirstIndex
+ LocStrings() = ArrayOutofString(UserFieldStrings(n), &quot;;&quot;)
+ For m = 0 To SBMAXFIELDINDEX
+ UserFieldFamily(n,m) = LocStrings(m)
+ Next m
+ Next n
+ Else
+ ReDim Preserve UserFieldFamily(0,SBMAXFIELDINDEX) as String
+ For m = 0 To SBMAXFIELDINDEX
+ UserFieldFamily(0,m) = oUserDataAccess.GetByName(UserFieldDataType(m,1))
+ Next m
+ End If
+ ToggleButtons(0)
+End Sub
+
+
+Sub AddRecord()
+Dim i as Integer
+Dim MaxIndex as Integer
+ For i = 1 To SBTBCount
+ DlgUserFields.GetControl(&quot;TextField&quot; &amp; i).Model.Text = &quot;&quot;
+ Next i
+ MaxIndex = Ubound(UserFieldFamily(),1)
+ ReDim Preserve UserFieldFamily(MaxIndex + 1, SBMAXFIELDINDEX) as String
+ ToggleButtons(MaxIndex + 1, 1)
+End Sub
+
+
+Sub FillupTextFields()
+Dim a as Integer
+Dim CurIndex as Integer
+ For a = 1 To SBTBCOUNT
+ CurIndex = (a-1) + ScrollBarValue
+ DlgUserFields.GetControl(&quot;Label&quot; &amp; a).Model.Label = UserFieldDataType(CurIndex,0)
+ DlgUserFields.GetControl(&quot;TextField&quot; &amp; a).Model.Text = UserFieldFamily(CurFieldIndex, CurIndex)
+ Next a
+End Sub
+
+
+Sub StepToRecord(aEvent as Object)
+Dim iStep as Integer
+ iStep = CInt(aEvent.Source.Model.Tag)
+ ScrollTextFieldInfo(ScrollBarValue)
+ ToggleButtons(CurFieldIndex + iStep)
+ FillUpTextFields()
+End Sub
+
+
+Sub SelectCurrentFields()
+Dim MaxIndex as Integer
+Dim i as Integer
+ ScrollTextFieldInfo(ScrollBarValue)
+ MaxIndex = Ubound(UserFieldFamily(),2)
+ For i = 0 To MaxIndex
+ oUserDataAccess.ReplaceByName(UserFieldDataType(i,1), UserFieldFamily(CurFieldIndex, i))
+ Next i
+ oUserDataAccess.commitChanges()
+End Sub
+
+
+Sub DeleteCurrentSettings()
+Dim n as Integer
+Dim m as Integer
+Dim MaxIndex as Integer
+ MaxIndex = Ubound(UserFieldFamily(),1)
+ If CurFieldIndex &lt; MaxIndex Then
+ For n = CurFieldIndex To MaxIndex - 1
+ For m = 0 To SBMAXFIELDINDEX
+ UserFieldFamily(n,m) = UserFieldFamily(n + 1,m)
+ Next m
+ Next n
+ Else
+ CurFieldIndex = MaxIndex - 1
+ End If
+ ReDim Preserve UserFieldFamily(MaxIndex-1, SBMAXfIELDINDEX) as String
+ FillupTextFields()
+ ToggleButtons(CurFieldIndex)
+End Sub</script:module> \ No newline at end of file
diff --git a/wizards/source/gimmicks/dialog.xlb b/wizards/source/gimmicks/dialog.xlb
new file mode 100644
index 000000000..22271dacb
--- /dev/null
+++ b/wizards/source/gimmicks/dialog.xlb
@@ -0,0 +1,6 @@
+<?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="Gimmicks" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="UserfieldDlg"/>
+ <library:element library:name="ReadFolderDlg"/>
+</library:library>
diff --git a/wizards/source/gimmicks/readdirs.dlg b/wizards/source/gimmicks/readdirs.dlg
new file mode 100644
index 000000000..20a89426d
--- /dev/null
+++ b/wizards/source/gimmicks/readdirs.dlg
Binary files differ
diff --git a/wizards/source/gimmicks/script.xlb b/wizards/source/gimmicks/script.xlb
new file mode 100644
index 000000000..5c820ba43
--- /dev/null
+++ b/wizards/source/gimmicks/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="Gimmicks" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="GetTexts"/>
+ <library:element library:name="Userfields"/>
+ <library:element library:name="ChangeAllChars"/>
+ <library:element library:name="AutoText"/>
+ <library:element library:name="ReadDir"/>
+</library:library>
diff --git a/wizards/source/imagelists/imagelists.ilst b/wizards/source/imagelists/imagelists.ilst
new file mode 100644
index 000000000..0a6714c65
--- /dev/null
+++ b/wizards/source/imagelists/imagelists.ilst
@@ -0,0 +1,7 @@
+%MODULE%/dbaccess/res/exinfo.png
+%MODULE%/wizards/res/portrait_32.png
+%MODULE%/wizards/res/landscape_32.png
+%MODULE%/wizards/res/formarrangelistside_42.png
+%MODULE%/wizards/res/formarrangelisttop_42.png
+%MODULE%/wizards/res/formarrangetable_42.png
+%MODULE%/wizards/res/formarrangefree_42.png
diff --git a/wizards/source/importwizard/API.xba b/wizards/source/importwizard/API.xba
new file mode 100644
index 000000000..97111aeca
--- /dev/null
+++ b/wizards/source/importwizard/API.xba
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="API" script:language="StarBasic">Declare Function RegOpenKeyEx Lib &quot;advapi32.dll&quot; Alias &quot;RegOpenKeyExA&quot; _
+ (ByVal hKey As Long, _
+ ByVal lpSubKey As String, _
+ ByVal ulOptions As Long, _
+ ByVal samDesired As Long, _
+ phkResult As Long) As Long
+
+Declare Function RegQueryValueExString Lib &quot;advapi32.dll&quot; Alias &quot;RegQueryValueExA&quot; _
+ (ByVal hKey As Long, _
+ ByVal lpValueName As String, _
+ ByVal lpReserved As Long, _
+ lpType As Long, _
+ lpData As String, _
+ lpcbData As Long) As Long
+
+Declare Function RegQueryValueExLong Lib &quot;advapi32.dll&quot; Alias &quot;RegQueryValueExA&quot; _
+ (ByVal hKey As Long, _
+ ByVal lpValueName As String, _
+ ByVal lpReserved As Long, _
+ lpType As Long, _
+ lpData As Long, _
+ lpcbData As Long) As Long
+
+Declare Function RegQueryValueExNULL Lib &quot;advapi32.dll&quot; Alias &quot;RegQueryValueExA&quot; _
+ (ByVal hKey As Long, _
+ ByVal lpValueName As String, _
+ ByVal lpReserved As Long, _
+ lpType As Long, _
+ ByVal lpData As Long, _
+ lpcbData As Long) As Long
+
+Declare Function RegCloseKeyA Lib &quot;advapi32.dll&quot; Alias &quot;RegCloseKey&quot; _
+ (ByVal hKey As Long) As Long
+
+
+Public Const HKEY_CLASSES_ROOT = &amp;H80000000
+Public Const HKEY_CURRENT_USER = &amp;H80000001
+Public Const HKEY_LOCAL_MACHINE = &amp;H80000002
+Public Const HKEY_USERS = &amp;H80000003
+Public Const KEY_ALL_ACCESS = &amp;H3F
+Public Const REG_OPTION_NON_VOLATILE = 0
+Public Const REG_SZ As Long = 1
+Public Const REG_DWORD As Long = 4
+Public Const ERROR_NONE = 0
+Public Const ERROR_BADDB = 1
+Public Const ERROR_BADKEY = 2
+Public Const ERROR_CANTOPEN = 3
+Public Const ERROR_CANTREAD = 4
+Public Const ERROR_CANTWRITE = 5
+Public Const ERROR_OUTOFMEMORY = 6
+Public Const ERROR_INVALID_PARAMETER = 7
+Public Const ERROR_ACCESS_DENIED = 8
+Public Const ERROR_INVALID_PARAMETERS = 87
+Public Const ERROR_NO_MORE_ITEMS = 259
+&apos;Public Const KEY_READ = &amp;H20019
+
+
+Function OpenRegKey(lBaseKey As Long, sKeyName As String) As Variant
+Dim LocKeyValue
+Dim hKey as Long
+Dim lRetValue as Long
+ lRetValue = RegOpenKeyEx(lBaseKey, sKeyName, 0, KEY_ALL_ACCESS, hKey)
+&apos; lRetValue = QueryValue(HKEY_LOCAL_MACHINE, &quot;SOFTWARE\Microsoft\Outlook Express\5.0\Default Settings&quot;, &quot;Revocation Checking&quot;)
+ If hKey &lt;&gt; 0 Then
+ RegCloseKeyA (hKey)
+ End If
+ OpenRegKey() = lRetValue
+End Function
+
+
+Function GetDefaultPath(CurOffice as Integer) As String
+Dim sPath as String
+Dim Index as Integer
+ Select Case Wizardmode
+ Case SBMICROSOFTMODE
+ Index = Applications(CurOffice,SBAPPLKEY)
+ If GetGUIType = 1 Then &apos; Windows
+ sPath = QueryValue(HKEY_LOCAL_MACHINE, sKeyName(Index), sValueName(Index))
+ Else
+ sPath = &quot;&quot;
+ End If
+ If sPath = &quot;&quot; Then
+ sPath = SOWorkPath
+ End If
+ GetDefaultPath = sPath
+ End Select
+End Function
+
+
+Function GetTemplateDefaultPath(Index as Integer) As String
+Dim sLocTemplatePath as String
+Dim sLocProgrampath as String
+Dim Progstring as String
+Dim PathList()as String
+Dim Maxindex as Integer
+Dim OldsLocTemplatePath
+Dim sTemplateKeyName as String
+Dim sTemplateValueName as String
+ On Local Error Goto NOVAlIDSYSTEMPATH
+ Select Case WizardMode
+ Case SBMICROSOFTMODE
+ If GetGUIType = 1 Then &apos; Windows
+ &apos; Template directory of Office 97
+ sTemplateKeyName = &quot;Software\Microsoft\Office\8.0\Common\FileNew\LocalTemplates&quot;
+ sTemplateValueName = &quot;&quot;
+ sLocTemplatePath = QueryValue(HKEY_LOCAL_MACHINE, sTemplateKeyName, sTemplateValueName)
+
+ If sLocTemplatePath = &quot;&quot; Then
+ &apos; Retrieve the template directory of Office 2000
+ &apos; Unfortunately there is no existing note about the template directory in
+ &apos; the whole registry.
+
+ &apos; Programdirectory of Office 2000
+ sTemplateKeyName = &quot;Software\Microsoft\Office\9.0\Common\InstallRoot&quot;
+ sTemplateValueName = &quot;Path&quot;
+ sLocProgrampath = QueryValue(HKEY_LOCAL_MACHINE, sTemplateKeyName, sTemplateValueName)
+ If sLocProgrampath &lt;&gt; &quot;&quot; Then
+ If Right(sLocProgrampath, 1) &lt;&gt; &quot;\&quot; Then
+ sLocProgrampath = sLocProgrampath &amp; &quot;\&quot;
+ End If
+ PathList() = ArrayoutofString(sLocProgrampath,&quot;\&quot;,Maxindex)
+ Progstring = &quot;\&quot; &amp; PathList(Maxindex-1) &amp; &quot;\&quot;
+ OldsLocTemplatePath = DeleteStr(sLocProgramPath,Progstring)
+
+ sLocTemplatePath = OldsLocTemplatePath &amp; &quot;\&quot; &amp; &quot;Templates&quot;
+
+ &apos; Does this subdirectory &quot;templates&quot; exist at all
+ If oUcb.Exists(sLocTemplatePath) Then
+ &apos; If Not the main directory of the office is the base
+ sLocTemplatePath = OldsLocTemplatePath
+ End If
+ Else
+ sLocTemplatePath = SOWorkPath
+ End If
+ End If
+ GetTemplateDefaultPath = ConvertToUrl(sLocTemplatePath)
+ Else
+ GetTemplateDefaultPath = SOWorkPath
+ End If
+ End Select
+NOVALIDSYSTEMPATH:
+ If Err &lt;&gt; 0 Then
+ GetTemplateDefaultPath() = SOWorkPath
+ Resume ONITGOES
+ ONITGOES:
+ End If
+End Function
+
+
+Function QueryValueEx(ByVal lhKey, ByVal szValueName As String, vValue As String) As Long
+Dim cch As Long
+Dim lrc As Long
+Dim lType As Long
+Dim lValue As Long
+Dim sValue As String
+Dim Empty
+
+ On Error GoTo QueryValueExError
+
+ lrc = RegQueryValueExNULL(lhKey, szValueName, 0&amp;, lType, 0&amp;, cch)
+ If lrc &lt;&gt; ERROR_NONE Then Error 5
+ Select Case lType
+ Case REG_SZ:
+ sValue = String(cch, 0)
+ lrc = RegQueryValueExString(lhKey, szValueName, 0&amp;, lType, sValue, cch)
+ If lrc = ERROR_NONE Then
+ vValue = Left$(sValue, cch)
+ Else
+ vValue = Empty
+ End If
+ Case REG_DWORD:
+ lrc = RegQueryValueExLong(lhKey, szValueName, 0&amp;, lType, lValue, cch)
+ If lrc = ERROR_NONE Then
+ vValue = lValue
+ End If
+ Case Else
+ lrc = -1
+ End Select
+QueryValueExExit:
+ QueryValueEx = lrc
+ Exit Function
+QueryValueExError:
+ Resume QueryValueExExit
+End Function
+
+
+Function QueryValue(BaseKey As Long, sKeyName As String, sValueName As String) As Variant
+Dim lRetVal As Long &apos; Returnvalue API-Call
+Dim hKey As Long &apos; One key handle
+Dim vValue As String &apos; Key value
+
+ lRetVal = RegOpenKeyEx(BaseKey, sKeyName, 0, KEY_ALL_ACCESS, hKey)
+ lRetVal = QueryValueEx(hKey, sValueName, vValue)
+ RegCloseKeyA (hKey)
+ QueryValue = vValue
+End Function
+</script:module>
diff --git a/wizards/source/importwizard/DialogModul.xba b/wizards/source/importwizard/DialogModul.xba
new file mode 100644
index 000000000..0bf782c6b
--- /dev/null
+++ b/wizards/source/importwizard/DialogModul.xba
@@ -0,0 +1,484 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="DialogModul" script:language="StarBasic">Option Explicit
+
+Public Const bDebugWizard = True
+
+Public Const SBFIRSTAPPLCHECKED = 0
+Public Const SBSECONDAPPLCHECKED = 1
+Public Const SBTHIRDAPPLCHECKED = 2
+Public Const SBFOURTHAPPLCHECKED = 3
+Public WizardMode as String
+Public Const SBMICROSOFTMODE = &quot;MS&quot;
+&apos; The absolute maximal Number of possible Applications
+Public Const SBMAXAPPLCOUNT = 4
+Public Const Twip = 425
+Public MaxApplCount as Integer
+Public CurOffice As Integer
+Public SOBitmapPath As String
+Public SOWorkPath As String
+Public SOTemplatePath as String
+Public bCancelTask As Boolean
+Public bDoKeepApplValues as Boolean
+Public oUcb as Object
+Public PathSeparator as String
+
+Public ApplCount as Integer
+Public sKeyName(SBMAXAPPLCOUNT-1) as String
+Public sValueName(SBMAXAPPLCOUNT-1) as String
+Public sCRLF as String
+Public MSFilterName(5,4) as String
+
+Public Applications(SBMAXAPPLCOUNT-1,9)
+
+Public Const SBAPPLCONVERT = 0
+Public Const SBDOCCONVERT = 1
+Public Const SBDOCRECURSIVE = 2
+Public Const SBDOCSOURCE = 3
+Public Const SBDOCTARGET = 4
+Public Const SBTEMPLCONVERT = 5
+Public Const SBTEMPLRECURSIVE = 6
+Public Const SBTEMPLSOURCE = 7
+Public Const SBTEMPLTARGET = 8
+Public Const SBAPPLKEY = 9
+Public XMLTemplateList()
+
+&apos; Application-relating Data are stored in this Array
+&apos; according to the following structure:
+&apos; Applications(X,0) = True/False (Application is to be converted)
+&apos; Applications(X,1) = True/False (Documents are to be converted)
+&apos; Applications(X,2) = True/False (Including Subdirectories)
+&apos; Applications(X,3) = &quot;File:///...&quot; (SourceUrl of the documents)
+&apos; Applications(X,4) = &quot;File///:...&quot; (TargetUrl of the documents)
+&apos; Applications(X,5) = True/False (Templates are to be converted)
+&apos; Applications(X,6) = True/False (Including Subdirectories)
+&apos; Applications(X,7) = &quot;File:///...&quot; (SourceUrl of the templates)
+&apos; Applications(X,8) = &quot;File:///...&quot; (TargetUrl of the templates)
+&apos; Applications(X,9) = 0 (Key to the original Index of the Applications)
+
+
+Sub FillStep_Welcome()
+Dim i as Integer
+&apos; bDoKeepApplValues = False
+ ImportDialogArea.Title = sTitle
+ With ImportDialog
+ .cmdHelp.Label = sHelpButton
+ .cmdCancel.Label = sCancelButton
+ .cmdBack.Label = sBackButton
+ .cmdGoOn.Label = sNextButton
+ .WelcomeTextLabel.Label = sWelcomeTextLabel1
+ .WelcomeTextLabel3.Label = sWelcomeTextLabel3
+
+ .optMSDocuments.Label = sContainerName(0)
+ .chkMSApplication1.Label = sMsDocumentCheckbox(0)
+ .chkMSApplication2.Label = sMsDocumentCheckbox(1)
+ .chkMSApplication3.Label = sMsDocumentCheckbox(2)
+
+ .cmdBack.Enabled = False
+ .Step = 1
+
+ If Not oFactoryKey.hasbyName(&quot;com.sun.star.text.TextDocument&quot;) Then
+ .chkLogfile.State = 0
+ .chkLogfile.Enabled = False
+ End If
+ End With
+ CheckModuleInstallation()
+ ToggleNextButton()
+End Sub
+
+
+Sub FillStep_InputPaths(OfficeIndex as Integer, bStartup as Boolean)
+Dim Index as Integer
+Dim oNullObject as Object
+ If bStartup And Not bDoKeepApplValues Then
+ If ImportDialog.optMSDocuments.State = 1 Then
+ SetupMSConfiguration()
+ Else
+ &apos;Not supposed to happen - is there an assert in BASIC...
+ End If
+ FillUpApplicationList()
+ End If
+ CurOffice = OfficeIndex
+ Index = Applications(CurOffice,SBAPPLKEY)
+ InitializePathsforCurrentApplication(Index)
+ With ImportDialog
+ .chkTemplatePath.Label = sTemplateCheckbox(Index)
+ .chkDocumentPath.State = Abs(Applications(CurOffice,SBDOCCONVERT))
+ .chkDocumentSearchSubDir.State = Abs(Applications(CurOffice,SBDOCRECURSIVE))
+ .txtDocumentImportPath.Text = ConvertFromUrl(Applications(CurOffice,SBDOCSOURCE))
+ .txtDocumentExportPath.Text = ConvertFromUrl(Applications(CurOffice,SBDOCTARGET))
+ .hlnDocuments.Label = sProgressMoreDocs
+ If WizardMode = SBMICROSOFTMODE Then
+ ImportDialogArea.Title = sTitle &amp; &quot; - &quot; &amp; sMSDocumentCheckBox(Index)
+ End If
+ .chkTemplatePath.Enabled = True
+ .chkDocumentPath.Enabled = True
+ .chkTemplatePath.Label = sTemplateCheckbox(Index)
+ .chkDocumentPath.Label = sDocumentCheckbox(Index)
+ .hlnTemplates.Label = sProgressMoreTemplates
+ .chkTemplatePath.State = Abs(Applications(CurOffice,SBTEMPLCONVERT))
+ ToggleInputPaths(oNullObject,&quot;Template&quot;)
+ ToggleInputPaths(oNullObject,&quot;Document&quot;)
+ .chkTemplateSearchSubDir.State = Abs(Applications(CurOffice,SBTEMPLRECURSIVE))
+ .txtTemplateImportPath.Text = ConvertFromUrl(Applications(CurOffice,SBTEMPLSOURCE))
+ .txtTemplateExportPath.Text = ConvertFromUrl(Applications(CurOffice,SBTEMPLTARGET))
+ .cmdGoOn.Label = sNextButton
+ .cmdBack.Enabled = True
+ ImportDialog.Step = 2
+ End With
+ ImportDialogArea.GetControl(&quot;chkTemplatePath&quot;).SetFocus()
+ ToggleNextButton()
+End Sub
+
+
+Sub FillUpApplicationList()
+Dim i as Integer
+Dim a as Integer
+Dim BoolValue as Boolean
+ If Not bDoKeepApplValues Then
+ a = 0
+ For i = 1 To ApplCount
+ If ImportDialog.optMSDocuments.State = 1 Then
+ BoolValue = ImportDialogArea.GetControl(&quot;chkMSApplication&quot; &amp; i).Model.State = 1
+ End If
+ Applications(a,SBAPPLCONVERT) = BoolValue
+ Applications(a,SBDOCCONVERT) = BoolValue
+ Applications(a,SBDOCRECURSIVE) = BoolValue
+ Applications(a,SBDOCSOURCE) = &quot;&quot; &apos; GetDefaultPath(i)
+ Applications(a,SBDOCTARGET) = &quot;&quot; &apos; SOWorkPath
+ Applications(a,SBTEMPLCONVERT) = BoolValue
+ Applications(a,SBTEMPLRECURSIVE) = BoolValue
+ Applications(a,SBTEMPLSOURCE) = &quot;&quot; &apos; GetTemplateDefaultPath(i)
+ Applications(a,SBTEMPLTARGET) = &quot;&quot; &apos; GetTargetTemplatePath(i)
+ Applications(a,SBAPPLKEY) = i-1
+ If BoolValue Then
+ a = a + 1
+ End If
+ Next i
+ ApplCount = a
+ End If
+End Sub
+
+
+Sub InitializePathsforCurrentApplication(i as Integer)
+ AssignPathToCurrentApplication(SBDOCSOURCE, GetDefaultPath(i))
+ AssignPathToCurrentApplication(SBDOCTARGET, SOWorkPath)
+ AssignPathToCurrentApplication(SBTEMPLSOURCE, GetTemplateDefaultPath(i))
+ AssignPathToCurrentApplication(SBTEMPLTARGET, GetTargetTemplatePath(i))
+End Sub
+
+
+Sub AssignPathToCurrentApplication(Index as Integer, NewPath as String)
+ If Applications(CurOffice,Index) = &quot;&quot; Then
+ If CurOffice &gt; 0 Then
+ Applications(CurOffice,Index) = Applications(CurOffice-1,Index)
+ Else
+ Applications(CurOffice,Index) = NewPath
+ End If
+ End If
+End Sub
+
+
+Sub SaveStep_InputPath()
+ Applications(CurOffice,SBDOCCONVERT) = ImportDialog.chkDocumentPath.State = 1
+ Applications(CurOffice,SBDOCRECURSIVE) = ImportDialog.chkDocumentSearchSubDir.State = 1
+ Applications(CurOffice,SBDOCSOURCE) = ConvertToURL(ImportDialog.txtDocumentImportPath.Text)
+ Applications(CurOffice,SBDOCTARGET) = ConvertToUrl(ImportDialog.txtDocumentExportPath.Text)
+ Applications(CurOffice,SBTEMPLCONVERT) = ImportDialog.chkTemplatePath.State = 1
+ Applications(CurOffice,SBTEMPLRECURSIVE) = ImportDialog.chkTemplateSearchSubDir.State = 1
+ Applications(CurOffice,SBTEMPLSOURCE) = ConvertToURL(ImportDialog.txtTemplateImportPath.Text)
+ Applications(CurOffice,SBTEMPLTARGET) = ConvertToURL(ImportDialog.txtTemplateExportPath.Text)
+End Sub
+
+
+Sub ToggleInputPaths(aEvent as Object, Optional sDocType)
+Dim bDoEnable as Boolean
+Dim sLocDocType as String
+Dim oCheckBox as Object
+ If Not IsNull(aEvent) Then
+ sLocDocType = aEvent.Source.Model.Tag
+ Else
+ sLocDocType = sDocType
+ End If
+ With ImportDialogArea
+ oCheckBox = .GetControl(&quot;chk&quot; &amp; sLocDocType &amp; &quot;Path&quot;).Model
+ bDoEnable = oCheckBox.State = 1 And oCheckBox.Enabled
+ .GetControl(&quot;lbl&quot; &amp; sLocDocType &amp; &quot;Import&quot;).Model.Enabled = bDoEnable
+ .GetControl(&quot;lbl&quot; &amp; sLocDocType &amp; &quot;Export&quot;).Model.Enabled = bDoEnable
+ .GetControl(&quot;txt&quot; &amp; sLocDocType &amp; &quot;ImportPath&quot;).Model.Enabled = bDoEnable
+ .GetControl(&quot;txt&quot; &amp; sLocDocType &amp; &quot;ExportPath&quot;).Model.Enabled = bDoEnable
+ .GetControl(&quot;chk&quot; &amp; sLocDocType &amp; &quot;SearchSubDir&quot;).Model.Enabled = bDoEnable
+ .GetControl(&quot;cmd&quot; &amp; sLocDocType &amp; &quot;Import&quot;).Model.Enabled = bDoEnable
+ .GetControl(&quot;cmd&quot; &amp; sLocDocType &amp; &quot;Export&quot;).Model.Enabled = bDoEnable
+ End With
+ ToggleNextButton()
+End Sub
+
+
+Function MakeSummaryString()
+Dim sTmpText As String
+Dim i as Integer
+Dim Index as Integer
+Dim sAddText as String
+ For i = 0 To ApplCount -1
+ Index = Applications(i,SBAPPLKEY)
+ If Applications(i,SBTEMPLCONVERT) Then
+ &apos; Templates are to be converted
+ sAddText = &quot;&quot;
+ If WizardMode = SBMICROSOFTMODE Then
+ sAddText = sSumMSTemplates(Index) &amp; sCRLF
+ End If
+ sTmpText = sTmpText &amp; sAddText &amp; ConvertFromUrl(Applications(i,SBTEMPLSOURCE)) &amp; sCRLF
+ If Applications(i,SBTEMPLRECURSIVE) Then
+ &apos; Including Subdirectories
+ sTmpText = sTmpText &amp; sSumInclusiveSubDir &amp; sCRLF
+ End If
+ sTmpText = sTmpText &amp; sSumSaveDocuments &amp; sCRLF
+ sTmpText = sTmpText &amp; ConvertFromUrl(Applications(i,SBTEMPLTARGET)) &amp; sCRLF
+ sTmpText = sTmpText &amp; sCRLF
+ End If
+
+ If Applications(i,SBDOCCONVERT) Then
+ &apos; Documents are to be converted
+ If WizardMode = SBMICROSOFTMODE Then
+ sAddText = sSumMSDocuments(Index) &amp; sCRLF
+ End If
+ sTmpText = sTmpText &amp; sAddText &amp; ConvertFromUrl(Applications(i,SBDOCSOURCE)) &amp; sCRLF
+
+ If Applications(i,SBDOCRECURSIVE) Then
+ &apos; Including Subdirectories
+ sTmpText = sTmpText &amp; sSumInclusiveSubDir &amp; sCRLF
+ End If
+
+ sTmpText = sTmpText &amp; sSumSaveDocuments &amp; sCRLF
+ sTmpText = sTmpText &amp; ConvertFromUrl(Applications(i,SBDOCTARGET)) &amp; sCRLF
+ sTmpText = sTmpText &amp; sCRLF
+ End If
+ Next i
+ MakeSummaryString = sTmpText
+End Function
+
+
+Sub FillStep_Summary()
+ ImportDialogArea.Title = sTitle
+ With ImportDialog
+ .SummaryTextbox.Text = MakeSummaryString()
+ .cmdGoOn.Enabled = .SummaryTextbox.Text &lt;&gt; &quot;&quot;
+ .cmdGoOn.Label = sBeginButton
+ .SummaryHeaderLabel.Label = sSummaryHeader
+ .Step = 3
+ End With
+ ImportDialogArea.GetControl(&quot;SummaryHeaderLabel&quot;).SetFocus()
+End Sub
+
+
+Sub FillStep_Progress()
+ With ImportDialog
+ .cmdBack.Enabled = False
+ .cmdGoOn.Enabled = False
+ .hlnProgress.Label = sProgressPage_1
+ .LabelRetrieval.FontWeight = com.sun.star.awt.FontWeight.BOLD
+ .LabelRetrieval.Label = sProgressPage_2
+ .LabelCurProgress.Label = sProgressPage_3
+ .LabelCurDocumentRetrieval.Label = &quot;&quot;
+ .LabelCurTemplateRetrieval.Label = &quot;&quot;
+ .LabelCurDocument.Label = &quot;&quot;
+ .Step = 4
+ End With
+ ImportDialogArea.GetControl(&quot;LabelRetrieval&quot;).SetFocus()
+ If ImportDialog.chkLogfile.State = 1 Then
+ ImportDialog.cmdShowLogFile.DefaultButton = True
+ End If
+End Sub
+
+
+Sub SetupMSConfiguration()
+ Wizardmode = SBMICROSOFTMODE
+ MaxApplCount = 3
+ ApplCount = 3
+ &apos; chkTemplatePath-Captions
+ sTemplateCheckBox(0) = GetResText(&quot;MSTemplateCheckbox_1_&quot;)
+ sTemplateCheckBox(1) = GetResText(&quot;MSTemplateCheckbox_2_&quot;)
+ sTemplateCheckBox(2) = GetResText(&quot;MSTemplateCheckbox_3_&quot;)
+ &apos; DocumentCheckbox- Captions
+ sDocumentCheckBox(0) = GetResText(&quot;MSDocumentCheckbox_1_&quot;)
+ sDocumentCheckBox(1) = GetResText(&quot;MSDocumentCheckbox_2_&quot;)
+ sDocumentCheckBox(2) = GetResText(&quot;MSDocumentCheckbox_3_&quot;)
+
+ sKeyName(0) = &quot;Software\Microsoft\Office\8.0\Word\Options&quot;
+ sKeyName(1) = &quot;Software\Microsoft\Office\8.0\Excel\Microsoft Excel&quot;
+ sKeyName(2) = &quot;Software\Microsoft\Office\8.0\PowerPoint\Recent Folder List\Default&quot;
+
+ sValueName(0) = &quot;DOC-PATH&quot;
+ sValueName(1) = &quot;DefaultPath&quot;
+ sValueName(2) = &quot;&quot;
+
+&apos; See definition of Filtername-Array about meaning of fields
+ MSFilterName(0,0) = &quot;doc|docx|docm&quot;
+ MSFilterName(0,1) = &quot;writer8|writer8|writer8&quot;
+ MSFilterName(0,2) = &quot;odt|odt|odt&quot;
+ MSFilterName(0,3) = sMSDocumentCheckBox(0)
+ MSFilterName(0,4) = &quot;Word&quot;
+
+
+ MSFilterName(1,0) = &quot;xls|xlsx|xlsm&quot;
+ MSFilterName(1,1) = &quot;calc8|calc8|calc8&quot;
+ MSFilterName(1,2) = &quot;ods|ods|ods&quot;
+ MSFilterName(1,3) = sMSDocumentCheckBox(1)
+ MSFilterName(1,4) = &quot;Excel&quot;
+
+ MSFilterName(2,0) = &quot;ppt|pps|pptx|pub|pptm|ppsx|ppsm&quot;
+ MSFilterName(2,1) = &quot;impress8|impress8|impress8|impress8|impress8|impress8|impress8&quot;
+ MSFilterName(2,2) = &quot;odp|odp|odp|odp|odp|odp|odp&quot;
+ MSFilterName(2,3) = sMSDocumentCheckBox(2)
+ MSFilterName(2,4) = &quot;PowerPoint/Publisher&quot;
+
+ MSFilterName(3,0) = &quot;dot|dotx|dotm&quot;
+ MSFilterName(3,1) = &quot;writer8_template|writer8_template|writer8_template&quot;
+ MSFilterName(3,2) = &quot;ott|ott|ott&quot;
+ MSFilterName(3,3) = sMSTemplateCheckBox(0)
+ MSFilterName(3,4) = &quot;Word&quot;
+
+ MSFilterName(4,0) = &quot;xlt|xltx|xltm&quot;
+ MSFilterName(4,1) = &quot;calc8_template|calc8_template|calc8_template&quot;
+ MSFilterName(4,2) = &quot;ots|ots|ots&quot;
+ MSFilterName(4,3) = sMSTemplateCheckBox(1)
+ MSFilterName(4,4) = &quot;Excel&quot;
+
+ MSFilterName(5,0) = &quot;pot|potx|potm&quot;
+ MSFilterName(5,1) = &quot;impress8_template|impress8_template|impress8_template&quot;
+ MSFilterName(5,2) = &quot;otp|otp|otp&quot;
+ MSFilterName(5,3) = sMSTemplateCheckBox(2)
+ MSFilterName(5,4) = &quot;PowerPoint&quot;
+End Sub
+
+
+Function CheckControlPath(oCheckbox as Object, oTextBox as Object, ByVal bDoEnable as Boolean)
+Dim sPath as String
+ If Not bDoEnable Then
+ CheckControlPath = False
+ ElseIf oCheckbox.State = 0 Then
+ CheckControlPath = True
+ Else
+ sPath = ConvertToUrl(Trim(oTextBox.Text))
+ CheckControlPath = oUcb.Exists(sPath)
+ End If
+End Function
+
+
+Function CheckInputPaths() as Boolean
+Dim bChangePage as Boolean
+ bChangePage = CheckTextBoxPath(ImportDialog.txtTemplateImportPath, True, False, sTitle, False)
+ bChangePage = CheckTextBoxPath(ImportDialog.txtTemplateExportPath, bChangePage, True, sTitle, False)
+ bChangePage = CheckTextBoxPath(ImportDialog.txtDocumentImportPath, bChangePage, False, sTitle, False)
+ bChangePage = CheckTextBoxPath(ImportDialog.txtDocumentExportPath, bChangePage, True, sTitle, False)
+ CheckInputPaths = bChangePage
+End Function
+
+
+Function CheckTextBoxPath(oTextBox as Object, ByVal bCheck as Boolean, bCreateNew as Boolean, sTitle as String, bgetResources as Boolean) as Boolean
+Dim iCreate as Integer
+Dim sQueryMessage as String
+Dim sUrlPath as String
+Dim sMessageNoDir as String
+Dim sShowPath as String
+Dim oLocUcb as Object
+ oLocUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ If bGetResources Then
+ If InitResources(&quot;ImportWizard&quot;) then
+ sNoDirCreation = GetResText(&quot;NoDirCreation&quot;)
+ sMsgDirNotThere = GetResText(&quot;MsgDirNotThere&quot;)
+ sQueryForNewCreation = GetResText(&quot;QueryfornewCreation&quot;)
+ Else
+ CheckTextBoxPath() = False
+ Exit Function
+ End If
+ End If
+ If oTextBox.Enabled Then
+ If bCheck Then
+ sShowPath = oTextBox.Text
+ sUrlPath = ConvertToUrl(sShowPath)
+ If Not oLocUcb.Exists(sUrlPath) Then
+ If Not bCreateNew Then
+ &apos; Sourcedirectories must be existing, Targetdirectories may be created new
+ sQueryMessage = ReplaceString(sMsgDirNotThere, sShowPath,&quot;%1&quot;)
+ Msgbox(sQueryMessage,16,sTitle)
+ CheckTextBoxPath() = False
+ Exit Function
+ Else
+ sQueryMessage = ReplaceString(sMsgDirNotThere, sShowPath,&quot;%1&quot;)
+ sQueryMessage = sQueryMessage &amp; Chr(13) &amp; sQueryForNewCreation
+ iCreate = Msgbox (sQueryMessage, 36, sTitle)
+ If iCreate = 6 Then
+ On Local Error Goto NOVALIDPATH
+ CreateFolder(sUrlPath)
+ If Not oLocUcb.Exists(sUrlPath) Then
+ Goto NOVALIDPATH
+ End If
+ Else
+ CheckTextBoxPath() = False
+ Exit Function
+ End If
+ End If
+ End If
+ CheckTextBoxPath() = True
+ Else
+ CheckTextBoxPath() = False
+ End If
+ Else
+ CheckTextBoxPath() = True
+ End If
+ Exit Function
+NOVALIDPATH:
+ sMessageNoDir = ReplaceString(sNoDirCreation, sShowPath, &quot;%1&quot;)
+ Msgbox(sMessageNoDir, 16, sTitle)
+ CheckTextBoxPath() = False
+End Function
+
+
+Sub InitializeProgressPage(oDialog as Object)
+ oDialog.LabelRetrieval.FontWeight = com.sun.star.awt.FontWeight.NORMAL
+ oDialog.LabelCurProgress.FontWeight = com.sun.star.awt.FontWeight.BOLD
+End Sub
+
+
+Sub SetProgressDisplay(AbsFound as Integer)
+ ImportDialog.LabelRetrieval.Label = sProgressPage_2 &amp; &quot; &quot; &amp; ReplaceString(sProgressPage_5, Str(AbsFound) &amp; &quot; &quot;, &quot;%1&quot;)
+ ImportDialog.LabelCurDocumentRetrieval.Label = sProgressFound &amp; &quot; &quot; &amp; CStr(AbsDocuFound) &amp; &quot; &quot; &amp; sProgressMoreDocs
+ ImportDialog.LabelCurTemplateRetrieval.Label = sProgressFound &amp; &quot; &quot; &amp; CStr(AbsTemplateFound) &amp; &quot; &quot; &amp; sProgressMoreTemplates
+End Sub
+
+Sub TakoverFolderName(aEvent as Object)
+Dim RefControlName as String
+Dim oRefControl
+ RefControlName = aEvent.Source.Model.Tag
+ oRefControl = ImportDialogArea.GetControl(RefControlName)
+ GetFolderName(oRefControl.Model)
+ ToggleNextButton()
+End Sub
+
+
+Sub FinalizeDialogButtons()
+ ImportDialog.cmdShowLogFile.Enabled = ((Isnull(oLogDocument) = False) And (ImportDialog.chkLogfile.State = 1))
+ ImportDialog.cmdCancel.Enabled = False
+ ImportDialog.cmdGoOn.Label = sCloseButton
+ ImportDialog.cmdGoOn.Enabled = True
+End Sub
+</script:module>
diff --git a/wizards/source/importwizard/FilesModul.xba b/wizards/source/importwizard/FilesModul.xba
new file mode 100644
index 000000000..cfac77dfe
--- /dev/null
+++ b/wizards/source/importwizard/FilesModul.xba
@@ -0,0 +1,783 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="FilesModul" script:language="StarBasic">Option Explicit
+
+Public AbsTemplateFound as Integer
+Public AbsDocuFound as Integer
+Public oLogDocument as Object
+Public oLogTable as Object
+Public bLogExists as Boolean
+Public sComment as String
+Public MaxCollectIndex as Integer
+Public bInsertRow as Boolean
+Public sLogUrl as String
+Public sCurPassWord as String
+Public FileCount as Integer
+Public XMLTemplateCount as Integer
+Public PathCollection(7,3) as String
+Public bIsFirstLogTable as Boolean
+
+
+Function ReadCollectionPaths(FilesList() as String, sFilterName() as String)
+Dim FilterIndex as Integer
+Dim bRecursive as Boolean
+Dim SearchDir as String
+Dim i as Integer
+Dim n as Integer
+Dim a as Integer
+Dim s as Integer
+Dim t as Integer
+Dim sFileContent() as String
+Dim NewList(0,1) as String
+Dim Index as Integer
+Dim CurFileName as String
+Dim CurExtension as String
+Dim CurFileContent as String
+Dim XMLTemplateContentList() as String
+Dim bIsTemplatePath as Boolean
+Dim MaxIndex as Integer
+Dim NewContentList() as String
+Dim XMLTemplateContentString as String
+Dim ApplIndex as Integer
+Dim bAssignFileName as Boolean
+Dim bInterruptSearch as Boolean
+ bInterruptSearch = False
+ For i = 0 To MaxCollectIndex
+ SearchDir = PathCollection(i,0)
+ bRecursive = PathCollection(i,1)
+ sFileContent() = ArrayoutofString(PathCollection(i,2), &quot;|&quot;)
+ NewList() = ReadDirectories(SearchDir, bRecursive, False, False, sFileContent(), &quot;&quot;)
+ If InterruptProcess Then
+ ReadCollectionPaths() = False
+ Exit Function
+ End If
+ If Ubound(NewList()) &gt; -1 Then
+ bIsTemplatePath = FieldInList(&quot;vor&quot;, sFileContent)
+ If bIsTemplatePath Then
+ XMLTemplateContentString = PathCollection(i,3)
+ XMLTemplateContentList() = ArrayoutofString(XMLTemplateContentString, &quot;|&quot;)
+ If Ubound(XMLTemplateContentList()) &gt; -1 Then
+ MaxIndex = Ubound(NewList())
+ ReDim Preserve NewList(MaxIndex, 1) as String
+ ReDim Preserve NewContentList(MaxIndex) as String
+ a = -1
+ For n = 0 To MaxIndex
+ bAssignFileName = True
+ If InterruptProcess() Then
+ ReadCollectionPaths() = False
+ Exit Function
+ End If
+ CurFileContent = &quot;&quot;
+ CurFileName = NewList(n,0)
+ If (FieldInList(NewList(n,1), XMLTemplateList())) Then
+ CurFileContent = GetRealFileContent(CurFileName)
+ t = SearchArrayforPartString(CurFileContent, XMLTemplateContentList())
+ bAssignFileName = (t &gt; -1)
+ If bAssignFileName Then
+ CurFileContent = XMLTemplateContentList(t)
+ End If
+ NewList(n,1) = CurFileContent
+ End If
+ CurExtension = NewList(n,1)
+ If bAssignFileName Then
+ If a &lt; n Then
+ a = a + 1
+ NewList(a,0) = CurFileName
+ NewList(a,1) = CurExtension
+ If CurFileContent = &quot;&quot; Then
+ CurFileContent = CurExtension
+ End If
+ ApplIndex = GetApplicationIndex(CurFileContent, sFiltername())
+ NewContentList(a) = ApplIndex
+ End If
+ End If
+ Next n
+ If a &lt; MaxIndex And a &gt; -1 Then
+ ReDim Preserve NewList(a, 1) as String
+ End If
+ If a &gt; -1 Then
+ AddListtoFilesList(FilesList(), NewList(), NewContentList())
+ End If
+ End If
+ Else
+ MaxIndex = Ubound(NewList())
+ ReDim Preserve NewContentList(MaxIndex) as String
+ For s = 0 To MaxIndex
+ CurExtension = NewList(s,1)
+ NewContentList(s) = GetApplicationIndex(CurExtension, sFiltername())
+ Next s
+ AddListtoFilesList(FilesList(), NewList(), NewContentList())
+ End If
+ End If
+ Next i
+ ReadCollectionPaths() = Ubound(FilesList()) &gt; -1
+End Function
+
+
+Function GetApplicationIndex(CurFileContent as String, sFilterName() as String) as Integer
+Dim Index as Integer
+Dim i as Integer
+ Index = GetIndexForPartStringinMultiArray(sFilterName(), CurFileContent, 0)
+ If Index &gt;= MaxApplCount Then
+ Index = Index - MaxApplCount
+ End If
+ For i = 0 To MaxApplCount - 1
+ If Applications(i, SBAPPLKEY) = Index Then
+ GetApplicationIndex() = i
+ Exit Function
+ End If
+ Next i
+ GetApplicationIndex() = - 1
+End Function
+
+
+Function InterruptProcess() as Boolean
+ If bCancelTask Or RetValue = 0 Then
+ bConversionIsRunning = False
+ InterruptProcess() = True
+ Exit Function
+ End if
+ InterruptProcess() = False
+End Function
+
+
+Sub AddCollectionPath(ApplIndex as Integer, DocIndex as Integer, RecursiveIndex as Integer, sFiltername() as String, DistIndex as Integer)
+ MaxCollectIndex = MaxCollectIndex + 1
+ PathCollection(MaxCollectIndex, 0) = Applications(ApplIndex, DocIndex)
+ PathCollection(MaxCollectIndex, 1) = Applications(ApplIndex, RecursiveIndex)
+ AddFilterNameToPathItem(ApplIndex, MaxCollectIndex, sFiltername(), DistIndex)
+End Sub
+
+
+Function SetExtension(LocExtension) as String
+ if (Instr(LocExtension, &quot;vnd.sun.xml.impress&quot;)) &gt; 0 then
+ SetExtension() = &quot;vor|sti|std&quot;
+ elseif (Instr(LocExtension, &quot;vnd.sun.xml.writer&quot;)) &gt; 0 then
+ SetExtension() = &quot;vor|stw&quot;
+ elseif (Instr(LocExtension, &quot;vnd.sun.xml.calc&quot;)) &gt; 0 then
+ SetExtension() = &quot;vor|stc&quot;
+ elseif (Instr(LocExtension, &quot;vnd.sun.xml.draw&quot;)) &gt; 0 then
+ SetExtension() = &quot;vor|std|sti&quot;
+ endif
+End Function
+
+Sub AddFilterNameToPathItem(ApplIndex as Integer, CollectIndex as Integer, sFiltername() as String, DistIndex as Integer)
+Dim iKey as Integer
+Dim CurListString as String
+Dim LocExtension as String
+Dim LocContentString as String
+Dim LocXMLTemplateContent as String
+ iKey = Applications(ApplIndex, SBAPPLKEY)
+ CurListString = PathCollection(CollectIndex, 2)
+ LocExtension = sFilterName(iKey +DistIndex, 0)
+ If Instr(LocExtension, &quot;vnd.sun.xml.&quot;) = 1 Then
+ LocExtension = SetExtension(LocExtension)
+ LocContentString = sFilterName(iKey +DistIndex, 0)
+ LocContentString = ReplaceString(LocContentString, &quot;|&quot;, &quot;;&quot;)
+ LocXMLTemplateContent = PathCollection(CollectIndex, 3)
+ If LocXMLTemplateContent = &quot;&quot; Then
+ LocXMLTemplateContent = LocContentString
+ Else
+ LocXMLTemplateContent = LocXMLTemplateContent &amp; &quot;|&quot; &amp; LocContentString
+ End If
+ PathCollection(CollectIndex, 3) = LocXMLTemplateContent
+ End If
+ If CurListString = &quot;&quot; Then
+ PathCollection(CollectIndex, 2) = LocExtension
+ Else
+ If Instr(CurListString, LocExtension) = 0 Then
+ PathCollection(CollectIndex, 2) = CurListString &amp; &quot;|&quot; &amp; LocExtension
+ End If
+ End If
+End Sub
+
+
+Sub CheckIfToAddPathToCollection(ApplIndex as Integer, bDoConvertIndex as Integer, DocIndex as Integer, RecursiveIndex as Integer, sFiltername() as String, DistIndex as Integer)
+Dim CollectIndex as Integer
+Dim bCheckDocuType as Boolean
+ bCheckDocuType = Applications(ApplIndex, bDoConvertIndex)
+ If bCheckDocuType Then
+ CollectIndex = GetIndexInMultiArray(PathCollection(), Applications(ApplIndex,DocIndex), 0)
+ If (CollectIndex &gt;-1) Then
+ If Applications(ApplIndex, RecursiveIndex) &lt;&gt; PathCollection(CollectIndex, 1) Then
+ AddCollectionPath(ApplIndex, DocIndex, RecursiveIndex, sFilterName(), DistIndex)
+ Else
+ AddFilterNameToPathItem(ApplIndex, CollectIndex, sFilterName(), DistIndex)
+ End If
+ Else
+ AddCollectionPath(ApplIndex, DocIndex, RecursiveIndex, sFilterName(), DistIndex)
+ End If
+ End If
+End Sub
+
+
+Sub CollectPaths(sFiltername() as String)
+Dim i as Integer
+Dim XMLTemplateContentString as String
+ MaxCollectIndex = -1
+ For i = 0 To ApplCount-1
+ CheckIfToAddPathToCollection(i, SBDOCCONVERT, SBDOCSOURCE, SBDOCRECURSIVE, sFilterName(), 0)
+ Next i
+ XMLTemplateCount = 0
+ XMLTemplateContentString = &quot;&quot;
+ For i = 0 To ApplCount-1
+ CheckIfToAddPathToCollection(i, SBTEMPLCONVERT, SBTEMPLSOURCE, SBTEMPLRECURSIVE, sFilterName(), MaxApplCount)
+ Next i
+End Sub
+
+
+Sub ConvertAllDocuments(sFilterName() as String)
+Dim FileProperties(1) as new com.sun.star.beans.PropertyValue
+Dim PWFileProperties(2) as New com.sun.star.beans.PropertyValue
+Dim WriterWebProperties(0) as new com.sun.star.beans.PropertyValue
+Dim OpenProperties(4) as new com.sun.star.beans.PropertyValue
+Dim oInteractionHandler as Object
+Dim InteractionTypes(0) as Long
+Dim FilesList(0,2) as String
+Dim sViewPath as String
+Dim i as Integer
+Dim FilterIndex as Integer
+Dim sSourceUrl as String
+Dim CurFilename as String
+Dim oDocument as Object
+Dim sExtension as String
+Dim OldExtension as String
+Dim CurFound as Integer
+Dim TotFound as Integer
+Dim TargetStemDir as String
+Dim SourceStemDir as String
+Dim TargetDir as String
+Dim sTargetUrl as String
+Dim CurFilterName as String
+Dim ApplIndex as Integer
+Dim Index as Integer
+Dim bIsDocument as Boolean
+Dim bDoSave as Boolean
+Dim sCurFileExists as String
+Dim MaxFileIndex as Integer
+Dim bContainsBasicMacro as Boolean
+Dim bIsPassWordProtected as Boolean
+Dim iOverwrite as Integer
+Dim sMimeTypeorExtension as String
+Dim sPrevMimeTypeorExtension as String
+ bConversionisrunning = True
+ InteractionTypes(0) = com.sun.star.task.PasswordRequestMode.PASSWORD_REENTER
+ oInteractionHandler = createUnoService(&quot;com.sun.star.task.InteractionHandler&quot;)
+ oInteractionHandler.initialize(InteractionTypes())
+ iGeneralOverwrite = SBOVERWRITEUNDEFINED
+ bConversionIsRunning = True
+ bLogExists = false
+ AbsTemplateFound = 0
+ AbsDocuFound = 0
+ CollectPaths(sFiltername())
+ If Not ReadCollectionPaths(FilesList(), sFilterName()) Then
+ TotFound = 0
+ SetProgressDisplay(0)
+ bConversionisrunning = false
+ FinalizeDialogButtons()
+ Exit Sub
+ End If
+ TotFound = Ubound(FilesList()) + 1
+ If FilesList(0,0) = &quot;&quot; Then &apos; Querying the number of fields in a multidimensional Array is unsecure
+ TotFound = 0 &apos; because it will return the value 0 (and not -1) even when the Array is empty
+ SetProgressDisplay(0)
+ End If
+ BubbleSortList(FilesList(), true)
+ If TotFound &gt; 0 Then
+ CreateLogDocument(OpenProperties())
+ InitializeProgressPage(ImportDialog)
+ OpenProperties(0).Name = &quot;Hidden&quot;
+ OpenProperties(0).Value = True
+ OpenProperties(1).Name = &quot;AsTemplate&quot;
+ OpenProperties(1).Value = False
+ OpenProperties(2).Name = &quot;MacroExecutionMode&quot;
+ OpenProperties(2).Value = com.sun.star.document.MacroExecMode.NEVER_EXECUTE
+ OpenProperties(3).Name = &quot;UpdateDocMode&quot;
+ OpenProperties(3).Value = com.sun.star.document.UpdateDocMode.NO_UPDATE
+ OpenProperties(4).Name = &quot;InteractionHandler&quot;
+ OpenProperties(4).Value = oInteractionHandler
+ MaxFileIndex = Ubound(FilesList(),1)
+ FileCount = 0
+ For i = 0 To MaxFileIndex
+ sComment = &quot;&quot;
+ If InterruptProcess() Then
+ Exit For
+ End If
+ bDoSave = True
+ sSourceUrl = FilesList(i,0)
+ sPrevMimeTypeorExtension = sMimeTypeorExtension
+ sMimeTypeorExtension = FilesList(i,1)
+ CurFiltername = GetFilterName(sMimeTypeorExtension, sFilterName(), sExtension, FilterIndex)
+ ApplIndex = FilesList(i,2)
+ If sMimeTypeorExtension &lt;&gt; sPrevMimeTypeorExtension Then
+ CreateLogTable(ApplIndex, sMimeTypeOrExtension, sFiltername())
+ End If
+ If ApplIndex &gt; Ubound(Applications) or (ApplIndex &lt; 0) Then
+ Msgbox &quot;Applicationindex out of bounds:&quot; &amp; sSourcUrl
+ End If
+ sViewPath = ConvertFromUrl(sSourceUrl) &apos; CutPathView(sSourceUrl, 70)
+ ImportDialog.LabelCurDocument.Label = Str(i+1) &amp; &quot;/&quot; &amp; MaxFileIndex + 1 &amp; &quot; (&quot; &amp; sViewPath &amp; &quot;)&quot;
+ Select Case lcase(sExtension)
+ Case &quot;odt&quot;, &quot;ods&quot;, &quot;odp&quot;, &quot;odg&quot;, &quot;odm&quot;, &quot;odf&quot;
+ SourceStemDir = RTrimStr(Applications(ApplIndex,SBDOCSOURCE), &quot;/&quot;)
+ TargetStemDir = RTrimStr(Applications(ApplIndex,SBDOCTARGET), &quot;/&quot;)
+ Case Else &apos; Templates and Helper-Applications remain
+ SourceStemDir = RTrimStr(Applications(ApplIndex,SBTEMPLSOURCE), &quot;/&quot;)
+ TargetStemDir = RTrimStr(Applications(ApplIndex,SBTEMPLTARGET), &quot;/&quot;)
+ End Select
+ sTargetUrl = ReplaceString(sSourceUrl, TargetStemDir, SourceStemDir)
+ CurFilename = GetFileNameWithoutExtension(sTargetUrl, &quot;/&quot;)
+ OldExtension = GetFileNameExtension(sTargetUrl)
+ sTargetUrl = RTrimStr(sTargetUrl, OldExtension)
+ sTargetUrl = sTargetUrl &amp; sExtension
+ TargetDir = RTrimStr(sTargetUrl, CurFilename &amp; &quot;.&quot; &amp; sExtension)
+ If (oUcb.Exists(sTargetUrl)) Then
+ If (iGeneralOverwrite &lt;&gt; SBOVERWRITEALWAYS) Then
+ If (iGeneralOverwrite = SBOVERWRITEUNDEFINED) Then
+ ShowOverwriteAllDialog(sTargetUrl, sTitle)
+ bDoSave = (iGeneralOverwrite = SBOVERWRITEQUERY) Or (iGeneralOverwrite = SBOVERWRITEALWAYS)
+ Elseif iGeneralOverwrite = SBOVERWRITENEVER Then
+ bDoSave = False
+ ElseIf ((iGeneralOverWrite = SBOVERWRITEQUERY) OR (iGeneralOverwrite = SBOVERWRITECANCEL)) Then
+ &apos; Todo: According to AS there might come a new feature that storeasUrl could possibly rise a UI dialog.
+ &apos; In this case my own UI becomes obsolete
+ sCurFileExists = ReplaceString(sFileExists, ConvertFromUrl(sTargetUrl), &quot;&lt;1&gt;&quot;)
+ sCurFileExists = ReplaceString(sCurFileExists, chr(13), &quot;&lt;CR&gt;&quot;)
+ iOverWrite = Msgbox (sCurFileExists, 32 + 3, sTitle)
+ Select Case iOverWrite
+ Case 1 &apos; OK
+ &apos; In the FileProperty-Bean this is already default
+ bDoSave = True
+ Case 2 &apos; Abort
+ CancelTask(False)
+ bDoSave = False
+ Case 7 &apos; No
+ bDoSave = False
+ End Select
+ End If
+ End If
+ End If
+ If bDoSave Then
+ If Not oUcb.Exists(TargetDir) Then
+ bDoSave = CreateFolder(TargetDir)
+ End If
+ If bDoSave Then
+ oDocument = StarDesktop.LoadComponentFromURL(sSourceUrl, &quot;_default&quot;, 0, OpenProperties())
+ If Not IsNull(oDocument) Then
+ InsertSourceUrlToLogDocument(sSourceUrl, &quot;&quot;)
+ bIsPassWordProtected = CheckPassWordProtection(oDocument)
+ CheckIfMacroExists(oDocument.BasicLibraries, sComment)
+ On Local Error Goto NOSAVING
+ If bIsPassWordProtected Then
+ PWFileProperties(0).Name = &quot;FilterName&quot;
+ PWFileProperties(0).Value = CurFilterName
+ PWFileProperties(1).Name = &quot;Overwrite&quot;
+ PWFileProperties(1).Value = True
+ PWFileProperties(2).Name = &quot;Password&quot;
+ PWFileProperties(2).Value = sCurPassWord
+ oDocument.StoreAsUrl(sTargetUrl, PWFileProperties())
+ Else
+ FileProperties(0).Name = &quot;FilterName&quot;
+ FileProperties(0).Value = CurFilterName
+ FileProperties(1).Name = &quot;Overwrite&quot;
+ FileProperties(1).Value = True
+ oDocument.StoreAsUrl(sTargetUrl,FileProperties())
+ End If
+ &apos; Todo: Make sure that an errorbox pops up when saving fails
+ NOSAVING:
+ If Err &lt;&gt; 0 Then
+ sCurcouldnotsaveDocument = ReplaceString(scouldnotsaveDocument, ConvertFromUrl(sTargetUrl), &quot;&lt;1&gt;&quot;)
+ sComment = ConcatComment(sComment, sCurCouldnotsaveDocument)
+ Resume LETSGO
+ LETSGO:
+ Else
+ FileCount = FileCount + 1
+ End If
+ oDocument.Dispose()
+ InsertTargetUrlToLogDocument(sTargetUrl, sComment)
+ Else
+ sCurcouldnotopenDocument = ReplaceString(scouldnotopenDocument, ConvertFromUrl(sSourceUrl), &quot;&lt;1&gt;&quot;)
+ sComment = ConcatComment(sComment, sCurCouldnotopenDocument)
+ InsertSourceUrlToLogDocument(sSourceUrl, sComment)
+ End If
+ End If
+ End If
+ Next i
+ End If
+ AddLogStatistics()
+ FinalizeDialogButtons()
+ bConversionIsRunning = False
+ Exit Sub
+RTError:
+ Msgbox sRTErrorDesc, 16, sRTErrorHeader
+End Sub
+
+
+
+Sub AddListtoFilesList(FirstList(), SecList(), NewContentList() as String)
+Dim sLocExtension as String
+Dim FirstStart as Integer
+Dim FirstEnd as Integer
+Dim i as Integer
+Dim s as Integer
+ If FirstList(0,0) = &quot;&quot; Then
+ FirstStart = Ubound(FirstList(),1)
+ Else
+ FirstStart = Ubound(FirstList(),1) + 1
+ End If
+ FirstEnd = FirstStart + Ubound(SecList(),1)
+ ReDim Preserve FirstList(FirstEnd,2)
+ s = 0
+ For i = FirstStart To FirstEnd
+ FirstList(i,0) = SecList(s,0)
+ FirstList(i,1) = SecList(s,1)
+ sLocExtension = lcase(FirstList(i,1))
+ Select Case sLocExtension
+ Case &quot;sdw&quot;, &quot;sdc&quot;, &quot;sda&quot;, &quot;sdd&quot;, &quot;smf&quot;, &quot;sgl&quot;, &quot;doc&quot;, &quot;docx&quot;, &quot;docm&quot;, &quot;xls&quot;, &quot;xlsx&quot;, &quot;xlsm&quot;, &quot;ppt&quot;, &quot;pps&quot;, &quot;pptx&quot;, &quot;pptm&quot;, &quot;ppsx&quot;, &quot;ppsm&quot;, &quot;pub&quot;, &quot;sxi&quot;, &quot;sxw&quot;, &quot;sxd&quot;, &quot;sxg&quot;, &quot;sxm&quot;, &quot;sxc&quot;
+ AbsDocuFound = AbsDocuFound + 1
+ Case else
+ AbsTemplateFound = AbsTemplateFound + 1
+ End Select
+ FirstList(i,2) = CStr(NewContentList(s))
+ s = s + 1
+ Next i
+ SetProgressDisplay(Ubound(FirstList()) + 1)
+End Sub
+
+
+
+Function GetTargetTemplatePath(Index as Integer)
+ Select Case WizardMode
+ Case SBMICROSOFTMODE
+ GetTargetTemplatePath() = SOTemplatePath &amp; &quot;/&quot; &amp; sTemplateGroupName
+ End Select
+End Function
+
+
+&apos; Retrieves the second value for a next to &apos;SearchString&apos; in
+&apos; a two-dimensional string-Array
+Function GetFilterName(sMimetypeorExtension as String, sFilterName(), sExtension as string, FilterIndex as Integer) as String
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim sLocFilterlist() as String
+ For i = 0 To Ubound(sFiltername(),1)
+ If Instr(1,sFilterName(i,0),sMimeTypeOrExtension) &lt;&gt; 0 Then
+ sLocFilterList() = ArrayoutofString(sFiltername(i,0),&quot;|&quot;, MaxIndex)
+ If MaxIndex = 0 Then
+ sExtension = sFiltername(i,2)
+ GetFilterName = sFilterName(i,1)
+ Else
+ Dim b as Integer
+ Dim sLocExtensionList() as String
+ b = SearchArrayForPartString(sMimetypeOrExtension, sLocFilterList())
+ sLocFilterList() = ArrayoutofString(sFiltername(i,1),&quot;|&quot;, MaxIndex)
+ GetFilterName = sLocFilterList(b)
+ sLocExtensionList() = ArrayoutofString(sFilterName(i,2), &quot;|&quot;, MaxIndex)
+ sExtension = sLocExtensionList(b)
+ End If
+ Exit For
+ End If
+ Next
+ FilterIndex = i
+End Function
+
+
+Function SearchArrayforPartString(SearchString as String, LocList()) as Integer
+Dim i as Integer
+Dim a as Integer
+Dim StringList() as String
+ For i = Lbound(LocList(),1) to Ubound(LocList(),1)
+ StringList() = ArrayoutofString(LocList(i), &quot;|&quot;)
+ For a = 0 To Ubound(StringList())
+ If (Instr(1, SearchString, StringList(a)) &lt;&gt; 0) Then
+ SearchArrayForPartString() = i
+ Exit Function
+ End If
+ Next a
+ Next i
+ SearchArrayForPartString() = -1
+End Function
+
+
+Sub CreateLogTable(ApplIndex as Integer, CurFileContent as String, sFilterName() as String)
+Dim oLogCursor as Object
+Dim oLogRows as Object
+Dim FilterIndex as Integer
+Dim sDocumentType as String
+Dim oTextCursor
+Dim oCell
+ If Not bLogExists Then
+ Exit Sub
+ End If
+ FilterIndex = GetIndexForPartStringinMultiArray(sFilterName(), CurFileContent, 0)
+ sDocumentType = sFiltername(FilterIndex,3)
+ oLogCursor = oLogDocument.Text.createTextCursor()
+ oLogCursor.GotoEnd(False)
+ If Not bIsFirstLogTable Then
+ oLogDocument.Text.insertControlCharacter(oLogCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False)
+ Else
+ bisFirstLogTable = False
+ End If
+ oLogCursor.HyperLinkURL = &quot;&quot;
+ oLogCursor.HyperLinkName = &quot;&quot;
+ oLogCursor.HyperLinkTarget = &quot;&quot;
+ oLogCursor.ParaStyleName = &quot;Heading 1&quot;
+ oLogCursor.setString(sDocumentType)
+ oLogCursor.CollapsetoEnd()
+ oLogDocument.Text.insertControlCharacter(oLogCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False)
+ oLogTable = oLogDocument.CreateInstance(&quot;com.sun.star.text.TextTable&quot;)
+ oLogTable.RepeatHeadline = true
+ oLogCursor.Text.InsertTextContent(oLogCursor, oLogTable, True)
+ oTextCursor = oLogTable.GetCellbyPosition(0,0).createTextCursor()
+ oTextCursor.SetString(sSourceDocuments)
+ oTextCursor = oLogTable.GetCellbyPosition(1,0).createTextCursor()
+ oTextCursor.SetString(sTargetDocuments)
+ bInsertRow = False
+End Sub
+
+
+Function GetSize(iWidth, iHeight) As New com.sun.star.awt.Size
+Dim aSize As New com.sun.star.awt.Size
+ aSize.Width = iWidth
+ aSize.Height = iHeight
+ GetSize() = aSize
+End Function
+
+
+Sub InsertCommandButtonatViewCursor(oLocDocument, oLocCursor, TargetUrl as String, Optional aSize)
+Dim oDocument
+Dim oController
+Dim oCommandButton
+Dim oShape
+Dim oDrawPage
+Dim oCommandControl
+Dim oEvent
+Dim oCell
+ oCommandButton = oLocDocument.createInstance(&quot;com.sun.star.form.component.CommandButton&quot;)
+ oShape = oLocDocument.CreateInstance (&quot;com.sun.star.drawing.ControlShape&quot;)
+ If IsMissing(aSize) Then
+ oShape.Size = GetSize(4000, 600)
+ End If
+ oCommandButton.Label = FileNameoutofPath(Targeturl)
+ oCommandButton.TargetFrame = &quot;_default&quot;
+ oCommandButton.ButtonType = com.sun.star.form.FormButtonType.URL
+ oCommandbutton.DispatchUrlInternal = True
+ oCommandButton.TargetURL = ConverttoUrl(TargetUrl)
+ oShape.Control = oCommandbutton
+ oLocCursor.Text.InsertTextContent(oLocCursor, oShape, True)
+End Sub
+
+
+
+Sub CreateLogDocument(HiddenProperties())
+Dim OpenProperties(0) as new com.sun.star.beans.PropertyValue
+Dim NoArgs()
+Dim i as Integer
+Dim bLogIsThere as Boolean
+ If ImportDialog.chkLogfile.State = 1 Then
+ i = 2
+ OpenProperties(0).Name = &quot;Hidden&quot;
+ OpenProperties(0).Value = True
+ oLogDocument = StarDesktop.LoadComponentFromURL(&quot;private:factory/swriter&quot;, &quot;_default&quot;, 4, OpenProperties())
+ SOWorkPath = RTrimStr(SOWorkPath,&quot;/&quot;)
+ sLogUrl = SOWorkPath &amp; &quot;/Logfile.odt&quot;
+ Do
+ bLogIsThere = oUcb.Exists(sLogUrl)
+ If bLogIsThere Then
+ If i = 2 Then
+ sLogUrl = ReplaceString(sLogUrl, &quot;/Logfile_2.odt&quot;, &quot;/Logfile.odt&quot;)
+ Else
+ sLogUrl = ReplaceString(sLogUrl, &quot;/Logfile_&quot; &amp; cStr(i) &amp; &quot;.odt&quot;, &quot;/Logfile_&quot; &amp; cStr(i-1) &amp; &quot;.odt&quot;)
+ End If
+ i = i + 1
+ End If
+ Loop Until Not bLogIsThere
+ bLogExists = True
+ oLogDocument.StoreAsUrl(sLogUrl, NoArgs())
+ End If
+End Sub
+
+
+Sub InsertTargetUrlToLogDocument(sTargetUrl as String, sComment as String)
+Dim oCell
+Dim oTextCursor
+Dim CurFilterTracingpath as String
+ If (bLogExists) And (sTargetUrl &lt;&gt; &quot;&quot;) Then
+ If sTargetUrl &lt;&gt; &quot;&quot; Then
+ oCell = oLogTable.GetCellbyPosition(1,oLogTable.Rows.Count-1)
+ InsertCommentToLogCell(sComment, oCell)
+ InsertHyperLinkToLogCell(sTargetUrl, oCell)
+ oLogDocument.Store()
+ End If
+ End If
+End Sub
+
+
+Sub InsertSourceUrlToLogDocument(SourceUrl as String, sComment) &apos;
+Dim oCell as Object
+ If bLogExists Then
+ If bInsertRow Then
+ oLogTable.Rows.InsertByIndex(oLogTable.Rows.Count,1)
+ Else
+ bInsertRow = True
+ End If
+ oCell = oLogTable.GetCellbyPosition(0,oLogTable.Rows.Count-1)
+ InsertCommentToLogCell(sComment, oCell)
+ InsertHyperLinkToLogCell(SourceUrl, oCell)
+ oLogDocument.Store()
+ End If
+End Sub
+
+
+Sub InsertHyperLinkToLogCell(sUrl as String, oCell as Object)
+Dim oLogCursor as Object
+Dim LocFileName as String
+ oLogCursor = oCell.createTextCursor()
+ oLogCursor.CollapseToStart()
+ oLogCursor.HyperLinkURL = sUrl
+ oLogCursor.HyperLinkName = sUrl
+ oLogCursor.HyperLinkTarget = sUrl
+ LocFileName = FileNameOutOfPath(sUrl)
+ oCell.InsertString(oLogCursor, LocFileName,False)
+End Sub
+
+
+Sub InsertCommentToLogCell(sComment as string, oCell as Object)
+Dim oCommentCursor as Object
+ If sComment &lt;&gt; &quot;&quot; Then
+ oCommentCursor = oCell.createTextCursor()
+ oCell.insertControlCharacter(oCommentCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False)
+ oCell.insertString(oCommentCursor, sComment, false)
+ End If
+End Sub
+
+
+Sub AddLogStatistics()
+Dim oCell as Object
+Dim oLogCursor as Object
+Dim MaxRowIndex as Integer
+ If bLogExists Then
+ MaxRowIndex = oLogTable.Rows.Count
+ sLogSummary = ReplaceString(sLogSummary, FileCount, &quot;&lt;COUNT&gt;&quot;)
+&apos; oLogTable.Rows.InsertByIndex(MaxRowIndex, 1)
+&apos; oCell = oLogTable.GetCellbyPosition(0, MaxRowIndex)
+&apos; oLogCursor = oCell.createTextCursor()
+&apos; oCell.InsertString(oLogCursor, sLogSummary,False)
+&apos; MergeRange(oLogTable, oCell, 1)
+
+ oLogCursor = oLogDocument.Text.CreateTextCursor
+ oLogCursor.gotoEnd(False)
+ oLogCursor.HyperLinkURL = &quot;&quot;
+ oLogCursor.HyperLinkName = &quot;&quot;
+ oLogCursor.HyperLinkTarget = &quot;&quot;
+ oLogCursor.SetString(sLogSummary)
+ oLogDocument.Store()
+ oLogDocument.Dispose()
+ bLogExists = False
+ End If
+End Sub
+
+
+
+Function CheckIfMacroExists(oBasicLibraries as Object, sComment as String) as Boolean
+Dim ModuleNames() as String
+Dim ModuleName as String
+Dim MaxLibIndex as Integer
+Dim MaxModuleIndex as Integer
+Dim bMacroExists as Boolean
+Dim n as Integer
+Dim m as Integer
+Dim LibName as String
+Dim sBasicCode as String
+Dim oLibrary as Object
+ bMacroExists = False
+ bMacroExists = oBasicLibraries.hasElements
+ If bMacroExists Then
+ MaxLibIndex = Ubound(oBasicLibraries.ElementNames())
+ For n = 0 To MaxLibIndex
+ LibName = oBasicLibraries.ElementNames(n)
+ If oBasicLibraries.isLibraryLoaded(LibName) Then
+ oLibrary = oBasicLibraries.getbyName(LibName)
+ If oLibrary.hasElements() Then
+ MaxModuleIndex = Ubound(oLibrary.ElementNames())
+ For m = 0 To MaxModuleIndex
+ ModuleName = oLibrary.ElementNames(m)
+ sBasicCode = oLibrary.getbyName(ModuleName)
+ If sBasicCode &lt;&gt; &quot;&quot; Then
+ ConcatComment(sComment, sReeditMacro)
+ CheckIfMacroExists() = True
+ Exit Function
+ End If
+ Next m
+ End If
+ End If
+ Next n
+ End If
+ CheckIfMacroExists() = False
+End Function
+
+
+
+Function CheckPassWordProtection(oDocument as Object)
+Dim bIsPassWordProtected as Boolean
+Dim i as Integer
+Dim oArgs()
+Dim MaxIndex as Integer
+Dim sblabla as String
+ bIsPassWordProtected = false
+ oArgs() = oDocument.getArgs()
+ MaxIndex = Ubound(oArgs())
+ For i = 0 To MaxIndex
+ sblabla = oArgs(i).Name
+ If oArgs(i).Name = &quot;Password&quot; Then
+ bIsPassWordProtected = True
+ sCurPassWord = oArgs(i).Value
+ Exit For
+ End If
+ Next i
+ CheckPassWordProtection() = bIsPassWordProtected
+End Function
+
+
+Sub OpenLogDocument()
+
+ bShowLogFile = True
+ ImportDialogArea.endexecute()
+
+End Sub
+
+
+Sub MergeRange(oTable as Object, oCell as Object, MergeCount as Integer)
+Dim oTableCursor as Object
+ oTableCursor = oTable.createCursorByCellName(oCell.CellName)
+ oTableCursor.goRight(MergeCount, True)
+ oTableCursor.mergeRange()
+End Sub
+
+
+Function ConcatComment(sComment as String, AdditionalComment as String)
+ If sComment = &quot;&quot; Then
+ sComment = AdditionalComment
+ Else
+ sComment = sComment &amp; chr(13) + AdditionalComment
+ End If
+ ConcatComment = sComment
+End Function
+</script:module>
diff --git a/wizards/source/importwizard/ImportDialog.xdl b/wizards/source/importwizard/ImportDialog.xdl
new file mode 100644
index 000000000..1f3fc71ff
--- /dev/null
+++ b/wizards/source/importwizard/ImportDialog.xdl
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="ImportDialog" dlg:left="96" dlg:top="28" dlg:width="270" dlg:height="210" dlg:page="4" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_DIALOG" dlg:closeable="true" dlg:moveable="true" dlg:title="ImportDialog">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblTemplateExport" dlg:tab-index="0" dlg:left="12" dlg:top="94" dlg:width="60" dlg:height="8" dlg:page="2" dlg:value="lblTemplateExport"/>
+ <dlg:textfield dlg:id="txtTemplateImportPath" dlg:tab-index="1" dlg:left="73" dlg:top="76" dlg:width="170" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_LBTEMPLATEPATH">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:ImportWizard.Main.ToggleNextButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:textfield>
+ <dlg:textfield dlg:id="txtTemplateExportPath" dlg:tab-index="2" dlg:left="73" dlg:top="92" dlg:width="170" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_EDTEMPLATEPATH"/>
+ <dlg:checkbox dlg:id="chkDocumentPath" dlg:tab-index="3" dlg:left="12" dlg:top="121" dlg:width="240" dlg:height="10" dlg:page="2" dlg:tag="Document" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CBDOCUMENT" dlg:value="chkDocumentPath" dlg:checked="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:ImportWizard.DialogModul.ToggleInputPaths?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:checkbox>
+ <dlg:checkbox dlg:id="chkDocumentSearchSubDir" dlg:tab-index="4" dlg:left="12" dlg:top="134" dlg:width="240" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CBDOCUMENTRECURSE" dlg:value="chkDocumentSearchSubDir" dlg:checked="false"/>
+ <dlg:text dlg:id="lblDocumentImport" dlg:tab-index="5" dlg:left="10" dlg:top="151" dlg:width="60" dlg:height="8" dlg:page="2" dlg:value="lblDocumentImport"/>
+ <dlg:text dlg:id="lblDocumentExport" dlg:tab-index="6" dlg:left="10" dlg:top="167" dlg:width="60" dlg:height="8" dlg:page="2" dlg:value="lblDocumentExport"/>
+ <dlg:textfield dlg:id="txtDocumentImportPath" dlg:tab-index="7" dlg:left="73" dlg:top="149" dlg:width="170" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_LBDOCUMENTPATH">
+ <script:event script:event-name="on-textchange" script:macro-name="vnd.sun.star.script:ImportWizard.Main.ToggleNextButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:textfield>
+ <dlg:textfield dlg:id="txtDocumentExportPath" dlg:tab-index="8" dlg:left="73" dlg:top="165" dlg:width="170" dlg:height="12" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_EDDOCUMENTPATH"/>
+ <dlg:text dlg:id="SummaryHeaderLabel" dlg:tab-index="9" dlg:left="6" dlg:top="37" dlg:width="258" dlg:height="8" dlg:page="3" dlg:value="SummaryHeaderLabel"/>
+ <dlg:textfield dlg:id="SummaryTextbox" dlg:tab-index="10" dlg:left="5" dlg:top="48" dlg:width="259" dlg:height="125" dlg:page="3" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_3_TBSUMMARY" dlg:vscroll="true" dlg:multiline="true" dlg:readonly="true"/>
+ <dlg:text dlg:id="LabelRetrieval" dlg:tab-index="11" dlg:left="10" dlg:top="67" dlg:width="255" dlg:height="8" dlg:page="4" dlg:value="LabelRetrieval"/>
+ <dlg:text dlg:id="LabelCurTemplateRetrieval" dlg:tab-index="12" dlg:left="15" dlg:top="79" dlg:width="249" dlg:height="8" dlg:page="4" dlg:value="LabelCurTemplateRetrieval"/>
+ <dlg:text dlg:id="LabelCurDocumentRetrieval" dlg:tab-index="13" dlg:left="15" dlg:top="91" dlg:width="249" dlg:height="8" dlg:page="4" dlg:value="LabelCurDocumentRetrieval"/>
+ <dlg:text dlg:id="LabelCurProgress" dlg:tab-index="14" dlg:left="10" dlg:top="106" dlg:width="255" dlg:height="8" dlg:page="4" dlg:value="LabelCurProgress"/>
+ <dlg:text dlg:id="LabelCurDocument" dlg:tab-index="15" dlg:left="15" dlg:top="118" dlg:width="249" dlg:height="20" dlg:page="4" dlg:value="LabelCurDocument" dlg:multiline="true"/>
+ <dlg:img dlg:id="ImportPreview" dlg:tab-index="16" dlg:left="6" dlg:top="6" dlg:width="258" dlg:height="26" dlg:scale-image="false"/>
+ <dlg:button dlg:id="cmdBack" dlg:tab-index="17" dlg:left="155" dlg:top="190" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_0_CMDPREV" dlg:value="cmdBack">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.Main.PrevStep?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="18" dlg:left="6" dlg:top="190" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_0_CMDCANCEL" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.Main.CancelTask?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdHelp" dlg:tab-index="19" dlg:left="65" dlg:top="190" dlg:width="50" dlg:height="14" dlg:value="cmdHelp" dlg:button-type="help"/>
+ <dlg:button dlg:id="cmdGoOn" dlg:tab-index="20" dlg:left="214" dlg:top="190" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_0_CMDNEXT" dlg:value="cmdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.Main.NextStep?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="WelcomeTextLabel" dlg:tab-index="21" dlg:left="6" dlg:top="38" dlg:width="258" dlg:height="20" dlg:page="1" dlg:value="WelcomeTextLabel" dlg:multiline="true"/>
+ <dlg:text dlg:id="WelcomeTextLabel3" dlg:tab-index="22" dlg:left="6" dlg:top="58" dlg:width="258" dlg:height="12" dlg:page="1" dlg:value="WelcomeTextLabel3"/>
+ <dlg:button dlg:id="cmdTemplateImport" dlg:tab-index="23" dlg:left="248" dlg:top="75" dlg:width="14" dlg:height="14" dlg:page="2" dlg:tag="txtTemplateImportPath" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CMDTEMPLATEPATHSELECT" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.DialogModul.TakoverFolderName?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdTemplateExport" dlg:tab-index="24" dlg:left="248" dlg:top="91" dlg:width="14" dlg:height="14" dlg:page="2" dlg:tag="txtTemplateExportPath" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CMDTEMPLATEPATHSELECT2" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.DialogModul.TakoverFolderName?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdDocumentImport" dlg:tab-index="25" dlg:left="248" dlg:top="148" dlg:width="14" dlg:height="14" dlg:page="2" dlg:tag="txtDocumentImportPath" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CMDDOCUMENTPATHSELECT" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.DialogModul.TakoverFolderName?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdDocumentExport" dlg:tab-index="26" dlg:left="248" dlg:top="164" dlg:width="14" dlg:height="14" dlg:page="2" dlg:tag="txtDocumentExportPath" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CMDDOCUMENTPATHSELECT2" dlg:value="...">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.DialogModul.TakoverFolderName?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="optMSDocuments" dlg:tab-index="27" dlg:left="6" dlg:top="72" dlg:width="258" dlg:height="9" dlg:page="1" dlg:tag="MS" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_0_OPTMSDOCUMENTS" dlg:value="optMSDocuments" dlg:checked="true">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.Main.ToggleCheckboxes?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:checkbox dlg:id="chkMSApplication1" dlg:tab-index="29" dlg:disabled="true" dlg:left="12" dlg:top="85" dlg:width="141" dlg:height="9" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CHKWORD" dlg:value="chkMSApplication1" dlg:checked="false">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:ImportWizard.Main.ToggleNextButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:checkbox>
+ <dlg:checkbox dlg:id="chkMSApplication2" dlg:tab-index="30" dlg:disabled="true" dlg:left="155" dlg:top="85" dlg:width="109" dlg:height="9" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CHKEXCEL" dlg:value="chkMSApplication2" dlg:checked="false">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:ImportWizard.Main.ToggleNextButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:checkbox>
+ <dlg:checkbox dlg:id="chkMSApplication3" dlg:tab-index="31" dlg:disabled="true" dlg:left="12" dlg:top="98" dlg:width="141" dlg:height="9" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CHKPOWERPOINT" dlg:value="chkMSApplication3" dlg:checked="false">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:ImportWizard.Main.ToggleNextButton?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:checkbox>
+ <dlg:checkbox dlg:id="chkTemplatePath" dlg:tab-index="36" dlg:left="12" dlg:top="48" dlg:width="240" dlg:height="10" dlg:page="2" dlg:tag="Template" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CBTEMPLATE" dlg:value="chkTemplatePath" dlg:checked="true">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:ImportWizard.DialogModul.ToggleInputPaths?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:checkbox>
+ <dlg:checkbox dlg:id="chkTemplateSearchSubDir" dlg:tab-index="37" dlg:left="12" dlg:top="61" dlg:width="240" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_2_CBTEMPLATERECURSE" dlg:value="chkTemplateSearchSubDir" dlg:checked="false"/>
+ <dlg:text dlg:id="lblTemplateImport" dlg:tab-index="38" dlg:left="12" dlg:top="78" dlg:width="60" dlg:height="8" dlg:page="2" dlg:value="lblTemplateImport"/>
+ <dlg:checkbox dlg:id="chkLogfile" dlg:tab-index="39" dlg:left="6" dlg:top="171" dlg:width="136" dlg:height="9" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGIMPORT_0_CHKLOGFILE" dlg:value="chkLogfile" dlg:checked="true"/>
+ <dlg:fixedline dlg:id="hlnTemplates" dlg:tab-index="40" dlg:left="6" dlg:top="37" dlg:width="258" dlg:height="8" dlg:page="2" dlg:value="hlnTemplates"/>
+ <dlg:fixedline dlg:id="hlnDocuments" dlg:tab-index="41" dlg:left="6" dlg:top="110" dlg:width="258" dlg:height="8" dlg:page="2" dlg:value="hlnDocuments"/>
+ <dlg:fixedline dlg:id="FixedLine1" dlg:tab-index="42" dlg:left="6" dlg:top="181" dlg:width="258" dlg:height="6"/>
+ <dlg:fixedline dlg:id="hlnProgress" dlg:tab-index="43" dlg:left="6" dlg:top="55" dlg:width="258" dlg:height="8" dlg:page="4" dlg:value="hlnProgress"/>
+ <dlg:button dlg:id="cmdShowLogFile" dlg:tab-index="44" dlg:disabled="true" dlg:left="75" dlg:top="142" dlg:width="120" dlg:height="14" dlg:page="4" dlg:value="cmdShowLogFile">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ImportWizard.FilesModul.OpenLogDocument?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ </dlg:bulletinboard>
+</dlg:window>
diff --git a/wizards/source/importwizard/Language.xba b/wizards/source/importwizard/Language.xba
new file mode 100644
index 000000000..bd890ed63
--- /dev/null
+++ b/wizards/source/importwizard/Language.xba
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Language" script:language="StarBasic">Option Explicit
+
+Public sMSTemplateCheckbox(2) As String
+Public sMSDocumentCheckbox(2) As String
+Public sTemplateCheckbox(SBMAXAPPLCOUNT-1) As String
+Public sDocumentCheckbox(SBMAXAPPLCOUNT-1) As String
+Public sTemplateGroupName As String
+Public sSearchInSubDir as String
+Public sPathErrorTemplates(SBMAXAPPLCOUNT-1) As String
+Public sPathErrorDocument(SBMAXAPPLCOUNT-1) As String
+Public sPathErrorStarDoc(SBMAXAPPLCOUNT-1) As String
+Public sStarDocLabel(SBMAXAPPLCOUNT-1) As String
+Public sImportLabel As String, sExportLabel As String
+Public SOApplicationName(5) As String
+Public sHelpButton As String, sCancelButton As String, sBackButton As String, sNextButton As String
+Public sSumInclusiveSubDir As String, sSumSaveDocuments As String
+Public sSummaryHeader As String
+Public sWelcometextLabel1 As String, sWelcometextLabel3 As String
+Public sBeginButton As String, sMsgDirNotThere As String
+Public sQueryForNewCreation As String, sPathError3 As String
+Public sNoDirCreation As String
+Public sProgressMoreDocs As String, sProgressMoreTemplates as String
+Public sFileExists As String, sMorePathsError3 As String
+Public sConvertError1 As String, sConvertError2 As String, sPathDialogMessage As String
+Public sRTErrorDesc As String, sRTErrorHeader As String
+Public sProgressPage_1 As String, sProgressPage_2 As String, sProgressPage_3 as String
+Public sProgressFound as String, sProgresspage_5 as String
+Public sContainerName(1) as String
+Public sReady as String, sTitle as String
+Public sCloseButton as String
+Public sSourceDocuments as String
+Public sTargetDocuments as String
+Public sSumMSDocuments(3) as String
+Public sSumMSTemplates(3) as String
+Public ModuleList(3) as String
+Public sLogSummary as String
+Public sReeditMacro as String
+Public sOverwriteallFiles as String
+Public sCouldnotopenDocument as String
+Public sCurcouldnotopenDocument as String
+Public sCouldnotsaveDocument as String
+Public sCurcouldnotsaveDocument as String
+
+
+Sub LoadLanguage()
+ If InitResources(&quot;ImportWizard&quot;) then
+ sHelpButton = GetResText(&quot;HelpButton&quot;)
+ sCancelButton = GetResText(&quot;CancelButton&quot;)
+ sBackButton = GetResText(&quot;BackButton&quot;)
+ sNextButton = GetResText(&quot;NextButton&quot;)
+ sBeginButton = GetResText(&quot;BeginButton&quot;)
+ sCloseButton = GetResText(&quot;CloseButton&quot;)
+
+ sWelcometextLabel1 = ReplaceString(GetResText(&quot;WelcometextLabel1&quot;), GetProductName(),&quot;%PRODUCTNAME&quot;)
+ sWelcometextLabel3 = GetResText(&quot;WelcometextLabel3&quot;)
+
+ &apos; Microsoft Documents
+ sMSTemplateCheckBox(0) = GetResText(&quot;MSTemplateCheckbox_1_&quot;)
+ sMSTemplateCheckBox(1) = GetResText(&quot;MSTemplateCheckbox_2_&quot;)
+ sMSTemplateCheckBox(2) = GetResText(&quot;MSTemplateCheckbox_3_&quot;)
+
+ &apos; DocumentCheckbox- Captions
+ sMSDocumentCheckBox(0) = GetResText(&quot;MSDocumentCheckbox_1_&quot;)
+ sMSDocumentCheckBox(1) = GetResText(&quot;MSDocumentCheckbox_2_&quot;)
+ sMSDocumentCheckBox(2) = GetResText(&quot;MSDocumentCheckbox_3_&quot;)
+
+ &apos;StarOffice Applicationnames
+
+ sContainerName(0) = GetResText(&quot;MSContainerName&quot;)
+
+ sSummaryHeader = GetResText(&quot;SummaryHeader&quot;)
+
+ sTemplateGroupName = GetResText(&quot;GroupnameDefault&quot;)
+
+ sProgressMoreDocs = GetResText(&quot;ProgressMoreDocs&quot;)
+ sProgressMoreTemplates = GetResText(&quot;ProgressMoreTemplates&quot;)
+ sNoDirCreation = GetResText(&quot;NoDirCreation&quot;)
+ sMsgDirNotThere = GetResText(&quot;MsgDirNotThere&quot;)
+ sQueryForNewCreation = GetResText(&quot;QueryfornewCreation&quot;)
+ sFileExists = GetResText(&quot;FileExists&quot;)
+ sMorePathsError3 = GetResText(&quot;MorePathsError3&quot;)
+ sConvertError1 = GetResText(&quot;ConvertError1&quot;)
+ sConvertError2 = GetResText(&quot;ConvertError2&quot;)
+ sRTErrorDesc = GetResText(&quot;RTErrorDesc&quot;)
+ sRTErrorHeader = GetResText(&quot;RTErrorHeader&quot;)
+ sOverwriteallFiles = GetResText(&quot;OverwriteallFiles&quot;)
+ sReeditMacro = GetResText(&quot;ReeditMacro&quot;)
+ sCouldnotsaveDocument = GetResText(&quot;CouldNotsaveDocument&quot;)
+ sCouldnotopenDocument = GetResText(&quot;CouldNotopenDocument&quot;)
+ sPathDialogMessage = GetResText(&quot;PathDialogMessage&quot;)
+ sTitle = GetResText(&quot;DialogTitle&quot;)
+
+ sProgressPage_1 = GetResText(&quot;ProgressPage1&quot;)
+ sProgressPage_2 = GetResText(&quot;ProgressPage2&quot;)
+ sProgressPage_3 = GetResText(&quot;ProgressPage3&quot;)
+ sProgressFound = GetResText(&quot;ProgressFound&quot;)
+ sProgressPage_5 = GetResText(&quot;ProgressPage5&quot;)
+ sReady = GetResText(&quot;Ready&quot;)
+ sSourceDocuments = GetResText(&quot;SourceDocuments&quot;)
+ sTargetDocuments = GetResText(&quot;TargetDocuments&quot;)
+ sLogSummary = GetResText(&quot;LogfileSummary&quot;)
+ sSumInclusiveSubDir = GetResText(&quot;SumInclusiveSubDir&quot;)
+ sSumSaveDocuments = GetResText(&quot;SumSaveDokumente&quot;)
+ sSumMSDocuments(0) = GetResText(&quot;SumMSTextDocuments&quot;)
+ sSumMSDocuments(1) = GetResText(&quot;SumMSTableDocuments&quot;)
+ sSumMSDocuments(2) = GetResText(&quot;SumMSDrawDocuments&quot;)
+ sSumMSTemplates(0) = GetResText(&quot;SumMSTextTemplates&quot;)
+ sSumMSTemplates(1) = GetResText(&quot;SumMSTableTemplates&quot;)
+ sSumMSTemplates(2) = GetResText(&quot;SumMSDrawTemplates&quot;)
+ With ImportDialog
+ sImportLabel = GetResText(&quot;TextImportLabel&quot;)
+ sExportLabel = GetResText(&quot;TextExportLabel&quot;)
+ sSearchInSubDir = GetResText(&quot;SearchInSubDir&quot;)
+ .chkTemplateSearchSubDir.Label = sSearchInSubDir
+ .lblDocumentImport.Label = sImportLabel
+ .lblDocumentExport.Label = sExportLabel
+ .chkDocumentSearchSubDir.Label = sSearchInSubDir
+ .lblTemplateImport.Label = sImportLabel
+ .lblTemplateExport.Label = sExportLabel
+ .chkLogfile.Label = GetResText(&quot;CreateLogfile&quot;)
+ .chkLogfile.Helptext = GetResText(&quot;LogfileHelpText&quot;)
+ .cmdShowLogFile.Label = GetResText(&quot;ShowLogfile&quot;)
+ End With
+ ModuleList(0) = &quot;com.sun.star.text.TextDocument&quot;
+ ModuleList(1) = &quot;com.sun.star.sheet.SpreadsheetDocument&quot;
+ ModuleList(2) = &quot;com.sun.star.drawing.DrawingDocument/com.sun.star.presentation.PresentationDocument&quot;
+ ModuleList(3) = &quot;com.sun.star.formula.FormulaProperties/com.sun.star.text.GlobalDocument&quot;
+ End If
+End Sub
+
+</script:module>
diff --git a/wizards/source/importwizard/Main.xba b/wizards/source/importwizard/Main.xba
new file mode 100644
index 000000000..b8cc8211e
--- /dev/null
+++ b/wizards/source/importwizard/Main.xba
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Main" script:language="StarBasic">Option Explicit
+REM ***** BASIC *****
+
+Public HeaderPreviews(4) as Object
+Public ImportDialog as Object
+Public ImportDialogArea as Object
+Public oFactoryKey as Object
+Public bShowLogFile as Boolean
+
+&apos; If the ProgressPage is already on Top The Dialog will be immediately closed when this flag is
+&apos; set to False
+Public bConversionIsRunning as Boolean
+Public RetValue as Integer
+
+Sub Main()
+ Dim NoArgs() as New com.sun.star.beans.PropertyValue
+ bShowLogFile=FALSE
+ If Not bDebugWizard Then
+ On Local Error Goto RTError
+ End If
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ RetValue = 10
+ bIsFirstLogTable = True
+ bConversionIsRunning = False
+ sCRLF = CHR(13) &amp; CHR(10)
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ oFactoryKey = GetRegistryKeyContent(&quot;org.openoffice.Setup/Office/Factories&quot;)
+ If GetImportWizardPaths() = False Then
+ Exit Sub
+ End If
+ bCancelTask = False
+ bDoKeepApplValues = False
+ CurOffice = 0
+ ImportDialogArea = LoadDialog(&quot;ImportWizard&quot;,&quot;ImportDialog&quot;)
+ ImportDialog = ImportDialogArea.Model
+ LoadLanguage()
+ WizardMode = SBMICROSOFTMODE
+ MaxApplCount = 3
+ FillStep_Welcome()
+ RepaintHeaderPreview()
+ ImportDialog.ImportPreview.BackGroundColor = RGB(0,60,126)
+ ImportDialog.cmdGoOn.DefaultButton = True
+ ImportDialogArea.GetControl(&quot;optMSDocuments&quot;).SetFocus()
+ ToggleCheckboxesWithBoolean(True)
+
+ RetValue = ImportDialogArea.Execute()
+ If bShowLogFile=TRUE Then
+ OpenDocument(sLogUrl, NoArgs())
+ End if
+ If RetValue = 0 Then
+ CancelTask()
+ End If
+ ImportDialogArea.Dispose()
+ End
+ Exit Sub
+RTError:
+ Msgbox sRTErrorDesc, 16, sRTErrorHeader
+End Sub
+
+
+Sub NextStep()
+Dim iCurStep as Integer
+ If Not bDebugWizard Then
+ On Error Goto RTError
+ End If
+ bConversionIsRunning = False
+ iCurStep = ImportDialog.Step
+ Select Case iCurStep
+ Case 1
+ FillStep_InputPaths(0, True)
+ Case 2
+ If CheckInputPaths Then
+ SaveStep_InputPath
+ If CurOffice &lt; ApplCount - 1 Then
+ CurOffice = CurOffice + 1
+ TakeOverPathSettings()
+ FillStep_InputPaths(CurOffice, False)
+ Else
+ FillStep_Summary()
+ End If
+ End If
+ Case 3
+ FillStep_Progress()
+ Select Case WizardMode
+ Case SBMICROSOFTMODE
+ Call ConvertAllDocuments(MSFilterName())
+ End Select
+ Case 4
+ CancelTask(True)
+ End Select
+
+ If ((ImportDialog.chkLogfile.State &lt;&gt; 1) OR (iCurStep &lt;&gt; 3)) Then
+ ImportDialog.cmdGoOn.DefaultButton = True
+ End If
+
+ RepaintHeaderPreview()
+ Exit Sub
+RTError:
+ Msgbox sRTErrorDesc, 16, sRTErrorHeader
+End Sub
+
+
+Sub PrevStep()
+Dim iCurStep as Integer
+ If Not bDebugWizard Then
+ On Error Goto RTError
+ End If
+ bConversionIsRunning = False
+ iCurStep = ImportDialog.Step
+ Select Case iCurStep
+ Case 4
+ ImportDialog.cmdCancel.Label = sCancelButton
+ FillStep_Summary()
+ Case 3
+ FillStep_InputPaths(Applcount-1, False)
+ Case 2
+ SaveStep_InputPath
+ If CurOffice &gt; 0 Then
+ CurOffice = CurOffice - 1
+ FillStep_InputPaths(CurOffice, False)
+ Else
+ FillStep_Welcome()
+ ToggleCheckboxesWithBoolean(True)
+ bDoKeepApplValues = True
+ End If
+ End Select
+ ImportDialog.cmdGoOn.DefaultButton = True
+ RepaintHeaderPreview()
+ Exit Sub
+RTError:
+ Msgbox sRTErrorDesc, 16, sRTErrorHeader
+End Sub
+
+
+Sub CancelTask()
+ If bConversionIsRunning Then
+ If Msgbox(sConvertError1, 36, sConvertError2) = 6 Then
+ bCancelTask = True
+ bInterruptSearch = True
+ Else
+ bCancelTask = False
+ ImportDialog.cmdCancel.Enabled = True
+ End If
+ Else
+ ImportDialogArea.EndExecute()
+ End If
+End Sub
+
+
+Sub TemplateDirSearchDialog()
+ CallDirSearchDialog(ImportDialog.TemplateImportPath)
+End Sub
+
+
+Sub RepaintHeaderPreview()
+Dim Bitmap As Object
+Dim CurStep as Integer
+Dim sBitmapPath as String
+Dim LocPrefix as String
+ CurStep = ImportDialog.Step
+ LocPrefix = WizardMode
+ LocPrefix = ReplaceString(LocPrefix,&quot;XML&quot;, &quot;SO&quot;)
+ If CurStep = 2 Then
+ sBitmapPath = SOBitmapPath &amp; LocPrefix &amp; &quot;-Import_&quot; &amp; CurStep &amp; &quot;-&quot; &amp; Applications(CurOffice,SBAPPLKEY) + 1 &amp; &quot;.png&quot;
+ Else
+ sBitmapPath = SOBitmapPath &amp; &quot;Import_&quot; &amp; CurStep &amp; &quot;.png&quot;
+ End If
+ ImportDialog.ImportPreview.ImageURL = sBitmapPath
+End Sub
+
+
+Sub CheckModuleInstallation()
+Dim i as Integer
+ For i = 1 To MaxApplCount
+ ImportDialogArea.GetControl(&quot;chk&quot; &amp; WizardMode &amp; &quot;Application&quot; &amp; i).Model.Enabled = Abs(CheckInstalledModule(i-1))
+ Next i
+End Sub
+
+
+Function CheckInstalledModule(Index as Integer) as Boolean
+Dim ModuleName as String
+Dim NameList() as String
+Dim MaxIndex as Integer
+Dim i as Integer
+ ModuleName = ModuleList(Index)
+ If Instr(1,ModuleName,&quot;/&quot;) &lt;&gt; 0 Then
+ CheckInstalledModule() = False
+ NameList() = ArrayoutOfString(ModuleName,&quot;/&quot;, MaxIndex)
+ For i = 0 To MaxIndex
+ If oFactoryKey.HasByName(NameList(i)) Then
+ CheckInstalledModule() = True
+ End If
+ Next i
+ Else
+ CheckInstalledModule() = oFactoryKey.HasByName(ModuleName)
+ End If
+End Function
+
+
+Sub ToggleCheckboxes(oEvent as Object)
+Dim bMSEnable as Boolean
+ WizardMode = oEvent.Source.Model.Tag
+ bMSEnable = WizardMode = &quot;MS&quot;
+ ToggleCheckboxesWithBoolean(bMSEnable)
+End Sub
+
+
+Sub ToggleCheckboxesWithBoolean(bMSEnable as Boolean)
+ If bMSEnable = True Then
+ WizardMode = SBMICROSOFTMODE
+ MaxApplCount = 3
+ Else
+ &apos;Not supposed to happen - is there an assert in BASIC...
+ End If
+ With ImportDialogArea
+ .GetControl(&quot;chkMSApplication1&quot;).Model.Enabled = bMSEnable
+ .GetControl(&quot;chkMSApplication2&quot;).Model.Enabled = bMSEnable
+ .GetControl(&quot;chkMSApplication3&quot;).Model.Enabled = bMSEnable
+ End With
+ CheckModuleInstallation()
+ bDoKeepApplValues = False
+ ToggleNextButton()
+End Sub
+
+
+Sub ToggleNextButton()
+Dim iCurStep as Integer
+Dim bDoEnable as Boolean
+Dim i as Integer
+ iCurStep = ImportDialog.Step
+ Select Case iCurStep
+ Case 1
+ With ImportDialog
+ If .optMSDocuments.State = 1 Then
+ bDoEnable = .chkMSApplication1.State = 1 Or .chkMSApplication2.State = 1 Or .chkMSApplication3.State = 1
+ End If
+ End With
+ bDoKeepApplValues = False
+ Case 2
+ bDoEnable = CheckControlPath(ImportDialog.chkTemplatePath, ImportDialog.txtTemplateImportPath, True)
+ bDoEnable = CheckControlPath(ImportDialog.chkDocumentPath, ImportDialog.txtDocumentImportPath, bDoEnable)
+ End Select
+ ImportDialog.cmdGoOn.Enabled = bDoEnable
+End Sub
+
+
+Sub TakeOverPathSettings()
+&apos;Takes over the Pathsettings from the first selected application to the next applications
+ If Applications(CurOffice,SBDOCSOURCE) = &quot;&quot; Then
+ Applications(CurOffice,SBDOCSOURCE) = Applications(0,SBDOCSOURCE)
+ Applications(CurOffice,SBDOCTARGET) = Applications(0,SBDOCTARGET)
+ Applications(CurOffice,SBTEMPLSOURCE) = Applications(0,SBTEMPLSOURCE)
+ Applications(CurOffice,SBTEMPLTARGET) = Applications(0,SBTEMPLTARGET)
+ End If
+End Sub
+
+
+Function GetImportWizardPaths() as Boolean
+ SOBitmapPath = GetOfficeSubPath(&quot;Template&quot;, &quot;../wizard/bitmap&quot;)
+ If SOBitmapPath &lt;&gt; &quot;&quot; Then
+ SOWorkPath = GetPathSettings(&quot;Work&quot;, False)
+ If SOWorkPath &lt;&gt; &quot;&quot; Then
+ SOTemplatePath = GetPathSettings(&quot;Template_writable&quot;,False,0)
+ If SOTemplatePath &lt;&gt; &quot;&quot; Then
+ GetImportWizardPaths() = True
+ Exit Function
+ End If
+ End If
+ End If
+ GetImportWizardPaths() = False
+End Function
+</script:module>
diff --git a/wizards/source/importwizard/dialog.xlb b/wizards/source/importwizard/dialog.xlb
new file mode 100644
index 000000000..f5cc021d5
--- /dev/null
+++ b/wizards/source/importwizard/dialog.xlb
@@ -0,0 +1,5 @@
+<?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="ImportWizard" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="ImportDialog"/>
+</library:library>
diff --git a/wizards/source/importwizard/script.xlb b/wizards/source/importwizard/script.xlb
new file mode 100644
index 000000000..2d10f65cb
--- /dev/null
+++ b/wizards/source/importwizard/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="ImportWizard" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="Main"/>
+ <library:element library:name="DialogModul"/>
+ <library:element library:name="Language"/>
+ <library:element library:name="FilesModul"/>
+ <library:element library:name="API"/>
+</library:library>
diff --git a/wizards/source/resources/resources_en_US.properties b/wizards/source/resources/resources_en_US.properties
new file mode 100644
index 000000000..32f9104e9
--- /dev/null
+++ b/wizards/source/resources/resources_en_US.properties
@@ -0,0 +1,579 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License; you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+# x-no-translate
+
+#
+# resources.properties
+#
+# resources for com.sun.star.wizards
+#
+RID_COMMON_0=The directory '%1' could not be created.<BR>There may not be enough space left on your hard disk.
+RID_COMMON_1=The text document could not be created.<BR>Please check if the module 'PRODUCTNAME Writer' is installed.
+RID_COMMON_2=The spreadsheet could not be created.<BR>Please check if the module 'PRODUCTNAME Calc' is installed.
+RID_COMMON_3=The presentation could not be created.<BR>Please check if the module 'PRODUCTNAME Impress' is installed.
+RID_COMMON_4=The drawing could not be created.<BR>Please check if the module 'PRODUCTNAME Draw' is installed.
+RID_COMMON_5=The formula could not be created.<BR>Please check if the module 'PRODUCTNAME Math' is installed.
+RID_COMMON_6=The files required could not be found.<BR>Please start the %PRODUCTNAME Setup and choose 'Repair'.
+RID_COMMON_7=The file '<PATH>' already exists.<BR><BR>Would you like to overwrite the existing file?
+RID_COMMON_8=Yes
+RID_COMMON_9=Yes to All
+RID_COMMON_10=No
+RID_COMMON_11=Cancel
+RID_COMMON_12=~Finish
+RID_COMMON_13=< ~Back
+RID_COMMON_14=~Next >
+RID_COMMON_15=~Help
+RID_COMMON_16=Steps
+RID_COMMON_17=Close
+RID_COMMON_18=OK
+RID_COMMON_19=The file already exists. Do you want to overwrite it?
+RID_COMMON_20=Template created via <wizard_name> on <current_date>.
+RID_COMMON_21=The wizard could not be run, because important files were not found.\nUnder 'Tools - Options - %PRODUCTNAME - Paths' click the 'Default' button to reset the paths to the original default settings.\nThen run the wizard again.
+RID_REPORT_0=Report Wizard
+RID_REPORT_3=~Table
+RID_REPORT_4=Colu~mns
+RID_REPORT_7=Report_
+RID_REPORT_8=- undefined -
+RID_REPORT_9=~Fields in report
+RID_REPORT_11=Grouping
+RID_REPORT_12=Sort options
+RID_REPORT_13=Choose layout
+RID_REPORT_14=Create report
+RID_REPORT_15=Layout of data
+RID_REPORT_16=Layout of headers and footers
+RID_REPORT_19=Fields
+RID_REPORT_20=~Sort by
+RID_REPORT_21=T~hen by
+RID_REPORT_22=Orientation
+RID_REPORT_23=Portrait
+RID_REPORT_24=Landscape
+RID_REPORT_28=Which fields do you want to have in your report?
+RID_REPORT_29=Do you want to add grouping levels?
+RID_REPORT_30=According to which fields do you want to sort the data?
+RID_REPORT_31=How do you want your report to look?
+RID_REPORT_32=Decide how you want to proceed
+RID_REPORT_33=Title of report
+RID_REPORT_34=Display report
+RID_REPORT_35=Create report
+RID_REPORT_36=Ascending
+RID_REPORT_37=Descending
+RID_REPORT_40=~Dynamic report
+RID_REPORT_41=~Create report now
+RID_REPORT_42=~Modify report layout
+RID_REPORT_43=Static report
+RID_REPORT_44=Save as
+RID_REPORT_50=Groupings
+RID_REPORT_51=Then b~y
+RID_REPORT_52=~Then by
+RID_REPORT_53=Asc~ending
+RID_REPORT_54=Ascend~ing
+RID_REPORT_55=Ascendin~g
+RID_REPORT_56=De~scending
+RID_REPORT_57=Des~cending
+RID_REPORT_58=De~scending
+RID_REPORT_60=Binary fields cannot be displayed in the report.
+RID_REPORT_61=The table '<TABLENAME>' does not exist.
+RID_REPORT_62=Creating Report...
+RID_REPORT_63=Number of records inserted: <COUNT>
+RID_REPORT_64=The form '<REPORTFORM>' does not exist.
+RID_REPORT_65=The query with the statement <BR>'<STATEMENT>' <BR> could not be run. <BR> Check your data source.
+RID_REPORT_66=The following hidden control in the form '<REPORTFORM>' could not be read: '<CONTROLNAME>'.
+RID_REPORT_67=Importing data...
+RID_REPORT_68=Labeling fields
+RID_REPORT_69=How do you want to label the fields?
+RID_REPORT_70=Label
+RID_REPORT_71=Field
+RID_REPORT_72=An error occurred in the wizard.<BR>The template '%PATH' could be erroneous.<BR>Either the required sections or tables do not exist or exist under the wrong name.<BR>See the Help for more detailed information.<BR>Please select another template.
+RID_REPORT_73=There is an invalid user field in a table.
+RID_REPORT_74=The sort criterion '<FIELDNAME>' was chosen twice. Each criterion can only be chosen once.
+RID_REPORT_75=Note: The dummy text will be replaced by data from the database when the report is created.
+RID_REPORT_76=A report '%REPORTNAME' already exists in the database. Please assign another name.
+RID_REPORT_78=How do you want to proceed after creating the report?
+RID_REPORT_79=What kind of report do you want to create?
+RID_REPORT_80=Tabular
+RID_REPORT_81=Columnar, single-column
+RID_REPORT_82=Columnar, two columns
+RID_REPORT_83=Columnar, three columns
+RID_REPORT_84=In blocks, labels left
+RID_REPORT_85=In blocks, labels above
+RID_REPORT_86=Title:
+RID_REPORT_87=Author:
+RID_REPORT_88=Date:
+# Please don't translate the words #page# and #count#, these are placeholders.
+RID_REPORT_89=Page #page# of #count#
+RID_REPORT_90=Page number:
+RID_REPORT_91=Page count:
+RID_REPORT_92=No valid report template was found.
+RID_REPORT_93=Page:
+RID_REPORT_94=Align Left - Border
+RID_REPORT_95=Align Left - Compact
+RID_REPORT_96=Align Left - Elegant
+RID_REPORT_97=Align Left - Highlighted
+RID_REPORT_98=Align Left - Modern
+RID_REPORT_99=Align Left - Red & Blue
+RID_REPORT_100=Default
+RID_REPORT_101=Outline - Borders
+RID_REPORT_102=Outline - Compact
+RID_REPORT_103=Outline - Elegant
+RID_REPORT_104=Outline - Highlighted
+RID_REPORT_105=Outline - Modern
+RID_REPORT_106=Outline - Red & Blue
+RID_REPORT_107=Outline, indented - Borders
+RID_REPORT_108=Outline, indented - Compact
+RID_REPORT_109=Outline, indented - Elegant
+RID_REPORT_110=Outline, indented - Highlighted
+RID_REPORT_111=Outline, indented - Modern
+RID_REPORT_112=Outline, indented - Red & Blue
+RID_REPORT_113=Bubbles
+RID_REPORT_114=Cinema
+RID_REPORT_115=Controlling
+RID_REPORT_116=Default
+RID_REPORT_117=Drafting
+RID_REPORT_118=Finances
+RID_REPORT_119=Flipchart
+RID_REPORT_120=Formal with Company Logo
+RID_REPORT_121=Generic
+RID_REPORT_122=Worldmap
+RID_DB_COMMON_0=C~reate
+RID_DB_COMMON_1=~Cancel
+RID_DB_COMMON_2=< ~Back
+RID_DB_COMMON_3=~Next >
+RID_DB_COMMON_4=~Database
+RID_DB_COMMON_5=~Table name
+RID_DB_COMMON_6=An error occurred while running the wizard. The wizard will be terminated.
+RID_DB_COMMON_8=No database has been installed. At least one database is required before the wizard for forms can be started.
+RID_DB_COMMON_9=The database does not contain any tables.
+RID_DB_COMMON_10=This title already exists in the database. Please enter another name.
+RID_DB_COMMON_11=The title must not contain any spaces or special characters.
+RID_DB_COMMON_12=The database service (com.sun.data.DatabaseEngine) could not be instantiated.
+RID_DB_COMMON_13=The selected table or query could not be opened.
+RID_DB_COMMON_14=No connection to the database could be established.
+RID_DB_COMMON_20=~Help
+RID_DB_COMMON_21=~Stop
+RID_DB_COMMON_30=The document could not be saved.
+RID_DB_COMMON_33=Exiting the wizard
+RID_DB_COMMON_34=Connecting to data source...
+RID_DB_COMMON_35=The connection to the data source could not be established.
+RID_DB_COMMON_36=The file path entered is not valid.
+RID_DB_COMMON_37=Please select a data source
+RID_DB_COMMON_38=Please select a table or query
+RID_DB_COMMON_39=Add field
+RID_DB_COMMON_40=Remove field
+RID_DB_COMMON_41=Add all fields
+RID_DB_COMMON_42=Remove all fields
+RID_DB_COMMON_43=Move field up
+RID_DB_COMMON_44=Move field down
+RID_DB_COMMON_45=The field names from '%NAME' could not be retrieved.
+RID_QUERY_0=Query Wizard
+RID_QUERY_1=Query
+RID_QUERY_2=Query Wizard
+RID_QUERY_3=~Tables
+RID_QUERY_4=A~vailable fields
+RID_QUERY_5=Name ~of the query
+RID_QUERY_6=Display ~Query
+RID_QUERY_7=~Modify Query
+RID_QUERY_8=~How do you want to proceed after creating the query?
+RID_QUERY_9=Match ~all of the following
+RID_QUERY_10=~Match any of the following
+RID_QUERY_11=~Detailed query (Shows all records of the query.)
+RID_QUERY_12=~Summary query (Shows only results of aggregate functions.)
+RID_QUERY_16=Aggregate functions
+RID_QUERY_17=Fields
+RID_QUERY_18=~Group by
+RID_QUERY_19=Field
+RID_QUERY_20=Alias
+RID_QUERY_21=Table:
+RID_QUERY_22=Query:
+RID_QUERY_24=Condition
+RID_QUERY_25=Value
+RID_QUERY_26=is equal to
+RID_QUERY_27=is not equal to
+RID_QUERY_28=is smaller than
+RID_QUERY_29=is greater than
+RID_QUERY_30=is equal or less than
+RID_QUERY_31=is equal or greater than
+RID_QUERY_32=like
+RID_QUERY_33=not like
+RID_QUERY_34=is null
+RID_QUERY_35=is not null
+RID_QUERY_36=true
+RID_QUERY_37=false
+RID_QUERY_38=and
+RID_QUERY_39=or
+RID_QUERY_40=get the sum of
+RID_QUERY_41=get the average of
+RID_QUERY_42=get the minimum of
+RID_QUERY_43=get the maximum of
+RID_QUERY_44=get the count of
+RID_QUERY_48=(none)
+RID_QUERY_50=Fie~lds in the Query:
+RID_QUERY_51=Sorting order:
+RID_QUERY_52=No sorting fields were assigned.
+RID_QUERY_53=Search conditions:
+RID_QUERY_54=No conditions were assigned.
+RID_QUERY_55=Aggregate functions:
+RID_QUERY_56=No aggregate functions were assigned.
+RID_QUERY_57=Grouped by:
+RID_QUERY_58=No Groups were assigned.
+RID_QUERY_59=Grouping conditions:
+RID_QUERY_60=No grouping conditions were assigned.
+RID_QUERY_70=Select the fields (columns) for your query
+RID_QUERY_71=Select the sorting order
+RID_QUERY_72=Select the search conditions
+RID_QUERY_73=Select the type of query
+RID_QUERY_74=Select the groups
+RID_QUERY_75=Select the grouping conditions
+RID_QUERY_76=Assign aliases if desired
+RID_QUERY_77=Check the overview and decide how to proceed
+RID_QUERY_80=Field selection
+RID_QUERY_81=Sorting order
+RID_QUERY_82=Search conditions
+RID_QUERY_83=Detail or summary
+RID_QUERY_84=Grouping
+RID_QUERY_85=Grouping conditions
+RID_QUERY_86=Aliases
+RID_QUERY_87=Overview
+RID_QUERY_88=A field that has not been assigned an aggregate function must be used in a group.
+RID_QUERY_89=The condition '<FIELDNAME> <LOGICOPERATOR> <VALUE>' was chosen twice. Each condition can only be chosen once
+RID_QUERY_90=The aggregate function <FUNCTION> has been assigned twice to the fieldname '<NUMERICFIELD>'.
+RID_QUERY_91=,
+RID_QUERY_92=<FIELDTITLE> (<FIELDNAME>)
+RID_QUERY_93=<FIELDNAME> (<SORTMODE>)
+RID_QUERY_94=<FIELDNAME> <LOGICOPERATOR> <VALUE>
+RID_QUERY_95=<CALCULATEDFUNCTION> <FIELDNAME>
+RID_QUERY_96=<FIELDNAME> <LOGICOPERATOR> <VALUE>
+RID_FORM_0=Form Wizard
+RID_FORM_1=Fields in ~the form
+RID_FORM_2=Binary fields are always listed and selectable from the left list.\nIf possible, they are interpreted as images.
+RID_FORM_3=A subform is a form that is inserted in another form.\nUse subforms to show data from tables or queries with a one-to-many relationship.
+RID_FORM_4=~Add Subform
+RID_FORM_5=~Subform based on existing relation
+RID_FORM_6=Tables or queries
+RID_FORM_7=Subform based on ~manual selection of fields
+RID_FORM_8=~Which relation do you want to add?
+RID_FORM_9=Fields in the ~subform
+RID_FORM_12=~Available fields
+RID_FORM_13=Fields in form
+RID_FORM_19=The join '<FIELDNAME1>' and '<FIELDNAME2>' has been selected twice.\nBut joins may only be used once.
+RID_FORM_20=~First joined subform field
+RID_FORM_21=~Second joined subform field
+RID_FORM_22=~Third joined subform field
+RID_FORM_23=~Fourth joined subform field
+RID_FORM_24=F~irst joined main form field
+RID_FORM_25=S~econd joined main form field
+RID_FORM_26=T~hird joined main form field
+RID_FORM_27=F~ourth joined main form field
+RID_FORM_28=Field border
+RID_FORM_29=No border
+RID_FORM_30=3D look
+RID_FORM_31=Flat
+RID_FORM_32=Label placement
+RID_FORM_33=Align left
+RID_FORM_34=Align right
+RID_FORM_35=Arrangement of DB fields
+RID_FORM_36=Columnar - Labels Left
+RID_FORM_37=Columnar - Labels on Top
+RID_FORM_38=In Blocks - Labels Left
+RID_FORM_39=In Blocks - Labels Above
+RID_FORM_40=As Data Sheet
+RID_FORM_41=Arrangement of the main form
+RID_FORM_42=Arrangement of the subform
+RID_FORM_44=The form is to be ~used for entering new data only.
+RID_FORM_45=Existing data will not be displayed
+RID_FORM_46=T~he form is to display all data
+RID_FORM_47=Do not allow ~modification of existing data
+RID_FORM_48=Do not allow ~deletion of existing data
+RID_FORM_49=Do not allow ~addition of new data
+RID_FORM_50=Name of ~the form
+RID_FORM_51=How do you want to proceed after creating the form?
+RID_FORM_52=~Work with the form
+RID_FORM_53=~Modify the form
+RID_FORM_55=~Page Styles
+RID_FORM_80=Field selection
+RID_FORM_81=Set up a subform
+RID_FORM_82=Add subform fields
+RID_FORM_83=Get joined fields
+RID_FORM_84=Arrange controls
+RID_FORM_85=Set data entry
+RID_FORM_86=Apply styles
+RID_FORM_87=Set name
+RID_FORM_88=(Date)
+RID_FORM_89=(Time)
+RID_FORM_90=Select the fields of your form
+RID_FORM_91=Decide if you want to set up a subform
+RID_FORM_92=Select the fields of your subform
+RID_FORM_93=Select the joins between your forms
+RID_FORM_94=Arrange the controls on your form
+RID_FORM_95=Select the data entry mode
+RID_FORM_96=Apply the style of your form
+RID_FORM_97=Set the name of the form
+RID_FORM_98=A form with the name '%FORMNAME' already exists.\nChoose another name.
+RID_TABLE_1=Table Wizard
+RID_TABLE_2=Select fields
+RID_TABLE_3=Set types and formats
+RID_TABLE_4=Set primary key
+RID_TABLE_5=Create table
+RID_TABLE_8=Select fields for your table
+RID_TABLE_9=Set field types and formats
+RID_TABLE_10=Set primary key
+RID_TABLE_11=Create table
+RID_TABLE_14=This wizard helps you to create a table for your database. After selecting a table category and a sample table, choose the fields you want to include in your table. You can include fields from more than one sample table.
+RID_TABLE_15=Ca~tegory
+RID_TABLE_16=B~usiness
+RID_TABLE_17=P~ersonal
+RID_TABLE_18=~Sample tables
+RID_TABLE_19=A~vailable fields
+RID_TABLE_20=Field information
+RID_TABLE_21=+
+RID_TABLE_22=-
+RID_TABLE_23=Field name
+RID_TABLE_24=Field type
+RID_TABLE_25=~Selected fields
+RID_TABLE_26=A primary key uniquely identifies each record in a database table. Primary keys ease the linking of information in separate tables, and it is recommended that you have a primary key in every table. Without a primary key, it will not be possible to enter data into this table.
+RID_TABLE_27=~Create a primary key
+RID_TABLE_28=~Automatically add a primary key
+RID_TABLE_29=~Use an existing field as a primary key
+RID_TABLE_30=Define p~rimary key as a combination of several fields
+RID_TABLE_31=F~ieldname
+RID_TABLE_32=~Primary key fields
+RID_TABLE_33=Auto ~value
+RID_TABLE_34=What do you want to name your table?
+RID_TABLE_35=Congratulations. You have entered all the information needed to create your table.
+RID_TABLE_36=What do you want to do next?
+RID_TABLE_37=Modify the table design
+RID_TABLE_38=Insert data immediately
+RID_TABLE_39=C~reate a form based on this table
+RID_TABLE_40=The table you have created could not be opened.
+RID_TABLE_41=The table name '%TABLENAME' contains a character ('%SPECIALCHAR') that might not be supported by the database.
+RID_TABLE_42=The field name '%FIELDNAME' contains a special character ('%SPECIALCHAR') that might not be supported by the database.
+RID_TABLE_43=Field
+RID_TABLE_44=MyTable
+RID_TABLE_45=Add a Field
+RID_TABLE_46=Remove the selected Field
+RID_TABLE_47=The field cannot be inserted because this would exceed the maximum number of %COUNT possible fields in the database table
+RID_TABLE_48=The name '%TABLENAME' already exists.\nPlease enter another name.
+RID_TABLE_49=Catalog of the table
+RID_TABLE_50=Schema of the table
+RID_TABLE_51=The field '%FIELDNAME' already exists.
+STEP_ZERO_0=~Cancel
+STEP_ZERO_1=~Help
+STEP_ZERO_2=< ~Back
+STEP_ZERO_3=~Convert
+STEP_ZERO_4=Note: Currency amounts from external links and currency conversion factors in formulas cannot be converted.
+STEP_ZERO_5=First, unprotect all sheets.
+STEP_ZERO_6=Currencies:
+STEP_ZERO_7=C~ontinue >
+STEP_ZERO_8=C~lose
+STEP_CONVERTER_0=~Entire document
+STEP_CONVERTER_1=Selection
+STEP_CONVERTER_2=Cell S~tyles
+STEP_CONVERTER_3=Currency cells in the current ~sheet
+STEP_CONVERTER_4=Currency cells in the entire ~document
+STEP_CONVERTER_5=~Selected range
+STEP_CONVERTER_6=Select Cell Styles
+STEP_CONVERTER_7=Select currency cells
+STEP_CONVERTER_8=Currency ranges:
+STEP_CONVERTER_9=Templates:
+STEP_AUTOPILOT_0=Extent
+STEP_AUTOPILOT_1=~Single %PRODUCTNAME Calc document
+STEP_AUTOPILOT_2=Complete ~directory
+STEP_AUTOPILOT_3=Source Document:
+STEP_AUTOPILOT_4=Source directory:
+STEP_AUTOPILOT_5=~Including subfolders
+STEP_AUTOPILOT_6=Target directory:
+STEP_AUTOPILOT_7=Temporarily unprotect sheet without query
+STEP_AUTOPILOT_10=Also convert fields and tables in text documents
+STATUSLINE_0=Conversion status:
+STATUSLINE_1=Conversion status of the cell templates:
+STATUSLINE_2=Registration of the relevant ranges: Sheet %1Number%1 of %2TotPageCount%2
+STATUSLINE_3=Entry of the ranges to be converted...
+STATUSLINE_4=Sheet protection for each sheet will be restored...
+STATUSLINE_5=Conversion of the currency units in the cell templates...
+MESSAGES_0=~Finish
+MESSAGES_1=Select directory
+MESSAGES_2=Select file
+MESSAGES_3=Select target directory
+MESSAGES_4=non-existent
+MESSAGES_5=Euro Converter
+MESSAGES_6=Should protected spreadsheets be temporarily unprotected?
+MESSAGES_7=Enter the password to unprotect the table %1TableName%1
+MESSAGES_8=Wrong Password!
+MESSAGES_9=Protected Sheet
+MESSAGES_10=Warning!
+MESSAGES_11=Protection for the sheets will not be removed.
+MESSAGES_12=Sheet cannot be unprotected
+MESSAGES_13=The Wizard cannot edit this document as cell formats cannot be modified in documents containing protected spreadsheets.
+MESSAGES_14=Please note that the Euro Converter will, otherwise, not be able to edit this document!
+MESSAGES_15=Please choose a currency to be converted first!
+MESSAGES_16=Password:
+MESSAGES_17=OK
+MESSAGES_18=Cancel
+MESSAGES_19=Please select a %PRODUCTNAME Calc document for editing!
+MESSAGES_20='<1>' is not a directory!
+MESSAGES_21=Document is read-only!
+MESSAGES_22=The '<1>' file already exists.<CR>Do you want to overwrite it?
+MESSAGES_23=Do you really want to terminate conversion at this point?
+MESSAGES_24=Cancel Wizard
+CURRENCIES_0=Portuguese Escudo
+CURRENCIES_1=Dutch Guilder
+CURRENCIES_2=French Franc
+CURRENCIES_3=Spanish Peseta
+CURRENCIES_4=Italian Lira
+CURRENCIES_5=German Mark
+CURRENCIES_6=Belgian Franc
+CURRENCIES_7=Irish Punt
+CURRENCIES_8=Luxembourg Franc
+CURRENCIES_9=Austrian Schilling
+CURRENCIES_10=Finnish Mark
+CURRENCIES_11=Greek Drachma
+CURRENCIES_12=Slovenian Tolar
+CURRENCIES_13=Cypriot Pound
+CURRENCIES_14=Maltese Lira
+CURRENCIES_15=Slovak Koruna
+CURRENCIES_16=Estonian Kroon
+CURRENCIES_17=Latvian Lats
+CURRENCIES_18=Lithuanian Litas
+STEP_LASTPAGE_0=Progress
+STEP_LASTPAGE_1=Retrieving the relevant documents...
+STEP_LASTPAGE_2=Converting the documents...
+STEP_LASTPAGE_3=Settings:
+STEP_LASTPAGE_4=Sheet is always unprotected
+STYLES_0=Theme Selection
+STYLES_1=Error while saving the document to the clipboard! The following action cannot be undone.
+STYLES_2=~Cancel
+STYLES_3=~OK
+STYLENAME_0=(Standard)
+STYLENAME_1=Autumn Leaves
+STYLENAME_2=Be
+STYLENAME_3=Black and White
+STYLENAME_4=Blackberry Bush
+STYLENAME_5=Blue Jeans
+STYLENAME_6=Fifties Diner
+STYLENAME_7=Glacier
+STYLENAME_8=Green Grapes
+STYLENAME_9=Marine
+STYLENAME_10=Millennium
+STYLENAME_11=Nature
+STYLENAME_12=Neon
+STYLENAME_13=Night
+STYLENAME_14=PC Nostalgia
+STYLENAME_15=Pastel
+STYLENAME_16=Pool Party
+STYLENAME_17=Pumpkin
+CorrespondenceDialog_0=Addressee
+CorrespondenceDialog_1=One recipient
+CorrespondenceDialog_2=Several recipients (address database)
+CorrespondenceDialog_3=Use of This Template
+CorrespondenceMsgError=An error has occurred.
+CorrespondenceFields_0=Click placeholder and overwrite
+CorrespondenceFields_1=Company
+CorrespondenceFields_2=Department
+CorrespondenceFields_3=First Name
+CorrespondenceFields_4=Last Name
+CorrespondenceFields_5=Street
+CorrespondenceFields_6=Country
+CorrespondenceFields_7=ZIP/Postal Code
+CorrespondenceFields_8=City
+CorrespondenceFields_9=Title
+CorrespondenceFields_10=Position
+CorrespondenceFields_11=Form of Address
+CorrespondenceFields_12=Initials
+CorrespondenceFields_13=Salutation
+CorrespondenceFields_14=Home Phone
+CorrespondenceFields_15=Work Phone
+CorrespondenceFields_16=Fax
+CorrespondenceFields_17=Email
+CorrespondenceFields_18=URL
+CorrespondenceFields_19=Notes
+CorrespondenceFields_20=Alt. Field 1
+CorrespondenceFields_21=Alt. Field 2
+CorrespondenceFields_22=Alt. Field 3
+CorrespondenceFields_23=Alt. Field 4
+CorrespondenceFields_24=ID
+CorrespondenceFields_25=State
+CorrespondenceFields_26=Office Phone
+CorrespondenceFields_27=Pager
+CorrespondenceFields_28=Mobile Phone
+CorrespondenceFields_29=Other Phone
+CorrespondenceFields_30=Calendar URL
+CorrespondenceFields_31=Invite
+CorrespondenceNoTextmark_0=The bookmark 'Recipient' is missing.
+CorrespondenceNoTextmark_1=Form letter fields can not be included.
+AgendaDlgName=Minutes Template
+AgendaDlgNoCancel=An option must be confirmed.
+AgendaDlgFrame=Minutes Type
+AgendaDlgButton1=Results Minutes
+AgendaDlgButton2=Evaluation Minutes
+TextField=User data field is not defined!
+NoDirCreation=The '%1' directory cannot be created:
+MsgDirNotThere=The '%1' directory does not exist.
+QueryfornewCreation=Do you want to create it now?
+HelpButton=~Help
+CancelButton=~Cancel
+BackButton=< ~Back
+NextButton=Ne~xt >
+BeginButton=~Convert
+CloseButton=~Close
+WelcometextLabel1=This wizard convert legacy format documents to Open Document Format for Office Applications.
+WelcometextLabel3=Select the document type for conversion:
+MSTemplateCheckbox_1_=Word templates
+MSTemplateCheckbox_2_=Excel templates
+MSTemplateCheckbox_3_=PowerPoint templates
+MSDocumentCheckbox_1_=Word documents
+MSDocumentCheckbox_2_=Excel documents
+MSDocumentCheckbox_3_=PowerPoint/Publisher documents
+MSContainerName=Microsoft Office
+SummaryHeader=Summary:
+GroupnameDefault=Imported_Templates
+ProgressMoreDocs=Documents
+ProgressMoreTemplates=Templates
+FileExists=The '<1>' file already exists.<CR>Do you want to overwrite it?
+MorePathsError3=Directories do not exist
+ConvertError1=Do you really want to terminate conversion at this point?
+ConvertError2=Cancel Wizard
+RTErrorDesc=An error has occurred in the wizard.
+RTErrorHeader=Error
+OverwriteallFiles=Do you want to overwrite documents without being asked?
+ReeditMacro=Document macro has to be revised.
+CouldNotsaveDocument=Document '<1>' could not be saved.
+CouldNotopenDocument=Document '<1>' could not be opened.
+PathDialogMessage=Select a directory
+DialogTitle=Document Converter
+SearchInSubDir=Including subdirectories
+ProgressPage1=Progress
+ProgressPage2=Retrieving the relevant documents:
+ProgressPage3=Converting the documents
+ProgressFound=Found:
+ProgressPage5="%1 found
+Ready=Finished
+SourceDocuments=Source documents
+TargetDocuments=Target documents
+LogfileSummary=<COUNT> documents converted
+SumInclusiveSubDir=All subdirectories will be taken into account
+SumSaveDokumente=These will be exported to the following directory:
+TextImportLabel=Import from:
+TextExportLabel=Save to:
+CreateLogfile=Create log file
+LogfileHelpText=A log file will be created in your work directory
+ShowLogfile=Show log file
+SumMSTextDocuments=All Word documents contained in the following directory will be imported:
+SumMSTableDocuments=All Excel documents contained in the following directory will be imported:
+SumMSDrawDocuments=All PowerPoint/Publisher documents contained in the following directory will be imported:
+SumMSTextTemplates=All Word templates contained in the following directory will be imported:
+SumMSTableTemplates=All Excel templates contained in the following directory will be imported:
+SumMSDrawTemplates=All PowerPoint templates contained in the following directory will be imported:
diff --git a/wizards/source/scriptforge/SF_Array.xba b/wizards/source/scriptforge/SF_Array.xba
new file mode 100644
index 000000000..49bdab147
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Array.xba
@@ -0,0 +1,2608 @@
+<?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_Array" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Array
+&apos;&apos;&apos; ========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Array&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos; Only 1D or 2D arrays are considered. Arrays with more than 2 dimensions are rejected
+&apos;&apos;&apos; With the noticeable exception of the CountDims method (&gt;2 dims allowed)
+&apos;&apos;&apos; The first argument of almost every method is the array to consider
+&apos;&apos;&apos; It is always passed by reference and left unchanged
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_array.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const ARRAYSEQUENCEERROR = &quot;ARRAYSEQUENCEERROR&quot; &apos; Incoherent arguments
+Const ARRAYINSERTERROR = &quot;ARRAYINSERTERROR&quot; &apos; Matrix and vector have incompatible sizes
+Const ARRAYINDEX1ERROR = &quot;ARRAYINDEX1ERROR&quot; &apos; Given index does not fit in array bounds
+Const ARRAYINDEX2ERROR = &quot;ARRAYINDEX2ERROR&quot; &apos; Given indexes do not fit in array bounds
+Const CSVPARSINGERROR = &quot;CSVPARSINGERROR&quot; &apos; Parsing error detected while parsing a csv file
+Const CSVOVERFLOWWARNING = &quot;CSVOVERFLOWWARNING&quot; &apos; Array becoming too big, import process of csv file is interrupted
+
+REM ============================================================ MODULE CONSTANTS
+
+Const MAXREPR = 50 &apos; Maximum length to represent an array in the console
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Array Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_Array&quot;
+End Property &apos; ScriptForge.SF_Array.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.Array&quot;
+End Property &apos; ScriptForge.SF_Array.ServiceName
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Append(Optional ByRef Array_1D As Variant _
+ , ParamArray pvArgs() As Variant _
+ ) As Variant
+&apos;&apos;&apos; Append at the end of the input array the items listed as arguments
+&apos;&apos;&apos; Arguments are appended blindly
+&apos;&apos;&apos; each of them might be a scalar of any type or a subarray
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_1D: the pre-existing array, may be empty
+&apos;&apos;&apos; pvArgs: a list of items to append to Array_1D
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; the new extended array. Its LBound is identical to that of Array_1D
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Append(Array(1, 2, 3), 4, 5) returns (1, 2, 3, 4, 5)
+
+Dim vAppend As Variant &apos; Return value
+Dim lNbArgs As Long &apos; Number of elements to append
+Dim lMax As Long &apos; UBound of input array
+Dim i As Long
+Const cstThisSub = &quot;Array.Append&quot;
+Const cstSubArgs = &quot;Array_1D, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vAppend = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+
+Try:
+ lMax = UBound(Array_1D)
+ lNbArgs = UBound(pvArgs) + 1 &apos; pvArgs is always zero-based
+ If lMax &lt; LBound(Array_1D) Then &apos; Initial array is empty
+ If lNbArgs &gt; 0 Then
+ ReDim vAppend(0 To lNbArgs - 1)
+ End If
+ Else
+ vAppend() = Array_1D()
+ If lNbArgs &gt; 0 Then
+ ReDim Preserve vAppend(LBound(Array_1D) To lMax + lNbArgs)
+ End If
+ End If
+ For i = 1 To lNbArgs
+ vAppend(lMax + i) = pvArgs(i - 1)
+ Next i
+
+Finally:
+ Append = vAppend()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Append
+
+REM -----------------------------------------------------------------------------
+Public Function AppendColumn(Optional ByRef Array_2D As Variant _
+ , Optional ByRef Column As Variant _
+ ) As Variant
+&apos;&apos;&apos; AppendColumn appends to the right side of a 2D array a new Column
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_2D: the pre-existing array, may be empty
+&apos;&apos;&apos; If the array has 1 dimension, it is considered as the 1st Column of the resulting 2D array
+&apos;&apos;&apos; Column: a 1D array with as many items as there are rows in Array_2D
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the new extended array. Its LBounds are identical to that of Array_2D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINSERTERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.AppendColumn(Array(1, 2, 3), Array(4, 5, 6)) returns ((1, 4), (2, 5), (3, 6))
+&apos;&apos;&apos; x = SF_Array.AppendColumn(Array(), Array(1, 2, 3)) =&gt; ∀ i ∈ {0 ≤ i ≤ 2} : x(0, i) ≡ i
+
+Dim vAppendColumn As Variant &apos; Return value
+Dim iDims As Integer &apos; Dimensions of Array_2D
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim lMin As Long &apos; LBound of Column array
+Dim lMax As Long &apos; UBound of Column array
+Dim i As Long
+Dim j As Long
+Const cstThisSub = &quot;Array.AppendColumn&quot;
+Const cstSubArgs = &quot;Array_2D, Column&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vAppendColumn = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;) Then GoTo Finally &apos;Initial check: not missing and array
+ If Not SF_Utils._ValidateArray(Column, &quot;Column&quot;, 1) Then GoTo Finally
+ End If
+ iDims = SF_Array.CountDims(Array_2D)
+ If iDims &gt; 2 Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally &apos;2nd check to manage error
+ End If
+
+Try:
+ lMin = LBound(Column)
+ lMax = UBound(Column)
+
+ &apos; Compute future dimensions of output array
+ Select Case iDims
+ Case 0 : lMin1 = lMin : lMax1 = lMax
+ lMin2 = 0 : lMax2 = -1
+ Case 1 : lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = 0 : lMax2 = 0
+ Case 2 : lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ End Select
+ If iDims &gt; 0 And lMax - lMin &lt;&gt; lMax1 - lMin1 Then GoTo CatchColumn
+ ReDim vAppendColumn(lMin1 To lMax1, lMin2 To lMax2 + 1)
+
+ &apos; Copy input array to output array
+ For i = lMin1 To lMax1
+ For j = lMin2 To lMax2
+ If iDims = 2 Then vAppendColumn(i, j) = Array_2D(i, j) Else vAppendColumn(i, j) = Array_2D(i)
+ Next j
+ Next i
+ &apos; Copy new Column
+ For i = lMin1 To lMax1
+ vAppendColumn(i, lMax2 + 1) = Column(i)
+ Next i
+
+Finally:
+ AppendColumn = vAppendColumn()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchColumn:
+ SF_Exception.RaiseFatal(ARRAYINSERTERROR, &quot;Column&quot;, SF_Array._Repr(Array_2D), SF_Utils._Repr(Column, MAXREPR))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.AppendColumn
+
+REM -----------------------------------------------------------------------------
+Public Function AppendRow(Optional ByRef Array_2D As Variant _
+ , Optional ByRef Row As Variant _
+ ) As Variant
+&apos;&apos;&apos; AppendRow appends below a 2D array a new row
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_2D: the pre-existing array, may be empty
+&apos;&apos;&apos; If the array has 1 dimension, it is considered as the 1st row of the resulting 2D array
+&apos;&apos;&apos; Row: a 1D array with as many items as there are columns in Array_2D
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the new extended array. Its LBounds are identical to that of Array_2D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINSERTERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.AppendRow(Array(1, 2, 3), Array(4, 5, 6)) returns ((1, 2, 3), (4, 5, 6))
+&apos;&apos;&apos; x = SF_Array.AppendRow(Array(), Array(1, 2, 3)) =&gt; ∀ i ∈ {0 ≤ i ≤ 2} : x(i, 0) ≡ i
+
+Dim vAppendRow As Variant &apos; Return value
+Dim iDims As Integer &apos; Dimensions of Array_2D
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim lMin As Long &apos; LBound of row array
+Dim lMax As Long &apos; UBound of row array
+Dim i As Long
+Dim j As Long
+Const cstThisSub = &quot;Array.AppendRow&quot;
+Const cstSubArgs = &quot;Array_2D, Row&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vAppendRow = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;) Then GoTo Finally &apos;Initial check: not missing and array
+ If Not SF_Utils._ValidateArray(Row, &quot;Row&quot;, 1) Then GoTo Finally
+ End If
+ iDims = SF_Array.CountDims(Array_2D)
+ If iDims &gt; 2 Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally &apos;2nd check to manage error
+ End If
+
+Try:
+ lMin = LBound(Row)
+ lMax = UBound(Row)
+
+ &apos; Compute future dimensions of output array
+ Select Case iDims
+ Case 0 : lMin1 = 0 : lMax1 = -1
+ lMin2 = lMin : lMax2 = lMax
+ Case 1 : lMin1 = 0 : lMax1 = 0
+ lMin2 = LBound(Array_2D, 1) : lMax2 = UBound(Array_2D, 1)
+ Case 2 : lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ End Select
+ If iDims &gt; 0 And lMax - lMin &lt;&gt; lMax2 - lMin2 Then GoTo CatchRow
+ ReDim vAppendRow(lMin1 To lMax1 + 1, lMin2 To lMax2)
+
+ &apos; Copy input array to output array
+ For i = lMin1 To lMax1
+ For j = lMin2 To lMax2
+ If iDims = 2 Then vAppendRow(i, j) = Array_2D(i, j) Else vAppendRow(i, j) = Array_2D(j)
+ Next j
+ Next i
+ &apos; Copy new row
+ For j = lMin2 To lMax2
+ vAppendRow(lMax1 + 1, j) = Row(j)
+ Next j
+
+Finally:
+ AppendRow = vAppendRow()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchRow:
+ SF_Exception.RaiseFatal(ARRAYINSERTERROR, &quot;Row&quot;, SF_Array._Repr(Array_2D), SF_Utils._Repr(Row, MAXREPR))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.AppendRow
+
+REM -----------------------------------------------------------------------------
+Public Function Contains(Optional ByRef Array_1D As Variant _
+ , Optional ByVal ToFind As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ , Optional ByVal SortOrder As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Check if a 1D array contains the ToFind number, string or date
+&apos;&apos;&apos; The comparison between strings can be done case-sensitive or not
+&apos;&apos;&apos; If the array is sorted then
+&apos;&apos;&apos; the array must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; a binary search is done
+&apos;&apos;&apos; Otherwise the array is scanned from top. Null or Empty items are simply ignored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to scan
+&apos;&apos;&apos; ToFind: a number, a date or a string to find
+&apos;&apos;&apos; CaseSensitive: Only for string comparisons, default = False
+&apos;&apos;&apos; SortOrder: &quot;ASC&quot;, &quot;DESC&quot; or &quot;&quot; (= not sorted, default)
+&apos;&apos;&apos; Return: True when found
+&apos;&apos;&apos; Result is unpredictable when array is announced sorted and is in reality not
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Contains(Array(&quot;A&quot;,&quot;B&quot;,&quot;c&quot;,&quot;D&quot;), &quot;C&quot;, SortOrder := &quot;ASC&quot;) returns True
+&apos;&apos;&apos; SF_Array.Contains(Array(&quot;A&quot;,&quot;B&quot;,&quot;c&quot;,&quot;D&quot;), &quot;C&quot;, CaseSensitive := True) returns False
+
+Dim bContains As Boolean &apos; Return value
+Dim iToFindType As Integer &apos; VarType of ToFind
+Const cstThisSub = &quot;Array.Contains&quot;
+Const cstSubArgs = &quot;Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;&quot;&quot;|&quot;&quot;ASC&quot;&quot;|&quot;&quot;DESC&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ bContains = False
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then SortOrder = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(SortOrder, &quot;SortOrder&quot;, V_STRING, Array(&quot;ASC&quot;, &quot;DESC&quot;, &quot;&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(ToFind, &quot;ToFind&quot;, Array(V_STRING, V_DATE, V_NUMERIC)) Then GoTo Finally
+ iToFindType = SF_Utils._VarTypeExt(ToFind)
+ If SortOrder &lt;&gt; &quot;&quot; Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1, iToFindType) Then GoTo Finally
+ Else
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ bContains = SF_Array._FindItem(Array_1D, ToFind, CaseSensitive, SortOrder)(0)
+
+Finally:
+ Contains = bContains
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Contains
+
+REM -----------------------------------------------------------------------------
+Public Function ConvertToDictionary(Optional ByRef Array_2D As Variant) As Variant
+&apos;&apos;&apos; Store the content of a 2-columns array into a dictionary
+&apos;&apos;&apos; Key found in 1st column, Item found in 2nd
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_2D: 1st column must contain exclusively non zero-length strings
+&apos;&apos;&apos; 1st column may not be sorted
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a ScriptForge dictionary object
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos;
+
+Dim oDict As Variant &apos; Return value
+Dim i As Long
+Const cstThisSub = &quot;Dictionary.ConvertToArray&quot;
+Const cstSubArgs = &quot;Array_2D&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2, V_STRING, True) Then GoTo Finally
+ End If
+
+Try:
+ Set oDict = SF_Services.CreateScriptService(&quot;Dictionary&quot;)
+ For i = LBound(Array_2D, 1) To UBound(Array_2D, 1)
+ oDict.Add(Array_2D(i, 0), Array_2D(i, 1))
+ Next i
+
+ ConvertToDictionary = oDict
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.ConvertToDictionary
+
+REM -----------------------------------------------------------------------------
+Public Function Copy(Optional ByRef Array_ND As Variant) As Variant
+&apos;&apos;&apos; Duplicate a 1D or 2D array
+&apos;&apos;&apos; A usual assignment copies an array by reference, i.e. shares the same memory location
+&apos;&apos;&apos; Dim a, b
+&apos;&apos;&apos; a = Array(1, 2, 3)
+&apos;&apos;&apos; b = a
+&apos;&apos;&apos; a(2) = 30
+&apos;&apos;&apos; MsgBox b(2) &apos; 30
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_ND: the array to copy, may be empty
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; the copied array. Subarrays however still remain assigned by reference
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Copy(Array(1, 2, 3)) returns (1, 2, 3)
+
+Dim vCopy As Variant &apos; Return value
+Dim iDims As Integer &apos; Number of dimensions of the input array
+Const cstThisSub = &quot;Array.Copy&quot;
+Const cstSubArgs = &quot;Array_ND&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vCopy = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_ND, &quot;Array_ND&quot;) Then GoTo Finally
+ iDims = SF_Array.CountDims(Array_ND)
+ If iDims &gt; 2 Then
+ If Not SF_Utils._ValidateArray(Array_ND, &quot;Array_ND&quot;, 2) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ Select Case iDims
+ Case 0
+ Case 1
+ vCopy = Array_ND
+ ReDim Preserve vCopy(LBound(Array_ND) To UBound(Array_ND))
+ Case 2
+ vCopy = Array_ND
+ ReDim Preserve vCopy(LBound(Array_ND, 1) To UBound(Array_ND, 1), LBound(Array_ND, 2) To UBound(Array_ND, 2))
+ End Select
+
+Finally:
+ Copy = vCopy()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Copy
+
+REM -----------------------------------------------------------------------------
+Public Function CountDims(Optional ByRef Array_ND As Variant) As Integer
+&apos;&apos;&apos; Count the number of dimensions of an array - may be &gt; 2
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_ND: the array to be examined
+&apos;&apos;&apos; Return: the number of dimensions: -1 = not array, 0 = uninitialized array, else &gt;= 1
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim a(1 To 10, -3 To 12, 5)
+&apos;&apos;&apos; CountDims(a) returns 3
+
+Dim iDims As Integer &apos; Return value
+Dim lMax As Long &apos; Storage for UBound of each dimension
+Const cstThisSub = &quot;Array.CountDims&quot;
+Const cstSubArgs = &quot;Array_ND&quot;
+
+Check:
+ iDims = -1
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If IsMissing(Array_ND) Then &apos; To have missing exception processed
+ If Not SF_Utils._ValidateArray(Array_ND, &quot;Array_ND&quot;) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ On Local Error Goto ErrHandler
+ &apos; Loop, increasing the dimension index (i) until an error occurs.
+ &apos; An error will occur when i exceeds the number of dimensions in the array. Returns i - 1.
+ iDims = 0
+ If Not IsArray(Array_ND) Then
+ Else
+ Do
+ iDims = iDims + 1
+ lMax = UBound(Array_ND, iDims)
+ Loop Until (Err &lt;&gt; 0)
+ End If
+
+ ErrHandler:
+ On Local Error GoTo 0
+
+ iDims = iDims - 1
+ If iDims = 1 Then
+ If LBound(Array_ND, 1) &gt; UBound(Array_ND, 1) Then iDims = 0
+ End If
+
+Finally:
+ CountDims = iDims
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Array.CountDims
+
+REM -----------------------------------------------------------------------------
+Public Function Difference(Optional ByRef Array1_1D As Variant _
+ , Optional ByRef Array2_1D As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Build a set being the Difference of the two input arrays, i.e. items are contained in 1st array and NOT in 2nd
+&apos;&apos;&apos; both input arrays must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; The comparison between strings is case sensitive or not
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array1_1D: a 1st input array
+&apos;&apos;&apos; Array2_1D: a 2nd input array
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns: a zero-based array containing unique items from the 1st array not present in the 2nd
+&apos;&apos;&apos; The output array is sorted in ascending order
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Difference(Array(&quot;A&quot;, &quot;C&quot;, &quot;A&quot;, &quot;b&quot;, &quot;B&quot;), Array(&quot;C&quot;, &quot;Z&quot;, &quot;b&quot;), True) returns (&quot;A&quot;, &quot;B&quot;)
+
+Dim vDifference() As Variant &apos; Return value
+Dim vSorted() As Variant &apos; The 2nd input array after sort
+Dim iType As Integer &apos; VarType of elements in input arrays
+Dim lMin1 As Long &apos; LBound of 1st input array
+Dim lMax1 As Long &apos; UBound of 1st input array
+Dim lMin2 As Long &apos; LBound of 2nd input array
+Dim lMax2 As Long &apos; UBound of 2nd input array
+Dim lSize As Long &apos; Number of Difference items
+Dim vItem As Variant &apos; One single item in the array
+Dim i As Long
+Const cstThisSub = &quot;Array.Difference&quot;
+Const cstSubArgs = &quot;Array1_1D, Array2_1D, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vDifference = Array()
+
+Check:
+ If IsMissing(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array1_1D, &quot;Array1_1D&quot;, 1, 0, True) Then GoTo Finally
+ iType = SF_Utils._VarTypeExt(Array1_1D(LBound(Array1_1D)))
+ If Not SF_Utils._ValidateArray(Array2_1D, &quot;Array2_1D&quot;, 1, iType, True) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin1 = LBound(Array1_1D) : lMax1 = UBound(Array1_1D)
+ lMin2 = LBound(Array2_1D) : lMax2 = UBound(Array2_1D)
+
+ &apos; If 1st array is empty, do nothing
+ If lMax1 &lt; lMin1 Then
+ ElseIf lMax2 &lt; lMin2 Then &apos; only 2nd array is empty
+ vUnion = SF_Array.Unique(Array1_1D, CaseSensitive)
+ Else
+
+ &apos; First sort the 2nd array
+ vSorted = SF_Array.Sort(Array2_1D, &quot;ASC&quot;, CaseSensitive)
+
+ &apos; Resize the output array to the size of the 1st array
+ ReDim vDifference(0 To (lMax1 - lMin1))
+ lSize = -1
+
+ &apos; Fill vDifference one by one with items present only in 1st set
+ For i = lMin1 To lMax1
+ vItem = Array1_1D(i)
+ If Not SF_Array.Contains(vSorted, vItem, CaseSensitive, &quot;ASC&quot;) Then
+ lSize = lSize + 1
+ vDifference(lSize) = vItem
+ End If
+ Next i
+
+ &apos; Remove unfilled entries and duplicates
+ If lSize &gt;= 0 Then
+ ReDim Preserve vDifference(0 To lSize)
+ vDifference() = SF_Array.Unique(vDifference, CaseSensitive)
+ Else
+ vDifference = Array()
+ End If
+ End If
+
+Finally:
+ Difference = vDifference()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Difference
+
+REM -----------------------------------------------------------------------------
+Public Function ExportToTextFile(Optional ByRef Array_1D As Variant _
+ , Optional ByVal FileName As Variant _
+ , Optional ByVal Encoding As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Write all items of the array sequentially to a text file
+&apos;&apos;&apos; If the file exists already, it will be overwritten without warning
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to export
+&apos;&apos;&apos; FileName: the full name (path + file) in SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.ExportToTextFile(Array(&quot;A&quot;,&quot;B&quot;,&quot;C&quot;,&quot;D&quot;), &quot;C:\Temp\A short file.txt&quot;)
+
+Dim bExport As Boolean &apos; Return value
+Dim oFile As Object &apos; Output file handler
+Dim sLine As String &apos; A single line
+Const cstThisSub = &quot;Array.ExportToTextFile&quot;
+Const cstSubArgs = &quot;Array_1D, FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExport = False
+
+Check:
+ If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1, V_STRING, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oFile = SF_FileSystem.CreateTextFile(FileName, Overwrite := True, Encoding := Encoding)
+ If Not IsNull(oFile) Then
+ With oFile
+ For Each sLine In Array_1D
+ .WriteLine(sLine)
+ Next sLine
+ .CloseFile()
+ End With
+ End If
+
+ bExport = True
+
+Finally:
+ If Not IsNull(oFile) Then Set oFile = oFile.Dispose()
+ ExportToTextFile = bExport
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.ExportToTextFile
+
+REM -----------------------------------------------------------------------------
+Public Function ExtractColumn(Optional ByRef Array_2D As Variant _
+ , Optional ByVal ColumnIndex As Variant _
+ ) As Variant
+&apos;&apos;&apos; ExtractColumn extracts from a 2D array a specific column
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_2D: the array from which to extract
+&apos;&apos;&apos; ColumnIndex: the column to extract - must be in the interval [LBound, UBound]
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the extracted column. Its LBound and UBound are identical to that of the 1st dimension of Array_2D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINDEX1ERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; |1, 2, 3|
+&apos;&apos;&apos; SF_Array.ExtractColumn( |4, 5, 6|, 2) returns (3, 6, 9)
+&apos;&apos;&apos; |7, 8, 9|
+
+Dim vExtractColumn As Variant &apos; Return value
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound1 of input array
+Dim lMax2 As Long &apos; UBound1 of input array
+Dim i As Long
+Const cstThisSub = &quot;Array.ExtractColumn&quot;
+Const cstSubArgs = &quot;Array_2D, ColumnIndex&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vExtractColumn = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally
+ If Not SF_Utils._Validate(ColumnIndex, &quot;ColumnIndex&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Compute future dimensions of output array
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ If ColumnIndex &lt; lMin2 Or ColumnIndex &gt; lMax2 Then GoTo CatchIndex
+ lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ ReDim vExtractColumn(lMin1 To lMax1)
+
+ &apos; Copy Column of input array to output array
+ For i = lMin1 To lMax1
+ vExtractColumn(i) = Array_2D(i, ColumnIndex)
+ Next i
+
+Finally:
+ ExtractColumn = vExtractColumn()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchIndex:
+ SF_Exception.RaiseFatal(ARRAYINDEX1ERROR, &quot;ColumnIndex&quot;, SF_Array._Repr(Array_2D), ColumnIndex)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.ExtractColumn
+
+REM -----------------------------------------------------------------------------
+Public Function ExtractRow(Optional ByRef Array_2D As Variant _
+ , Optional ByVal RowIndex As Variant _
+ ) As Variant
+&apos;&apos;&apos; ExtractRow extracts from a 2D array a specific row
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_2D: the array from which to extract
+&apos;&apos;&apos; RowIndex: the row to extract - must be in the interval [LBound, UBound]
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the extracted row. Its LBound and UBound are identical to that of the 2nd dimension of Array_2D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINDEX1ERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; |1, 2, 3|
+&apos;&apos;&apos; SF_Array.ExtractRow(|4, 5, 6|, 2) returns (7, 8, 9)
+&apos;&apos;&apos; |7, 8, 9|
+
+Dim vExtractRow As Variant &apos; Return value
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound1 of input array
+Dim lMax2 As Long &apos; UBound1 of input array
+Dim i As Long
+Const cstThisSub = &quot;Array.ExtractRow&quot;
+Const cstSubArgs = &quot;Array_2D, RowIndex&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vExtractRow = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally
+ If Not SF_Utils._Validate(RowIndex, &quot;RowIndex&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Compute future dimensions of output array
+ lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ If RowIndex &lt; lMin1 Or RowIndex &gt; lMax1 Then GoTo CatchIndex
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ ReDim vExtractRow(lMin2 To lMax2)
+
+ &apos; Copy row of input array to output array
+ For i = lMin2 To lMax2
+ vExtractRow(i) = Array_2D(RowIndex, i)
+ Next i
+
+Finally:
+ ExtractRow = vExtractRow()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchIndex:
+ SF_Exception.RaiseFatal(ARRAYINDEX1ERROR, &quot;RowIndex&quot;, SF_Array._Repr(Array_2D), RowIndex)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.ExtractRow
+
+REM -----------------------------------------------------------------------------
+Public Function Flatten(Optional ByRef Array_1D As Variant) As Variant
+&apos;&apos;&apos; Stack all items and all items in subarrays into one array without subarrays
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_1D: the pre-existing array, may be empty
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The new flattened array. Its LBound is identical to that of Array_1D
+&apos;&apos;&apos; If one of the subarrays has a number of dimensions &gt; 1 Then that subarray is left unchanged
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Flatten(Array(1, 2, Array(3, 4, 5)) returns (1, 2, 3, 4, 5)
+
+Dim vFlatten As Variant &apos; Return value
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim lIndex As Long &apos; Index in output array
+Dim vItem As Variant &apos; Array single item
+Dim iDims As Integer &apos; Array number of dimensions
+Dim lEmpty As Long &apos; Number of empty subarrays
+Dim i As Long
+Dim j As Long
+Const cstThisSub = &quot;Array.Flatten&quot;
+Const cstSubArgs = &quot;Array_1D&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vFlatten = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+
+Try:
+ If UBound(Array_1D) &gt;= LBound(Array_1D) Then
+ lMin = LBound(Array_1D) : lMax = UBound(Array_1D)
+ ReDim vFlatten(lMin To lMax) &apos; Initial minimal sizing
+ lEmpty = 0
+ lIndex = lMin - 1
+ For i = lMin To lMax
+ vItem = Array_1D(i)
+ If IsArray(vItem) Then
+ iDims = SF_Array.CountDims(vItem)
+ Select Case iDims
+ Case 0 &apos; Empty arrays are ignored
+ lEmpty = lEmpty + 1
+ Case 1 &apos; Only 1D subarrays are flattened
+ ReDim Preserve vFlatten(lMin To UBound(vFlatten) + UBound(vItem) - LBound(vItem))
+ For j = LBound(vItem) To UBound(vItem)
+ lIndex = lIndex + 1
+ vFlatten(lIndex) = vItem(j)
+ Next j
+ Case &gt; 1 &apos; Other arrays are left unchanged
+ lIndex = lIndex + 1
+ vFlatten(lIndex) = vItem
+ End Select
+ Else
+ lIndex = lIndex + 1
+ vFlatten(lIndex) = vItem
+ End If
+ Next i
+ End If
+ &apos; Reduce size of output if Array_1D is populated with some empty arrays
+ If lEmpty &gt; 0 Then
+ If lIndex - lEmpty &lt; lMin Then
+ vFlatten = Array()
+ Else
+ ReDim Preserve vFlatten(lMin To UBound(vFlatten) - lEmpty)
+ End If
+ End If
+
+Finally:
+ Flatten = vFlatten()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Flatten
+
+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;Array.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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; ScriptForge.SF_Array.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function ImportFromCSVFile(Optional ByRef FileName As Variant _
+ , Optional ByVal Delimiter As Variant _
+ , Optional ByVal DateFormat As Variant _
+ , Optional ByVal _IsoDate As Variant _
+ ) As Variant
+&apos;&apos;&apos; Import the data contained in a comma-separated values (CSV) file
+&apos;&apos;&apos; The comma may be replaced by any character
+&apos;&apos;&apos; Each line in the file contains a full record
+&apos;&apos;&apos; Line splitting is not allowed)
+&apos;&apos;&apos; However sequences like \n, \t, ... are left unchanged. Use SF_String.Unescape() to manage them
+&apos;&apos;&apos; A special mechanism is implemented to load dates
+&apos;&apos;&apos; The applicable CSV format is described in https://tools.ietf.org/html/rfc4180
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: the name of the text file containing the data expressed as given by the current FileNaming
+&apos;&apos;&apos; property of the SF_FileSystem service. Default = both URL format or native format
+&apos;&apos;&apos; Delimiter: Default = &quot;,&quot;. Other usual options are &quot;;&quot; and the tab character
+&apos;&apos;&apos; DateFormat: either YYYY-MM-DD, DD-MM-YYYY or MM-DD-YYYY
+&apos;&apos;&apos; The dash (-) may be replaced by a dot (.), a slash (/) or a space
+&apos;&apos;&apos; Other date formats will be ignored
+&apos;&apos;&apos; If &quot;&quot; (default), dates will be considered as strings
+&apos;&apos;&apos; _IsoDate: when True, the execution is initiated from Python, do not convert dates to Date variables. Internal use only
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A 2D-array with each row corresponding with a single record read in the file
+&apos;&apos;&apos; and each column corresponding with a field of the record
+&apos;&apos;&apos; No check is made about the coherence of the field types across columns
+&apos;&apos;&apos; A best guess will be made to identify numeric and date types
+&apos;&apos;&apos; If a line contains less or more fields than the first line in the file,
+&apos;&apos;&apos; an exception will be raised. Empty lines however are simply ignored
+&apos;&apos;&apos; If the size of the file exceeds the number of items limit, a warning is raised
+&apos;&apos;&apos; and the array is truncated
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; CSVPARSINGERROR Given file is not formatted as a csv file
+&apos;&apos;&apos; CSVOVERFLOWWARNING Maximum number of allowed items exceeded
+
+Dim vArray As Variant &apos; Returned array
+Dim lCol As Long &apos; Index of last column of vArray
+Dim lRow As Long &apos; Index of current row of vArray
+Dim lFileSize As Long &apos; Number of records found in the file
+Dim vCsv As Object &apos; CSV file handler
+Dim sLine As String &apos; Last read line
+Dim vLine As Variant &apos; Array of fields of last read line
+Dim sItem As String &apos; Individual item in the file
+Dim vItem As Variant &apos; Individual item in the output array
+Dim iPosition As Integer &apos; Date position in individual item
+Dim iYear As Integer, iMonth As Integer, iDay As Integer
+ &apos; Date components
+Dim i As Long
+Const cstItemsLimit = 250000 &apos; Maximum number of admitted items
+Const cstThisSub = &quot;Array.ImportFromCSVFile&quot;
+Const cstSubArgs = &quot;FileName, [Delimiter=&quot;&quot;,&quot;&quot;], [DateFormat=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vArray = Array()
+
+Check:
+ If IsMissing(Delimiter) Or IsEmpty(Delimiter) Then Delimiter = &quot;,&quot;
+ If IsMissing(DateFormat) Or IsEmpty(DateFormat) Then DateFormat = &quot;&quot;
+ If IsMissing(_IsoDate) Or IsEmpty(_IsoDate) Then _IsoDate = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Delimiter, &quot;Delimiter&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(DateFormat, &quot;DateFormat&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(Delimiter) = 0 Then Delimiter = &quot;,&quot;
+
+Try:
+ &apos; Counts the lines present in the file to size the final array
+ &apos; Very beneficial for large files, better than multiple ReDims
+ &apos; Small overhead for small files
+ lFileSize = SF_FileSystem._CountTextLines(FileName, False)
+ If lFileSize &lt;= 0 Then GoTo Finally
+
+ &apos; Reread file line by line
+ Set vCsv = SF_FileSystem.OpenTextFile(FileName, IOMode := SF_FileSystem.ForReading)
+ If IsNull(vCsv) Then GoTo Finally &apos; Open error
+ lRow = -1
+ With vCsv
+ Do While Not .AtEndOfStream
+ sLine = .ReadLine()
+ If Len(sLine) &gt; 0 Then &apos; Ignore empty lines
+ If InStr(sLine, &quot;&quot;&quot;&quot;) &gt; 0 Then vLine = SF_String.SplitNotQuoted(sLine, Delimiter) Else vLine = Split(sLine, Delimiter) &apos; Simple split when relevant
+ lRow = lRow + 1
+ If lRow = 0 Then &apos; Initial sizing of output array
+ lCol = UBound(vLine)
+ ReDim vArray(0 To lFileSize - 1, 0 To lCol)
+ ElseIf UBound(vLine) &lt;&gt; lCol Then
+ GoTo CatchCSVFormat
+ End If
+ &apos; Check type and copy all items of the line
+ For i = 0 To lCol
+ If Left(vLine(i), 1) = &quot;&quot;&quot;&quot; Then sItem = SF_String.Unquote(vLine(i)) Else sItem = vLine(i) &apos; Unquote only when useful
+ &apos; Interpret the individual line item
+ Select Case True
+ Case IsNumeric(sItem)
+ If InStr(sItem, &quot;.&quot;) + InStr(1, sItem, &quot;e&quot;, 1) &gt; 0 Then vItem = Val(sItem) Else vItem = CLng(sItem)
+ Case DateFormat &lt;&gt; &quot;&quot; And Len(sItem) = Len(DateFormat)
+ If SF_String.IsADate(sItem, DateFormat) Then
+ iPosition = InStr(DateFormat, &quot;YYYY&quot;) : iYear = CInt(Mid(sItem, iPosition, 4))
+ iPosition = InStr(DateFormat, &quot;MM&quot;) : iMonth = CInt(Mid(sItem, iPosition, 2))
+ iPosition = InStr(DateFormat, &quot;DD&quot;) : iDay = CInt(Mid(sItem, iPosition, 2))
+ vItem = DateSerial(iYear, iMonth, iDay)
+ If _IsoDate Then vItem = SF_Utils._CDateToIso(vItem) &apos; Called from Python
+ Else
+ vItem = sItem
+ End If
+ Case Else : vItem = sItem
+ End Select
+ vArray(lRow, i) = vItem
+ Next i
+ End If
+ &apos; Provision to avoid very large arrays and their sometimes erratic behaviour
+ If (lRow + 2) * (lCol + 1) &gt; cstItemsLimit Then
+ ReDim Preserve vArray(0 To lRow, 0 To lCol)
+ GoTo CatchOverflow
+ End If
+ Loop
+ End With
+
+Finally:
+ If Not IsNull(vCsv) Then
+ vCsv.CloseFile()
+ Set vCsv = vCsv.Dispose()
+ End If
+ ImportFromCSVFile = vArray
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchCSVFormat:
+ SF_Exception.RaiseFatal(CSVPARSINGERROR, FileName, vCsv.Line, sLine)
+ GoTo Finally
+CatchOverflow:
+ &apos;TODO SF_Exception.RaiseWarning(SF_Exception.CSVOVERFLOWWARNING, cstThisSub)
+ &apos;MsgBox &quot;TOO MUCH LINES !!&quot;
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.ImportFromCSVFile
+
+REM -----------------------------------------------------------------------------
+Public Function IndexOf(Optional ByRef Array_1D As Variant _
+ , Optional ByVal ToFind As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ , Optional ByVal SortOrder As Variant _
+ ) As Long
+&apos;&apos;&apos; Finds in a 1D array the ToFind number, string or date
+&apos;&apos;&apos; ToFind must exist within the array.
+&apos;&apos;&apos; The comparison between strings can be done case-sensitively or not
+&apos;&apos;&apos; If the array is sorted then
+&apos;&apos;&apos; the array must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; a binary search is done
+&apos;&apos;&apos; Otherwise the array is scanned from top. Null or Empty items are simply ignored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to scan
+&apos;&apos;&apos; ToFind: a number, a date or a string to find
+&apos;&apos;&apos; CaseSensitive: Only for string comparisons, default = False
+&apos;&apos;&apos; SortOrder: &quot;ASC&quot;, &quot;DESC&quot; or &quot;&quot; (= not sorted, default)
+&apos;&apos;&apos; Return: the index of the found item, LBound - 1 if not found
+&apos;&apos;&apos; Result is unpredictable when array is announced sorted and is in reality not
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.IndexOf(Array(&quot;A&quot;,&quot;B&quot;,&quot;c&quot;,&quot;D&quot;), &quot;C&quot;, SortOrder := &quot;ASC&quot;) returns 2
+&apos;&apos;&apos; SF_Array.IndexOf(Array(&quot;A&quot;,&quot;B&quot;,&quot;c&quot;,&quot;D&quot;), &quot;C&quot;, CaseSensitive := True) returns -1
+
+Dim vFindItem As Variant &apos; 2-items array (0) = True if found, (1) = Index where found
+Dim lIndex As Long &apos; Return value
+Dim iToFindType As Integer &apos; VarType of ToFind
+Const cstThisSub = &quot;Array.IndexOf&quot;
+Const cstSubArgs = &quot;Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;&quot;&quot;|&quot;&quot;ASC&quot;&quot;|&quot;&quot;DESC&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ lIndex = -1
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then SortOrder = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(SortOrder, &quot;SortOrder&quot;, V_STRING, Array(&quot;ASC&quot;, &quot;DESC&quot;, &quot;&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(ToFind, &quot;ToFind&quot;, Array(V_STRING, V_DATE, V_NUMERIC)) Then GoTo Finally
+ iToFindType = SF_Utils._VarTypeExt(ToFind)
+ If SortOrder &lt;&gt; &quot;&quot; Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array&quot;, 1, iToFindType) Then GoTo Finally
+ Else
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array&quot;, 1) Then GoTo Finally
+ End If
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ vFindItem = SF_Array._FindItem(Array_1D, ToFind, CaseSensitive, SortOrder)
+ If vFindItem(0) = True Then lIndex = vFindItem(1) Else lIndex = LBound(Array_1D) - 1
+
+Finally:
+ IndexOf = lIndex
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.IndexOf
+
+REM -----------------------------------------------------------------------------
+Public Function Insert(Optional ByRef Array_1D As Variant _
+ , Optional ByVal Before As Variant _
+ , ParamArray pvArgs() As Variant _
+ ) As Variant
+&apos;&apos;&apos; Insert before the index Before of the input array the items listed as arguments
+&apos;&apos;&apos; Arguments are inserted blindly
+&apos;&apos;&apos; each of them might be a scalar of any type or a subarray
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_1D: the pre-existing array, may be empty
+&apos;&apos;&apos; Before: the index before which to insert; must be in the interval [LBound, UBound + 1]
+&apos;&apos;&apos; pvArgs: a list of items to Insert inside Array_1D
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the new rxtended array. Its LBound is identical to that of Array_1D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINSERTERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Insert(Array(1, 2, 3), 2, 4, 5) returns (1, 2, 4, 5, 3)
+
+Dim vInsert As Variant &apos; Return value
+Dim lNbArgs As Long &apos; Number of elements to Insert
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim i As Long
+Const cstThisSub = &quot;Array.Insert&quot;
+Const cstSubArgs = &quot;Array_1D, Before, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vInsert = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ If Not SF_Utils._Validate(Before, &quot;Before&quot;, V_NUMERIC) Then GoTo Finally
+ If Before &lt; LBound(Array_1D) Or Before &gt; UBound(Array_1D) + 1 Then GoTo CatchArgument
+ End If
+
+Try:
+ lNbArgs = UBound(pvArgs) + 1 &apos; pvArgs is always zero-based
+ lMin = LBound(Array_1D) &apos; = LBound(vInsert)
+ lMax = UBound(Array_1D) &apos; &lt;&gt; UBound(vInsert)
+ If lNbArgs &gt; 0 Then
+ ReDim vInsert(lMin To lMax + lNbArgs)
+ For i = lMin To UBound(vInsert)
+ If i &lt; Before Then
+ vInsert(i) = Array_1D(i)
+ ElseIf i &lt; Before + lNbArgs Then
+ vInsert(i) = pvArgs(i - Before)
+ Else
+ vInsert(i) = Array_1D(i - lNbArgs)
+ End If
+ Next i
+ Else
+ vInsert() = Array_1D()
+ End If
+
+Finally:
+ Insert = vInsert()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchArgument:
+ &apos;TODO SF_Exception.RaiseFatal(ARRAYINSERTERROR, cstThisSub)
+ MsgBox &quot;INVALID ARGUMENT VALUE !!&quot;
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Insert
+
+REM -----------------------------------------------------------------------------
+Public Function InsertSorted(Optional ByRef Array_1D As Variant _
+ , Optional ByVal Item As Variant _
+ , Optional ByVal SortOrder As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Insert in a sorted array a new item on its place
+&apos;&apos;&apos; the array must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to sort
+&apos;&apos;&apos; Item: the scalar value to insert, same type as the existing array items
+&apos;&apos;&apos; SortOrder: &quot;ASC&quot; (default) or &quot;DESC&quot;
+&apos;&apos;&apos; CaseSensitive: Default = False
+&apos;&apos;&apos; Returns: the extended sorted array with same LBound as input array
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; InsertSorted(Array(&quot;A&quot;, &quot;C&quot;, &quot;a&quot;, &quot;b&quot;), &quot;B&quot;, CaseSensitive := True) returns (&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;a&quot;, &quot;b&quot;)
+
+Dim vSorted() As Variant &apos; Return value
+Dim iType As Integer &apos; VarType of elements in input array
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim lIndex As Long &apos; Place where to insert new item
+Const cstThisSub = &quot;Array.InsertSorted&quot;
+Const cstSubArgs = &quot;Array_1D, Item, [SortOrder=&quot;&quot;ASC&quot;&quot;|&quot;&quot;DESC&quot;&quot;], [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSorted = Array()
+
+Check:
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then SortOrder = &quot;ASC&quot;
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1, 0) Then GoTo Finally
+ If LBound(Array_1D) &lt;= UBound(Array_1D) Then
+ iType = SF_Utils._VarTypeExt(Array_1D(LBound(Array_1D)))
+ If Not SF_Utils._Validate(Item, &quot;Item&quot;, iType) Then GoTo Finally
+ Else
+ If Not SF_Utils._Validate(Item, &quot;Item&quot;, Array(V_STRING, V_DATE, V_NUMERIC)) Then GoTo Finally
+ End If
+ If Not SF_Utils._Validate(SortOrder, &quot;SortOrder&quot;, V_STRING, Array(&quot;ASC&quot;,&quot;DESC&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin = LBound(Array_1D)
+ lMax = UBound(Array_1D)
+ lIndex = SF_Array._FindItem(Array_1D, Item, CaseSensitive, SortOrder)(1)
+ vSorted = SF_Array.Insert(Array_1D, lIndex, Item)
+
+Finally:
+ InsertSorted = vSorted()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.InsertSorted
+
+REM -----------------------------------------------------------------------------
+Public Function Intersection(Optional ByRef Array1_1D As Variant _
+ , Optional ByRef Array2_1D As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Build a set being the intersection of the two input arrays, i.e. items are contained in both arrays
+&apos;&apos;&apos; both input arrays must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; The comparison between strings is case sensitive or not
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array1_1D: a 1st input array
+&apos;&apos;&apos; Array2_1D: a 2nd input array
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns: a zero-based array containing unique items stored in both input arrays
+&apos;&apos;&apos; The output array is sorted in ascending order
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Intersection(Array(&quot;A&quot;, &quot;C&quot;, &quot;A&quot;, &quot;b&quot;, &quot;B&quot;), Array(&quot;C&quot;, &quot;Z&quot;, &quot;b&quot;), True) returns (&quot;C&quot;, &quot;b&quot;)
+
+Dim vIntersection() As Variant &apos; Return value
+Dim vSorted() As Variant &apos; The shortest input array after sort
+Dim iType As Integer &apos; VarType of elements in input arrays
+Dim lMin1 As Long &apos; LBound of 1st input array
+Dim lMax1 As Long &apos; UBound of 1st input array
+Dim lMin2 As Long &apos; LBound of 2nd input array
+Dim lMax2 As Long &apos; UBound of 2nd input array
+Dim lMin As Long &apos; LBound of unsorted array
+Dim lMax As Long &apos; UBound of unsorted array
+Dim iShortest As Integer &apos; 1 or 2 depending on shortest input array
+Dim lSize As Long &apos; Number of Intersection items
+Dim vItem As Variant &apos; One single item in the array
+Dim i As Long
+Const cstThisSub = &quot;Array.Intersection&quot;
+Const cstSubArgs = &quot;Array1_1D, Array2_1D, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vIntersection = Array()
+
+Check:
+ If IsMissing(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array1_1D, &quot;Array1_1D&quot;, 1, 0, True) Then GoTo Finally
+ iType = SF_Utils._VarTypeExt(Array1_1D(LBound(Array1_1D)))
+ If Not SF_Utils._ValidateArray(Array2_1D, &quot;Array2_1D&quot;, 1, iType, True) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin1 = LBound(Array1_1D) : lMax1 = UBound(Array1_1D)
+ lMin2 = LBound(Array2_1D) : lMax2 = UBound(Array2_1D)
+
+ &apos; If one of both arrays is empty, do nothing
+ If lMax1 &gt;= lMin1 And lMax2 &gt;= lMin2 Then
+
+ &apos; First sort the shortest array
+ If lMax1 - lMin1 &lt;= lMax2 - lMin2 Then
+ iShortest = 1
+ vSorted = SF_Array.Sort(Array1_1D, &quot;ASC&quot;, CaseSensitive)
+ lMin = lMin2 : lMax = lMax2 &apos; Bounds of unsorted array
+ Else
+ iShortest = 2
+ vSorted = SF_Array.Sort(Array2_1D, &quot;ASC&quot;, CaseSensitive)
+ lMin = lMin1 : lMax = lMax1 &apos; Bounds of unsorted array
+ End If
+
+ &apos; Resize the output array to the size of the shortest array
+ ReDim vIntersection(0 To (lMax - lMin))
+ lSize = -1
+
+ &apos; Fill vIntersection one by one only with items present in both sets
+ For i = lMin To lMax
+ If iShortest = 1 Then vItem = Array2_1D(i) Else vItem = Array1_1D(i) &apos; Pick in unsorted array
+ If SF_Array.Contains(vSorted, vItem, CaseSensitive, &quot;ASC&quot;) Then
+ lSize = lSize + 1
+ vIntersection(lSize) = vItem
+ End If
+ Next i
+
+ &apos; Remove unfilled entries and duplicates
+ If lSize &gt;= 0 Then
+ ReDim Preserve vIntersection(0 To lSize)
+ vIntersection() = SF_Array.Unique(vIntersection, CaseSensitive)
+ Else
+ vIntersection = Array()
+ End If
+ End If
+
+Finally:
+ Intersection = vIntersection()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Intersection
+
+REM -----------------------------------------------------------------------------
+Public Function Join2D(Optional ByRef Array_2D As Variant _
+ , Optional ByVal ColumnDelimiter As Variant _
+ , Optional ByVal RowDelimiter As Variant _
+ , Optional ByVal Quote As Variant _
+ ) As String
+&apos;&apos;&apos; Join a two-dimensional array with two delimiters, one for columns, one for rows
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_2D: each item must be either a String, a number, a Date or a Boolean
+&apos;&apos;&apos; ColumnDelimiter: delimits each column (default = Tab/Chr(9))
+&apos;&apos;&apos; RowDelimiter: delimits each row (default = LineFeed/Chr(10))
+&apos;&apos;&apos; Quote: if True, protect strings with double quotes (default = False)
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; A string after conversion of numbers and dates
+&apos;&apos;&apos; Invalid items are replaced by a zero-length string
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; | 1, 2, &quot;A&quot;, [2020-02-29], 5 |
+&apos;&apos;&apos; SF_Array.Join_2D( | 6, 7, &quot;this is a string&quot;, 9, 10 | , &quot;,&quot;, &quot;/&quot;)
+&apos;&apos;&apos; &apos; &quot;1,2,A,2020-02-29 00:00:00,5/6,7,this is a string,9,10&quot;
+
+Dim sJoin As String &apos; The return value
+Dim sItem As String &apos; The string representation of a single item
+Dim vItem As Variant &apos; Single item
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim i As Long
+Dim j As Long
+Const cstThisSub = &quot;Array.Join2D&quot;
+Const cstSubArgs = &quot;Array_2D, [ColumnDelimiter=Chr(9)], [RowDelimiter=Chr(10)], [Quote=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sJoin = &quot;&quot;
+
+Check:
+ If IsMissing(ColumnDelimiter) Or IsEmpty(ColumnDelimiter) Then ColumnDelimiter = Chr(9)
+ If IsMissing(RowDelimiter) Or IsEmpty(RowDelimiter) Then RowDelimiter = Chr(10)
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally
+ If Not SF_Utils._Validate(ColumnDelimiter, &quot;ColumnDelimiter&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(RowDelimiter, &quot;RowDelimiter&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Quote, &quot;Quote&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ If lMin1 &lt;= lMax1 Then
+ For i = lMin1 To lMax1
+ For j = lMin2 To lMax2
+ vItem = Array_2D(i, j)
+ Select Case SF_Utils._VarTypeExt(vItem)
+ Case V_STRING : If Quote Then sItem = SF_String.Quote(vItem) Else sItem = vItem
+ Case V_NUMERIC, V_DATE : sItem = SF_Utils._Repr(vItem)
+ Case V_BOOLEAN : sItem = Iif(vItem, &quot;True&quot;, &quot;False&quot;) &apos;TODO: L10N
+ Case Else : sItem = &quot;&quot;
+ End Select
+ sJoin = sJoin &amp; sItem &amp; Iif(j &lt; lMax2, ColumnDelimiter, &quot;&quot;)
+ Next j
+ sJoin = sJoin &amp; Iif(i &lt; lMax1, RowDelimiter, &quot;&quot;)
+ Next i
+ End If
+
+Finally:
+ Join2D = sJoin
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Join2D
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Array service as an array
+
+ Methods = Array( _
+ &quot;Append&quot; _
+ , &quot;AppendColumn&quot; _
+ , &quot;AppendRow&quot; _
+ , &quot;Contains&quot; _
+ , &quot;ConvertToDictionary&quot; _
+ , &quot;CountDims&quot; _
+ , &quot;Difference&quot; _
+ , &quot;ExportToTextFile&quot; _
+ , &quot;ExtractColumn&quot; _
+ , &quot;ExtractRow&quot; _
+ , &quot;Flatten&quot; _
+ , &quot;ImportFromCSVFile&quot; _
+ , &quot;IndexOf&quot; _
+ , &quot;Insert&quot; _
+ , &quot;InsertSorted&quot; _
+ , &quot;Intersection&quot; _
+ , &quot;Join2D&quot; _
+ , &quot;Prepend&quot; _
+ , &quot;PrependColumn&quot; _
+ , &quot;PrependRow&quot; _
+ , &quot;RangeInit&quot; _
+ , &quot;Reverse&quot; _
+ , &quot;Shuffle&quot; _
+ , &quot;Sort&quot; _
+ , &quot;SortColumns&quot; _
+ , &quot;SortRows&quot; _
+ , &quot;Transpose&quot; _
+ , &quot;TrimArray&quot; _
+ , &quot;Union&quot; _
+ , &quot;Unique&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Array.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Prepend(Optional ByRef Array_1D As Variant _
+ , ParamArray pvArgs() As Variant _
+ ) As Variant
+&apos;&apos;&apos; Prepend at the beginning of the input array the items listed as arguments
+&apos;&apos;&apos; Arguments are Prepended blindly
+&apos;&apos;&apos; each of them might be a scalar of any type or a subarray
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_1D: the pre-existing array, may be empty
+&apos;&apos;&apos; pvArgs: a list of items to Prepend to Array_1D
+&apos;&apos;&apos; Return: the new rxtended array. Its LBound is identical to that of Array_1D
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Prepend(Array(1, 2, 3), 4, 5) returns (4, 5, 1, 2, 3)
+
+Dim vPrepend As Variant &apos; Return value
+Dim lNbArgs As Long &apos; Number of elements to Prepend
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim i As Long
+Const cstThisSub = &quot;Array.Prepend&quot;
+Const cstSubArgs = &quot;Array_1D, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vPrepend = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+
+Try:
+ lNbArgs = UBound(pvArgs) + 1 &apos; pvArgs is always zero-based
+ lMin = LBound(Array_1D) &apos; = LBound(vPrepend)
+ lMax = UBound(Array_1D) &apos; &lt;&gt; UBound(vPrepend)
+ If lMax &lt; LBound(Array_1D) And lNbArgs &gt; 0 Then &apos; Initial array is empty
+ ReDim vPrepend(0 To lNbArgs - 1)
+ Else
+ ReDim vPrepend(lMin To lMax + lNbArgs)
+ End If
+ For i = lMin To UBound(vPrepend)
+ If i &lt; lMin + lNbArgs Then vPrepend(i) = pvArgs(i - lMin) Else vPrepend(i) = Array_1D(i - lNbArgs)
+ Next i
+
+Finally:
+ Prepend = vPrepend
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Prepend
+
+REM -----------------------------------------------------------------------------
+Public Function PrependColumn(Optional ByRef Array_2D As Variant _
+ , Optional ByRef Column As Variant _
+ ) As Variant
+&apos;&apos;&apos; PrependColumn prepends to the left side of a 2D array a new Column
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_2D: the pre-existing array, may be empty
+&apos;&apos;&apos; If the array has 1 dimension, it is considered as the last Column of the resulting 2D array
+&apos;&apos;&apos; Column: a 1D array with as many items as there are rows in Array_2D
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the new rxtended array. Its LBounds are identical to that of Array_2D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINSERTERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.PrependColumn(Array(1, 2, 3), Array(4, 5, 6)) returns ((4, 1), (5, 2), (6, 3))
+&apos;&apos;&apos; x = SF_Array.PrependColumn(Array(), Array(1, 2, 3)) =&gt; ∀ i ∈ {0 ≤ i ≤ 2} : x(0, i) ≡ i
+
+Dim vPrependColumn As Variant &apos; Return value
+Dim iDims As Integer &apos; Dimensions of Array_2D
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim lMin As Long &apos; LBound of Column array
+Dim lMax As Long &apos; UBound of Column array
+Dim i As Long
+Dim j As Long
+Const cstThisSub = &quot;Array.PrependColumn&quot;
+Const cstSubArgs = &quot;Array_2D, Column&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vPrependColumn = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;) Then GoTo Finally &apos;Initial check: not missing and array
+ If Not SF_Utils._ValidateArray(Column, &quot;Column&quot;, 1) Then GoTo Finally
+ End If
+ iDims = SF_Array.CountDims(Array_2D)
+ If iDims &gt; 2 Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally &apos;2nd check to manage error
+ End If
+
+Try:
+ lMin = LBound(Column)
+ lMax = UBound(Column)
+
+ &apos; Compute future dimensions of output array
+ Select Case iDims
+ Case 0 : lMin1 = lMin : lMax1 = lMax
+ lMin2 = 0 : lMax2 = -1
+ Case 1 : lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = 0 : lMax2 = 0
+ Case 2 : lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ End Select
+ If iDims &gt; 0 And lMax - lMin &lt;&gt; lMax1 - lMin1 Then GoTo CatchColumn
+ ReDim vPrependColumn(lMin1 To lMax1, lMin2 To lMax2 + 1)
+
+ &apos; Copy input array to output array
+ For i = lMin1 To lMax1
+ For j = lMin2 + 1 To lMax2 + 1
+ If iDims = 2 Then vPrependColumn(i, j) = Array_2D(i, j - 1) Else vPrependColumn(i, j) = Array_2D(i)
+ Next j
+ Next i
+ &apos; Copy new Column
+ For i = lMin1 To lMax1
+ vPrependColumn(i, lMin2) = Column(i)
+ Next i
+
+Finally:
+ PrependColumn = vPrependColumn()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchColumn:
+ SF_Exception.RaiseFatal(ARRAYINSERTERROR, &quot;Column&quot;, SF_Array._Repr(Array_2D), SF_Utils._Repr(Column, MAXREPR))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.PrependColumn
+
+REM -----------------------------------------------------------------------------
+Public Function PrependRow(Optional ByRef Array_2D As Variant _
+ , Optional ByRef Row As Variant _
+ ) As Variant
+&apos;&apos;&apos; PrependRow prepends on top of a 2D array a new row
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Array_2D: the pre-existing array, may be empty
+&apos;&apos;&apos; If the array has 1 dimension, it is considered as the last row of the resulting 2D array
+&apos;&apos;&apos; Row: a 1D array with as many items as there are columns in Array_2D
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the new rxtended array. Its LBounds are identical to that of Array_2D
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINSERTERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.PrependRow(Array(1, 2, 3), Array(4, 5, 6)) returns ((4, 5, 6), (1, 2, 3))
+&apos;&apos;&apos; x = SF_Array.PrependColumn(Array(), Array(1, 2, 3) =&gt; ∀ i ∈ {0 ≤ i ≤ 2} : x(i, 0) ≡ i
+
+Dim vPrependRow As Variant &apos; Return value
+Dim iDims As Integer &apos; Dimensions of Array_2D
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim lMin As Long &apos; LBound of row array
+Dim lMax As Long &apos; UBound of row array
+Dim i As Long
+Dim j As Long
+Const cstThisSub = &quot;Array.PrependRow&quot;
+Const cstSubArgs = &quot;Array_2D, Row&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vPrependRow = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;) Then GoTo Finally &apos;Initial check: not missing and array
+ If Not SF_Utils._ValidateArray(Row, &quot;Row&quot;, 1) Then GoTo Finally
+ End If
+ iDims = SF_Array.CountDims(Array_2D)
+ If iDims &gt; 2 Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally &apos;2nd check to manage error
+ End If
+
+Try:
+ lMin = LBound(Row)
+ lMax = UBound(Row)
+
+ &apos; Compute future dimensions of output array
+ Select Case iDims
+ Case 0 : lMin1 = 0 : lMax1 = -1
+ lMin2 = lMin : lMax2 = lMax
+ Case 1 : lMin1 = 0 : lMax1 = 0
+ lMin2 = LBound(Array_2D, 1) : lMax2 = UBound(Array_2D, 1)
+ Case 2 : lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ End Select
+ If iDims &gt; 0 And lMax - lMin &lt;&gt; lMax2 - lMin2 Then GoTo CatchRow
+ ReDim vPrependRow(lMin1 To lMax1 + 1, lMin2 To lMax2)
+
+ &apos; Copy input array to output array
+ For i = lMin1 + 1 To lMax1 + 1
+ For j = lMin2 To lMax2
+ If iDims = 2 Then vPrependRow(i, j) = Array_2D(i - 1, j) Else vPrependRow(i, j) = Array_2D(j)
+ Next j
+ Next i
+ &apos; Copy new row
+ For j = lMin2 To lMax2
+ vPrependRow(lMin1, j) = Row(j)
+ Next j
+
+Finally:
+ PrependRow = vPrependRow()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchRow:
+ SF_Exception.RaiseFatal(ARRAYINSERTERROR, &quot;Row&quot;, SF_Array._Repr(Array_2D), SF_Utils._Repr(Row, MAXREPR))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.PrependRow
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties as an array
+
+ Properties = Array( _
+ )
+
+End Function &apos; ScriptForge.SF_Array.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function RangeInit(Optional ByVal From As Variant _
+ , Optional ByVal UpTo As Variant _
+ , Optional ByVal ByStep As Variant _
+ ) As Variant
+&apos;&apos;&apos; Initialize a new zero-based array with numeric values
+&apos;&apos;&apos; Args: all numeric
+&apos;&apos;&apos; From: value of first item
+&apos;&apos;&apos; UpTo: last item should not exceed UpTo
+&apos;&apos;&apos; ByStep: difference between 2 successive items
+&apos;&apos;&apos; Return: the new array
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYSEQUENCEERROR Wrong arguments, f.i. UpTo &lt; From with ByStep &gt; 0
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.RangeInit(10, 1, -1) returns (10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
+
+Dim lIndex As Long &apos; Index of array
+Dim lSize As Long &apos; UBound of resulting array
+Dim vCurrentItem As Variant &apos; Last stored item
+Dim vArray() &apos; The return value
+Const cstThisSub = &quot;Array.RangeInit&quot;
+Const cstSubArgs = &quot;From, UpTo, [ByStep = 1]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vArray = Array()
+
+Check:
+ If IsMissing(ByStep) Or IsEmpty(ByStep) Then ByStep = 1
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(From, &quot;From&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(UpTo, &quot;UpTo&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(ByStep, &quot;ByStep&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+ If (From &lt; UpTo And ByStep &lt;= 0) Or (From &gt; UpTo And ByStep &gt;= 0) Then GoTo CatchSequence
+
+Try:
+ lSize = CLng(Abs((UpTo - From) / ByStep))
+ ReDim vArray(0 To lSize)
+ For lIndex = 0 To lSize
+ vArray(lIndex) = From + lIndex * ByStep
+ Next lIndex
+
+Finally:
+ RangeInit = vArray
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchSequence:
+ SF_Exception.RaiseFatal(ARRAYSEQUENCEERROR, From, UpTo, ByStep)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.RangeInit
+
+REM -----------------------------------------------------------------------------
+Public Function Reverse(Optional ByRef Array_1D As Variant) As Variant
+&apos;&apos;&apos; Return the reversed 1D input array
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to reverse
+&apos;&apos;&apos; Returns: the reversed array
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Reverse(Array(1, 2, 3, 4)) returns (4, 3, 2, 1)
+
+Dim vReverse() As Variant &apos; Return value
+Dim lHalf As Long &apos; Middle of array
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim i As Long, j As Long
+Const cstThisSub = &quot;Array.Reverse&quot;
+Const cstSubArgs = &quot;Array_1D&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vReverse = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+
+Try:
+ lMin = LBound(Array_1D)
+ lMax = UBound(Array_1D)
+ ReDim vReverse(lMin To lMax)
+ lHalf = Int((lMax + lMin) / 2)
+ j = lMax
+ For i = lMin To lHalf
+ vReverse(i) = Array_1D(j)
+ vReverse(j) = Array_1D(i)
+ j = j - 1
+ Next i
+ &apos; Odd number of items
+ If IsEmpty(vReverse(lHalf + 1)) Then vReverse(lHalf + 1) = Array_1D(lHalf + 1)
+
+Finally:
+ Reverse = vReverse()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Reverse
+
+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;Array.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; ScriptForge.SF_Array.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Shuffle(Optional ByRef Array_1D As Variant) As Variant
+&apos;&apos;&apos; Returns a random permutation of a 1D array
+&apos;&apos;&apos; https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to shuffle
+&apos;&apos;&apos; Returns: the shuffled array
+
+Dim vShuffle() As Variant &apos; Return value
+Dim vSwapValue As Variant &apos; Intermediate value during swap
+Dim lMin As Long &apos; LBound of Array_1D
+Dim lCurrentIndex As Long &apos; Decremented from UBount to LBound
+Dim lRandomIndex As Long &apos; Random between LBound and lCurrentIndex
+Dim i As Long
+Const cstThisSub = &quot;Array.Shuffle&quot;
+Const cstSubArgs = &quot;Array_1D&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vShuffle = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+
+Try:
+ lMin = LBound(Array_1D)
+ lCurrentIndex = UBound(array_1D)
+ &apos; Initialize the output array
+ ReDim vShuffle(lMin To lCurrentIndex)
+ For i = lMin To lCurrentIndex
+ vShuffle(i) = Array_1D(i)
+ Next i
+ &apos; Now ... shuffle !
+ Do While lCurrentIndex &gt; lMin
+ lRandomIndex = Int(Rnd * (lCurrentIndex - lMin)) + lMin
+ vSwapValue = vShuffle(lCurrentIndex)
+ vShuffle(lCurrentIndex) = vShuffle(lRandomIndex)
+ vShuffle(lRandomIndex) = vSwapValue
+ lCurrentIndex = lCurrentIndex - 1
+ Loop
+
+Finally:
+ Shuffle = vShuffle()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Shuffle
+
+REM -----------------------------------------------------------------------------
+Public Function Slice(Optional ByRef Array_1D As Variant _
+ , Optional ByVal From As Variant _
+ , Optional ByVal UpTo As Variant _
+ ) As Variant
+&apos;&apos;&apos; Returns a subset of a 1D array
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to slice
+&apos;&apos;&apos; From: the lower index of the subarray to extract (included)
+&apos;&apos;&apos; UpTo: the upper index of the subarray to extract (included). Default = the last item of Array_1D
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The selected subarray with the same LBound as the input array.
+&apos;&apos;&apos; If UpTo &lt; From then the returned array is empty
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINDEX2ERROR Wrong values for From and/or UpTo
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; SF_Array.Slice(Array(1, 2, 3, 4, 5), 1, 3) returns (2, 3, 4)
+
+Dim vSlice() As Variant &apos; Return value
+Dim lMin As Long &apos; LBound of Array_1D
+Dim lIndex As Long &apos; Current index in output array
+Dim i As Long
+Const cstThisSub = &quot;Array.Slice&quot;
+Const cstSubArgs = &quot;Array_1D, From, [UpTo = UBound(Array_1D)]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSlice = Array()
+
+Check:
+ If IsMissing(UpTo) Or IsEmpty(UpTo) Then UpTo = -1
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ If Not SF_Utils._Validate(From, &quot;From&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(UpTo, &quot;UpTo&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+ If UpTo = -1 Then UpTo = UBound(Array_1D)
+ If From &lt; LBound(Array_1D) Or From &gt; UBound(Array_1D) _
+ Or From &gt; UpTo Or UpTo &gt; UBound(Array_1D) Then GoTo CatchIndex
+
+Try:
+ If UpTo &gt;= From Then
+ lMin = LBound(Array_1D)
+ &apos; Initialize the output array
+ ReDim vSlice(lMin To lMin + UpTo - From)
+ lIndex = lMin - 1
+ For i = From To UpTo
+ lIndex = lIndex + 1
+ vSlice(lIndex) = Array_1D(i)
+ Next i
+ End If
+
+Finally:
+ Slice = vSlice()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchIndex:
+ SF_Exception.RaiseFatal(ARRAYINDEX2ERROR, SF_Array._Repr(Array_1D), From, UpTo)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Slice
+
+REM -----------------------------------------------------------------------------
+Public Function Sort(Optional ByRef Array_1D As Variant _
+ , Optional ByVal SortOrder As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Sort a 1D array in ascending or descending order. String comparisons can be case-sensitive or not
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to sort
+&apos;&apos;&apos; must be filled homogeneously by either strings, dates or numbers
+&apos;&apos;&apos; Null and Empty values are allowed
+&apos;&apos;&apos; SortOrder: &quot;ASC&quot; (default) or &quot;DESC&quot;
+&apos;&apos;&apos; CaseSensitive: Default = False
+&apos;&apos;&apos; Returns: the sorted array
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Sort(Array(&quot;a&quot;, &quot;A&quot;, &quot;b&quot;, &quot;B&quot;, &quot;C&quot;), CaseSensitive := True) returns (&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;a&quot;, &quot;b&quot;)
+
+Dim vSort() As Variant &apos; Return value
+Dim vIndexes() As Variant &apos; Indexes of sorted items
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim i As Long
+Const cstThisSub = &quot;Array.Sort&quot;
+Const cstSubArgs = &quot;Array_1D, [SortOrder=&quot;&quot;&quot;&quot;|&quot;&quot;ASC&quot;&quot;|&quot;&quot;DESC&quot;&quot;], [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSort = Array()
+
+Check:
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then SortOrder = &quot;ASC&quot;
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1, 0) Then GoTo Finally
+ If Not SF_Utils._Validate(SortOrder, &quot;SortOrder&quot;, V_STRING, Array(&quot;ASC&quot;,&quot;DESC&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin = LBound(Array_1D)
+ lMax = UBound(Array_1D)
+ vIndexes() = SF_Array._HeapSort(Array_1D, ( SortOrder = &quot;ASC&quot; ), CaseSensitive)
+
+ &apos; Load output array
+ ReDim vSort(lMin To lMax)
+ For i = lMin To lMax
+ vSort(i) = Array_1D(vIndexes(i))
+ Next i
+
+Finally:
+ Sort = vSort()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Sort
+
+REM -----------------------------------------------------------------------------
+Public Function SortColumns(Optional ByRef Array_2D As Variant _
+ , Optional ByVal RowIndex As Variant _
+ , Optional ByVal SortOrder As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Returns a permutation of the columns of a 2D array, sorted on the values of a given row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_2D: the input array
+&apos;&apos;&apos; RowIndex: the index of the row to sort the columns on
+&apos;&apos;&apos; the row must be filled homogeneously by either strings, dates or numbers
+&apos;&apos;&apos; Null and Empty values are allowed
+&apos;&apos;&apos; SortOrder: &quot;ASC&quot; (default) or &quot;DESC&quot;
+&apos;&apos;&apos; CaseSensitive: Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the array with permuted columns, LBounds and UBounds are unchanged
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINDEXERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; | 5, 7, 3 | | 7, 5, 3 |
+&apos;&apos;&apos; SF_Array.SortColumns( | 1, 9, 5 |, 2, &quot;ASC&quot;) returns | 9, 1, 5 |
+&apos;&apos;&apos; | 6, 1, 8 | | 1, 6, 8 |
+
+Dim vSort() As Variant &apos; Return value
+Dim vRow() As Variant &apos; The row on which to sort the array
+Dim vIndexes() As Variant &apos; Indexes of sorted row
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim i As Long, j As Long
+Const cstThisSub = &quot;Array.SortColumn&quot;
+Const cstSubArgs = &quot;Array_2D, RowIndex, [SortOrder=&quot;&quot;&quot;&quot;|&quot;&quot;ASC&quot;&quot;|&quot;&quot;DESC&quot;&quot;], [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSort = Array()
+
+Check:
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then SortOrder = &quot;ASC&quot;
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally
+ If Not SF_Utils._Validate(RowIndex, &quot;RowIndex&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(SortOrder, &quot;SortOrder&quot;, V_STRING, Array(&quot;ASC&quot;,&quot;DESC&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ If RowIndex &lt; lMin1 Or RowIndex &gt; lMax1 Then GoTo CatchIndex
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+
+ &apos; Extract and sort the RowIndex-th row
+ vRow = SF_Array.ExtractRow(Array_2D, RowIndex)
+ If Not SF_Utils._ValidateArray(vRow, &quot;Row #&quot; &amp; CStr(RowIndex), 1, 0) Then GoTo Finally
+ vIndexes() = SF_Array._HeapSort(vRow, ( SortOrder = &quot;ASC&quot; ), CaseSensitive)
+
+ &apos; Load output array
+ ReDim vSort(lMin1 To lMax1, lMin2 To lMax2)
+ For i = lMin1 To lMax1
+ For j = lMin2 To lMax2
+ vSort(i, j) = Array_2D(i, vIndexes(j))
+ Next j
+ Next i
+
+Finally:
+ SortColumns = vSort()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchIndex:
+ &apos;TODO SF_Exception.RaiseFatal(ARRAYINDEXERROR, cstThisSub)
+ MsgBox &quot;INVALID INDEX VALUE !!&quot;
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.SortColumns
+
+REM -----------------------------------------------------------------------------
+Public Function SortRows(Optional ByRef Array_2D As Variant _
+ , Optional ByVal ColumnIndex As Variant _
+ , Optional ByVal SortOrder As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Returns a permutation of the rows of a 2D array, sorted on the values of a given column
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_2D: the input array
+&apos;&apos;&apos; ColumnIndex: the index of the column to sort the rows on
+&apos;&apos;&apos; the column must be filled homogeneously by either strings, dates or numbers
+&apos;&apos;&apos; Null and Empty values are allowed
+&apos;&apos;&apos; SortOrder: &quot;ASC&quot; (default) or &quot;DESC&quot;
+&apos;&apos;&apos; CaseSensitive: Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the array with permuted Rows, LBounds and UBounds are unchanged
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYINDEXERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; | 5, 7, 3 | | 1, 9, 5 |
+&apos;&apos;&apos; SF_Array.SortRows( | 1, 9, 5 |, 0, &quot;ASC&quot;) returns | 5, 7, 3 |
+&apos;&apos;&apos; | 6, 1, 8 | | 6, 1, 8 |
+
+Dim vSort() As Variant &apos; Return value
+Dim vCol() As Variant &apos; The column on which to sort the array
+Dim vIndexes() As Variant &apos; Indexes of sorted row
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim i As Long, j As Long
+Const cstThisSub = &quot;Array.SortRow&quot;
+Const cstSubArgs = &quot;Array_2D, ColumnIndex, [SortOrder=&quot;&quot;&quot;&quot;|&quot;&quot;ASC&quot;&quot;|&quot;&quot;DESC&quot;&quot;], [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSort = Array()
+
+Check:
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then SortOrder = &quot;ASC&quot;
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally
+ If Not SF_Utils._Validate(ColumnIndex, &quot;ColumnIndex&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(SortOrder, &quot;SortOrder&quot;, V_STRING, Array(&quot;ASC&quot;,&quot;DESC&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ If ColumnIndex &lt; lMin2 Or ColumnIndex &gt; lMax2 Then GoTo CatchIndex
+ lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+
+ &apos; Extract and sort the ColumnIndex-th column
+ vCol = SF_Array.ExtractColumn(Array_2D, ColumnIndex)
+ If Not SF_Utils._ValidateArray(vCol, &quot;Column #&quot; &amp; CStr(ColumnIndex), 1, 0) Then GoTo Finally
+ vIndexes() = SF_Array._HeapSort(vCol, ( SortOrder = &quot;ASC&quot; ), CaseSensitive)
+
+ &apos; Load output array
+ ReDim vSort(lMin1 To lMax1, lMin2 To lMax2)
+ For i = lMin1 To lMax1
+ For j = lMin2 To lMax2
+ vSort(i, j) = Array_2D(vIndexes(i), j)
+ Next j
+ Next i
+
+Finally:
+ SortRows = vSort()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchIndex:
+ &apos;TODO SF_Exception.RaiseFatal(ARRAYINDEXERROR, cstThisSub)
+ MsgBox &quot;INVALID INDEX VALUE !!&quot;
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.SortRows
+
+REM -----------------------------------------------------------------------------
+Public Function Transpose(Optional ByRef Array_2D As Variant) As Variant
+&apos;&apos;&apos; Swaps rows and columns in a 2D array
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_2D: the array to transpose
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The transposed array
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; | 1, 2 | | 1, 3, 5 |
+&apos;&apos;&apos; SF_Array.Transpose( | 3, 4 | ) returns | 2, 4, 6 |
+&apos;&apos;&apos; | 5, 6 |
+
+Dim vTranspose As Variant &apos; Return value
+Dim lIndex As Long &apos; vTranspose index
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim i As Long, j As Long
+Const cstThisSub = &quot;Array.Transpose&quot;
+Const cstSubArgs = &quot;Array_2D&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vTranspose = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_2D, &quot;Array_2D&quot;, 2) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Resize the output array
+ lMin1 = LBound(Array_2D, 1) : lMax1 = UBound(Array_2D, 1)
+ lMin2 = LBound(Array_2D, 2) : lMax2 = UBound(Array_2D, 2)
+ If lMin1 &lt;= lMax1 Then
+ ReDim vTranspose(lMin2 To lMax2, lMin1 To lMax1)
+ End If
+
+ &apos; Transpose items
+ For i = lMin1 To lMax1
+ For j = lMin2 To lMax2
+ vTranspose(j, i) = Array_2D(i, j)
+ Next j
+ Next i
+
+Finally:
+ Transpose = vTranspose
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Transpose
+
+REM -----------------------------------------------------------------------------
+Public Function TrimArray(Optional ByRef Array_1D As Variant) As Variant
+&apos;&apos;&apos; Remove from a 1D array all Null, Empty and zero-length entries
+&apos;&apos;&apos; Strings are trimmed as well
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the array to scan
+&apos;&apos;&apos; Return: The trimmed array
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.TrimArray(Array(&quot;A&quot;,&quot;B&quot;,Null,&quot; D &quot;)) returns (&quot;A&quot;,&quot;B&quot;,&quot;D&quot;)
+
+Dim vTrimArray As Variant &apos; Return value
+Dim lIndex As Long &apos; vTrimArray index
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim vItem As Variant &apos; Single array item
+Dim i As Long
+Const cstThisSub = &quot;Array.TrimArray&quot;
+Const cstSubArgs = &quot;Array_1D&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vTrimArray = Array()
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1) Then GoTo Finally
+ End If
+
+Try:
+ lMin = LBound(Array_1D)
+ lMax = UBound(Array_1D)
+ If lMin &lt;= lMax Then
+ ReDim vTrimArray(lMin To lMax)
+ End If
+ lIndex = lMin - 1
+
+ &apos; Load only valid items from Array_1D to vTrimArray
+ For i = lMin To lMax
+ vItem = Array_1D(i)
+ Select Case VarType(vItem)
+ Case V_EMPTY
+ Case V_NULL : vItem = Empty
+ Case V_STRING
+ vItem = Trim(vItem)
+ If Len(vItem) = 0 Then vItem = Empty
+ Case Else
+ End Select
+ If Not IsEmpty(vItem) Then
+ lIndex = lIndex + 1
+ vTrimArray(lIndex) = vItem
+ End If
+ Next i
+
+ &apos;Keep valid entries
+ If lMin &lt;= lIndex Then
+ ReDim Preserve vTrimArray(lMin To lIndex)
+ Else
+ vTrimArray = Array()
+ End If
+
+Finally:
+ TrimArray = vTrimArray
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.TrimArray
+
+REM -----------------------------------------------------------------------------
+Public Function Union(Optional ByRef Array1_1D As Variant _
+ , Optional ByRef Array2_1D As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Build a set being the Union of the two input arrays, i.e. items are contained in any of both arrays
+&apos;&apos;&apos; both input arrays must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; The comparison between strings is case sensitive or not
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array1_1D: a 1st input array
+&apos;&apos;&apos; Array2_1D: a 2nd input array
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns: a zero-based array containing unique items stored in any of both input arrays
+&apos;&apos;&apos; The output array is sorted in ascending order
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Array.Union(Array(&quot;A&quot;, &quot;C&quot;, &quot;A&quot;, &quot;b&quot;, &quot;B&quot;), Array(&quot;C&quot;, &quot;Z&quot;, &quot;b&quot;), True) returns (&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;Z&quot;, &quot;b&quot;)
+
+Dim vUnion() As Variant &apos; Return value
+Dim iType As Integer &apos; VarType of elements in input arrays
+Dim lMin1 As Long &apos; LBound of 1st input array
+Dim lMax1 As Long &apos; UBound of 1st input array
+Dim lMin2 As Long &apos; LBound of 2nd input array
+Dim lMax2 As Long &apos; UBound of 2nd input array
+Dim lSize As Long &apos; Number of Union items
+Dim i As Long
+Const cstThisSub = &quot;Array.Union&quot;
+Const cstSubArgs = &quot;Array1_1D, Array2_1D, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vUnion = Array()
+
+Check:
+ If IsMissing(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array1_1D, &quot;Array1_1D&quot;, 1, 0, True) Then GoTo Finally
+ iType = SF_Utils._VarTypeExt(Array1_1D(LBound(Array1_1D)))
+ If Not SF_Utils._ValidateArray(Array2_1D, &quot;Array2_1D&quot;, 1, iType, True) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin1 = LBound(Array1_1D) : lMax1 = UBound(Array1_1D)
+ lMin2 = LBound(Array2_1D) : lMax2 = UBound(Array2_1D)
+
+ &apos; If both arrays are empty, do nothing
+ If lMax1 &lt; lMin1 And lMax2 &lt; lMin2 Then
+ ElseIf lMax1 &lt; lMin1 Then &apos; only 1st array is empty
+ vUnion = SF_Array.Unique(Array2_1D, CaseSensitive)
+ ElseIf lMax2 &lt; lMin2 Then &apos; only 2nd array is empty
+ vUnion = SF_Array.Unique(Array1_1D, CaseSensitive)
+ Else
+
+ &apos; Build union of both arrays
+ ReDim vUnion(0 To (lMax1 - lMin1) + (lMax2 - lMin2) + 1)
+ lSize = -1
+
+ &apos; Fill vUnion one by one only with items present in any set
+ For i = lMin1 To lMax1
+ lSize = lSize + 1
+ vUnion(lSize) = Array1_1D(i)
+ Next i
+ For i = lMin2 To lMax2
+ lSize = lSize + 1
+ vUnion(lSize) = Array2_1D(i)
+ Next i
+
+ &apos; Remove duplicates
+ vUnion() = SF_Array.Unique(vUnion, CaseSensitive)
+ End If
+
+Finally:
+ Union = vUnion()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Union
+
+REM -----------------------------------------------------------------------------
+Public Function Unique(Optional ByRef Array_1D As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Variant
+&apos;&apos;&apos; Build a set of unique values derived from the input array
+&apos;&apos;&apos; the input array must be filled homogeneously, i.e. all items must be of the same type
+&apos;&apos;&apos; Empty and Null items are forbidden
+&apos;&apos;&apos; The comparison between strings is case sensitive or not
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Array_1D: the input array with potential duplicates
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns: the array without duplicates with same LBound as input array
+&apos;&apos;&apos; The output array is sorted in ascending order
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Unique(Array(&quot;A&quot;, &quot;C&quot;, &quot;A&quot;, &quot;b&quot;, &quot;B&quot;), True) returns (&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;b&quot;)
+
+Dim vUnique() As Variant &apos; Return value
+Dim vSorted() As Variant &apos; The input array after sort
+Dim lMin As Long &apos; LBound of input array
+Dim lMax As Long &apos; UBound of input array
+Dim lUnique As Long &apos; Number of unique items
+Dim vIndex As Variant &apos; Output of _FindItem() method
+Dim vItem As Variant &apos; One single item in the array
+Dim i As Long
+Const cstThisSub = &quot;Array.Unique&quot;
+Const cstSubArgs = &quot;Array_1D, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vUnique = Array()
+
+Check:
+ If IsMissing(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateArray(Array_1D, &quot;Array_1D&quot;, 1, 0, True) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lMin = LBound(Array_1D)
+ lMax = UBound(Array_1D)
+ If lMax &gt;= lMin Then
+ &apos; First sort the array
+ vSorted = SF_Array.Sort(Array_1D, &quot;ASC&quot;, CaseSensitive)
+ ReDim vUnique(lMin To lMax)
+ lUnique = lMin
+ &apos; Fill vUnique one by one ignoring duplicates
+ For i = lMin To lMax
+ vItem = vSorted(i)
+ If i = lMin Then
+ vUnique(i) = vItem
+ Else
+ If SF_Array._ValCompare(vItem, vSorted(i - 1), CaseSensitive) = 0 Then &apos; Ignore item
+ Else
+ lUnique = lUnique + 1
+ vUnique(lUnique) = vItem
+ End If
+ End If
+ Next i
+ &apos; Remove unfilled entries
+ ReDim Preserve vUnique(lMin To lUnique)
+ End If
+
+Finally:
+ Unique = vUnique()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Array.Unique
+
+REM ============================================================= PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function _FindItem(ByRef pvArray_1D As Variant _
+ , ByVal pvToFind As Variant _
+ , ByVal pbCaseSensitive As Boolean _
+ , ByVal psSortOrder As String _
+ ) As Variant
+&apos;&apos;&apos; Check if a 1D array contains the ToFind number, string or date and return its index
+&apos;&apos;&apos; The comparison between strings can be done case-sensitively or not
+&apos;&apos;&apos; If the array is sorted then a binary search is done
+&apos;&apos;&apos; Otherwise the array is scanned from top. Null or Empty items are simply ignored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArray_1D: the array to scan
+&apos;&apos;&apos; pvToFind: a number, a date or a string to find
+&apos;&apos;&apos; pbCaseSensitive: Only for string comparisons, default = False
+&apos;&apos;&apos; psSortOrder: &quot;ASC&quot;, &quot;DESC&quot; or &quot;&quot; (= not sorted, default)
+&apos;&apos;&apos; Return: a (0:1) array
+&apos;&apos;&apos; (0) = True when found
+&apos;&apos;&apos; (1) = if found: index of item
+&apos;&apos;&apos; if not found: if sorted, index of next item in the array (might be = UBound + 1)
+&apos;&apos;&apos; if not sorted, meaningless
+&apos;&apos;&apos; Result is unpredictable when array is announced sorted and is in reality not
+&apos;&apos;&apos; Called by Contains, IndexOf and InsertSorted. Also called by SF_Dictionary
+
+Dim bContains As Boolean &apos; True if match found
+Dim iToFindType As Integer &apos; VarType of pvToFind
+Dim lTop As Long, lBottom As Long &apos; Interval in scope of binary search
+Dim lIndex As Long &apos; Index used in search
+Dim iCompare As Integer &apos; Output of _ValCompare function
+Dim lLoops As Long &apos; Count binary searches
+Dim lMaxLoops As Long &apos; Max number of loops during binary search: to avoid infinite loops if array not sorted
+Dim vFound(1) As Variant &apos; Returned array (Contains, Index)
+
+ bContains = False
+
+ If LBound(pvArray_1D) &gt; UBound(pvArray_1D) Then &apos; Empty array, do nothing
+ Else
+ &apos; Search sequentially
+ If Len(psSortOrder) = 0 Then
+ For lIndex = LBound(pvArray_1D) To UBound(pvArray_1D)
+ bContains = ( SF_Array._ValCompare(pvToFind, pvArray_1D(lIndex), pbCaseSensitive) = 0 )
+ If bContains Then Exit For
+ Next lIndex
+ Else
+ &apos; Binary search
+ If psSortOrder = &quot;ASC&quot; Then
+ lTop = UBound(pvArray_1D)
+ lBottom = lBound(pvArray_1D)
+ Else
+ lBottom = UBound(pvArray_1D)
+ lTop = lBound(pvArray_1D)
+ End If
+ lLoops = 0
+ lMaxLoops = CLng((Log(UBound(pvArray_1D) - LBound(pvArray_1D) + 1.0) / Log(2.0))) + 1
+ Do
+ lLoops = lLoops + 1
+ lIndex = (lTop + lBottom) / 2
+ iCompare = SF_Array._ValCompare(pvToFind, pvArray_1D(lIndex), pbCaseSensitive)
+ Select Case True
+ Case iCompare = 0 : bContains = True
+ Case iCompare &lt; 0 And psSortOrder = &quot;ASC&quot;
+ lTop = lIndex - 1
+ Case iCompare &gt; 0 And psSortOrder = &quot;DESC&quot;
+ lBottom = lIndex - 1
+ Case iCompare &gt; 0 And psSortOrder = &quot;ASC&quot;
+ lBottom = lIndex + 1
+ Case iCompare &lt; 0 And psSortOrder = &quot;DESC&quot;
+ lTop = lIndex + 1
+ End Select
+ Loop Until ( bContains ) Or ( lBottom &gt; lTop And psSortOrder = &quot;ASC&quot; ) Or (lBottom &lt; lTop And psSortOrder = &quot;DESC&quot; ) Or lLoops &gt; lMaxLoops
+ &apos; Flag first next non-matching element
+ If Not bContains Then lIndex = Iif(psSortOrder = &quot;ASC&quot;, lBottom, lTop)
+ End If
+ End If
+
+ &apos; Build output array
+ vFound(0) = bContains
+ vFound(1) = lIndex
+ _FindItem = vFound
+
+End Function &apos; ScriptForge.SF_Array._FindItem
+
+REM -----------------------------------------------------------------------------
+Private Function _HeapSort(ByRef pvArray As Variant _
+ , Optional ByVal pbAscending As Boolean _
+ , Optional ByVal pbCaseSensitive As Boolean _
+ ) As Variant
+&apos;&apos;&apos; Sort an array: items are presumed all strings, all dates or all numeric
+&apos;&apos;&apos; Null or Empty are allowed and are considered smaller than other items
+&apos;&apos;&apos; https://en.wikipedia.org/wiki/Heapsort
+&apos;&apos;&apos; http://www.vbforums.com/showthread.php?473677-VB6-Sorting-algorithms-(sort-array-sorting-arrays)&amp;p=2909250#post2909250
+&apos;&apos;&apos; HeapSort preferred to QuickSort because not recursive (this routine returns an array of indexes !!)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArray: a 1D array
+&apos;&apos;&apos; pbAscending: default = True
+&apos;&apos;&apos; pbCaseSensitive: default = False
+&apos;&apos;&apos; Returns
+&apos;&apos;&apos; An array of Longs of same dimensions as the input array listing the indexes of the sorted items
+&apos;&apos;&apos; An empty array if the sort failed
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; _HeapSort(Array(4, 2, 6, 1) returns (3, 1, 0, 2)
+
+Dim vIndexes As Variant &apos; Return value
+Dim i As Long
+Dim lMin As Long, lMax As Long &apos; Array bounds
+Dim lSwap As Long &apos; For index swaps
+
+ If IsMissing(pbAscending) Then pbAscending = True
+ If IsMissing(pbCaseSensitive) Then pbCaseSensitive = False
+ vIndexes = Array()
+ lMin = LBound(pvArray, 1)
+ lMax = UBound(pvArray, 1)
+
+ &apos; Initialize output array
+ ReDim vIndexes(lMin To lMax)
+ For i = lMin To lMax
+ vIndexes(i) = i
+ Next i
+
+ &apos; Initial heapify
+ For i = (lMax + lMin) \ 2 To lMin Step -1
+ SF_Array._HeapSort1(pvArray, vIndexes, i, lMin, lMax, pbCaseSensitive)
+ Next i
+ &apos; Next heapify
+ For i = lMax To lMin + 1 Step -1
+ &apos; Only indexes as swapped, not the array items themselves
+ lSwap = vIndexes(i)
+ vIndexes(i) = vIndexes(lMin)
+ vIndexes(lMin) = lSwap
+ SF_Array._HeapSort1(pvArray, vIndexes, lMin, lMin, i - 1, pbCaseSensitive)
+ Next i
+
+ If pbAscending Then _HeapSort = vIndexes() Else _HeapSort = SF_Array.Reverse(vIndexes())
+
+End Function &apos; ScriptForge.SF_Array._HeapSort
+
+REM -----------------------------------------------------------------------------
+Private Sub _HeapSort1(ByRef pvArray As Variant _
+ , ByRef pvIndexes As Variant _
+ , ByVal plIndex As Long _
+ , ByVal plMin As Long _
+ , ByVal plMax As Long _
+ , ByVal pbCaseSensitive As Boolean _
+ )
+&apos;&apos;&apos; Sub called by _HeapSort only
+
+ Dim lLeaf As Long
+ Dim lSwap As Long
+
+ Do
+ lLeaf = plIndex + plIndex - (plMin - 1)
+ Select Case lLeaf
+ Case Is &gt; plMax: Exit Do
+ Case Is &lt; plMax
+ If SF_Array._ValCompare(pvArray(pvIndexes(lLeaf + 1)), pvArray(pvIndexes(lLeaf)), pbCaseSensitive) &gt; 0 Then lLeaf = lLeaf + 1
+ End Select
+ If SF_Array._ValCompare(pvArray(pvIndexes(plIndex)), pvArray(pvIndexes(lLeaf)), pbCaseSensitive) &gt; 0 Then Exit Do
+ &apos; Only indexes as swapped, not the array items themselves
+ lSwap = pvIndexes(plIndex)
+ pvIndexes(plIndex) = pvIndexes(lLeaf)
+ pvIndexes(lLeaf) = lSwap
+ plIndex = lLeaf
+ Loop
+
+End Sub &apos; ScriptForge.SF_Array._HeapSort1
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr(ByRef pvArray As Variant) As String
+&apos;&apos;&apos; Convert array to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArray: the array to convert, individual items may be of any type, including arrays
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[ARRAY] (L:U[, L:U]...)&quot; if # of Dims &gt; 1
+&apos;&apos;&apos; &quot;[ARRAY] (L:U) (item1,item2, ...)&quot; if 1D array
+
+Dim iDims As Integer &apos; Number of dimensions of the array
+Dim sArray As String &apos; Return value
+Dim i As Long
+Const cstArrayEmpty = &quot;[ARRAY] ()&quot;
+Const cstArray = &quot;[ARRAY]&quot;
+Const cstMaxLength = 50 &apos; Maximum length for items
+Const cstSeparator = &quot;, &quot;
+
+ _Repr = &quot;&quot;
+ iDims = SF_Array.CountDims(pvArray)
+
+ Select Case iDims
+ Case -1 : Exit Function &apos; Not an array
+ Case 0 : sArray = cstArrayEmpty
+ Case Else
+ sArray = cstArray
+ For i = 1 To iDims
+ sArray = sArray &amp; Iif(i = 1, &quot; (&quot;, &quot;, &quot;) &amp; CStr(LBound(pvArray, i)) &amp; &quot;:&quot; &amp; CStr(UBound(pvArray, i))
+ Next i
+ sArray = sArray &amp; &quot;)&quot;
+ &apos; List individual items of 1D arrays
+ If iDims = 1 Then
+ sArray = sArray &amp; &quot; (&quot;
+ For i = LBound(pvArray) To UBound(pvArray)
+ sArray = sArray &amp; SF_Utils._Repr(pvArray(i), cstMaxLength) &amp; cstSeparator &apos; Recursive call
+ Next i
+ sArray = Left(sArray, Len(sArray) - Len(cstSeparator)) &apos; Suppress last comma
+ sArray = sArray &amp; &quot;)&quot;
+ End If
+ End Select
+
+ _Repr = sArray
+
+End Function &apos; ScriptForge.SF_Array._Repr
+
+REM -----------------------------------------------------------------------------
+Public Function _StaticType(ByRef pvArray As Variant) As Integer
+&apos;&apos;&apos; If array is static, return its type
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArray: array to examine
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; array type, -1 if not identified
+&apos;&apos;&apos; All numeric types are aggregated into V_NUMERIC
+
+Dim iArrayType As Integer &apos; VarType of array
+Dim iType As Integer &apos; VarType of items
+
+ iArrayType = VarType(pvArray)
+ iType = iArrayType - V_ARRAY
+ Select Case iType
+ Case V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE, V_CURRENCY, V_BIGINT, V_DECIMAL, V_BOOLEAN
+ _StaticType = V_NUMERIC
+ Case V_STRING, V_DATE
+ _StaticType = iType
+ Case Else
+ _StaticType = -1
+ End Select
+
+End Function &apos; ScriptForge.SF_Utils._StaticType
+
+REM -----------------------------------------------------------------------------
+Private Function _ValCompare(ByVal pvValue1 As Variant _
+ , pvValue2 As Variant _
+ , Optional ByVal pbCaseSensitive As Boolean _
+ ) As Integer
+&apos;&apos;&apos; Compare 2 values : equality, greater than or smaller than
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvValue1 and pvValue2: values to compare. pvValues must be String, Number, Date, Empty or Null
+&apos;&apos;&apos; By convention: Empty &lt; Null &lt; string, number or date
+&apos;&apos;&apos; pbCaseSensitive: ignored when not String comparison
+&apos;&apos;&apos; Return: -1 when pvValue1 &lt; pvValue2
+&apos;&apos;&apos; +1 when pvValue1 &gt; pvValue2
+&apos;&apos;&apos; 0 when pvValue1 = pvValue2
+&apos;&apos;&apos; -2 when comparison is nonsense
+
+Dim iCompare As Integer, iVarType1 As Integer, iVarType2 As Integer
+
+ If IsMissing(pbCaseSensitive) Then pbCaseSensitive = False
+ iVarType1 = SF_Utils._VarTypeExt(pvValue1)
+ iVarType2 = SF_Utils._VarTypeExt(pvValue2)
+
+ iCompare = -2
+ If iVarType1 = V_OBJECT Or iVarType1 = V_BYTE Or iVarType1 &gt;= V_ARRAY Then &apos; Nonsense
+ ElseIf iVarType2 = V_OBJECT Or iVarType2 = V_BYTE Or iVarType2 &gt;= V_ARRAY Then &apos; Nonsense
+ ElseIf iVarType1 = V_STRING And iVarType2 = V_STRING Then
+ iCompare = StrComp(pvValue1, pvValue2, Iif(pbCaseSensitive, 1, 0))
+ ElseIf iVarType1 = V_NULL Or iVarType1 = V_EMPTY Or iVarType2 = V_NULL Or iVarType2 = V_EMPTY Then
+ Select Case True
+ Case pvValue1 = pvValue2 : iCompare = 0
+ Case iVarType1 = V_NULL And iVarType2 = V_EMPTY : iCompare = +1
+ Case iVarType1 = V_EMPTY And iVarType2 = V_NULL : iCompare = -1
+ Case iVarType1 = V_NULL Or iVarType1 = V_EMPTY : iCompare = -1
+ Case iVarType2 = V_NULL Or iVarType2 = V_EMPTY : iCompare = +1
+ End Select
+ ElseIf iVarType1 = iVarType2 Then
+ Select Case True
+ Case pvValue1 &lt; pvValue2 : iCompare = -1
+ Case pvValue1 = pvValue2 : iCompare = 0
+ Case pvValue1 &gt; pvValue2 : iCompare = +1
+ End Select
+ End If
+
+ _ValCompare = iCompare
+
+End Function &apos; ScriptForge.SF_Array._ValCompare
+
+REM ================================================= END OF SCRIPTFORGE.SF_ARRAY
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Dictionary.xba b/wizards/source/scriptforge/SF_Dictionary.xba
new file mode 100644
index 000000000..22ada5148
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Dictionary.xba
@@ -0,0 +1,959 @@
+<?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_Dictionary" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Dictionary
+&apos;&apos;&apos; =============
+&apos;&apos;&apos; Class for management of dictionaries
+&apos;&apos;&apos; A dictionary is a collection of key-item pairs
+&apos;&apos;&apos; The key is a not case-sensitive string
+&apos;&apos;&apos; Items may be of any type
+&apos;&apos;&apos; Keys, items can be retrieved, counted, etc.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The implementation is based on
+&apos;&apos;&apos; - one collection mapping keys and entries in the array
+&apos;&apos;&apos; - one 1-column array: key + data
+&apos;&apos;&apos;
+&apos;&apos;&apos; Why a Dictionary class beside the builtin Collection class ?
+&apos;&apos;&apos; A standard Basic collection does not support the retrieval of the keys
+&apos;&apos;&apos; Additionally it may contain only simple data (strings, numbers, ...)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service instantiation example:
+&apos;&apos;&apos; Dim myDict As Variant
+&apos;&apos;&apos; myDict = CreateScriptService(&quot;Dictionary&quot;) &apos; Once per dictionary
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_dictionary.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const DUPLICATEKEYERROR = &quot;DUPLICATEKEYERROR&quot; &apos; Key exists already
+Const UNKNOWNKEYERROR = &quot;UNKNOWNKEYERROR&quot; &apos; Key not found
+Const INVALIDKEYERROR = &quot;INVALIDKEYERROR&quot; &apos; Key contains only spaces
+
+REM ============================================================= PRIVATE MEMBERS
+
+&apos; Defines an entry in the MapItems array
+Type ItemMap
+ Key As String
+ Value As Variant
+End Type
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be &quot;DICTIONARY&quot;
+Private ServiceName As String
+Private MapKeys As Variant &apos; To retain the original keys
+Private MapItems As Variant &apos; Array of ItemMaps
+Private _MapSize As Long &apos; Total number of entries in the dictionary
+Private _MapRemoved As Long &apos; Number of inactive entries in the dictionary
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;DICTIONARY&quot;
+ ServiceName = &quot;ScriptForge.Dictionary&quot;
+ Set MapKeys = New Collection
+ Set MapItems = Array()
+ _MapSize = 0
+ _MapRemoved = 0
+End Sub &apos; ScriptForge.SF_Dictionary Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; ScriptForge.SF_Dictionary Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ RemoveAll()
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Dictionary Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Count() As Long
+&apos;&apos;&apos; Actual number of entries in the dictionary
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myDict.Count
+
+ Count = _PropertyGet(&quot;Count&quot;)
+
+End Property &apos; ScriptForge.SF_Dictionary.Count
+
+REM -----------------------------------------------------------------------------
+Public Function Item(Optional ByVal Key As Variant) As Variant
+&apos;&apos;&apos; Return the value of the item related to Key
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Key: the key value (string)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Empty if not found, otherwise the found value
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myDict.Item(&quot;ThisKey&quot;)
+&apos;&apos;&apos; NB: defined as a function to not disrupt the Basic IDE debugger
+
+ Item = _PropertyGet(&quot;Item&quot;, Key)
+
+End Function &apos; ScriptForge.SF_Dictionary.Item
+
+REM -----------------------------------------------------------------------------
+Property Get Items() as Variant
+&apos;&apos;&apos; Return the list of Items as a 1D array
+&apos;&apos;&apos; The Items and Keys properties return their respective contents in the same order
+&apos;&apos;&apos; The order is however not necessarily identical to the creation sequence
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The array is empty if the dictionary is empty
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; a = myDict.Items
+&apos;&apos;&apos; For Each b In a ...
+
+ Items = _PropertyGet(&quot;Items&quot;)
+
+End Property &apos; ScriptForge.SF_Dictionary.Items
+
+REM -----------------------------------------------------------------------------
+Property Get Keys() as Variant
+&apos;&apos;&apos; Return the list of keys as a 1D array
+&apos;&apos;&apos; The Keys and Items properties return their respective contents in the same order
+&apos;&apos;&apos; The order is however not necessarily identical to the creation sequence
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The array is empty if the dictionary is empty
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; a = myDict.Keys
+&apos;&apos;&apos; For each b In a ...
+
+ Keys = _PropertyGet(&quot;Keys&quot;)
+
+End Property &apos; ScriptForge.SF_Dictionary.Keys
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Add(Optional ByVal Key As Variant _
+ , Optional ByVal Item As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Add a new key-item pair into the dictionary
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Key: must not yet exist in the dictionary
+&apos;&apos;&apos; Item: any value, including an array, a Basic object, a UNO object, ...
+&apos;&apos;&apos; Returns: True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
+&apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDict.Add(&quot;NewKey&quot;, NewValue)
+
+Dim oItemMap As ItemMap &apos; New entry in the MapItems array
+Const cstThisSub = &quot;Dictionary.Add&quot;
+Const cstSubArgs = &quot;Key, Item&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Add = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
+ If IsArray(Item) Then
+ If Not SF_Utils._ValidateArray(Item, &quot;Item&quot;) Then GoTo Catch
+ Else
+ If Not SF_Utils._Validate(Item, &quot;Item&quot;) Then GoTo Catch
+ End If
+ End If
+ If Key = Space(Len(Key)) Then GoTo CatchInvalid
+ If Exists(Key) Then GoTo CatchDuplicate
+
+Try:
+ _MapSize = _MapSize + 1
+ MapKeys.Add(_MapSize, Key)
+ oItemMap.Key = Key
+ oItemMap.Value = Item
+ ReDim Preserve MapItems(1 To _MapSize)
+ MapItems(_MapSize) = oItemMap
+ Add = True
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchDuplicate:
+ SF_Exception.RaiseFatal(DUPLICATEKEYERROR, &quot;Key&quot;, Key)
+ GoTo Finally
+CatchInvalid:
+ SF_Exception.RaiseFatal(INVALIDKEYERROR, &quot;Key&quot;)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.Add
+
+REM -----------------------------------------------------------------------------
+Public Function ConvertToArray() As Variant
+&apos;&apos;&apos; Store the content of the dictionary in a 2-columns array:
+&apos;&apos;&apos; Key stored in 1st column, Item stored in 2nd
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a zero-based 2D array(0:Count - 1, 0:1)
+&apos;&apos;&apos; an empty array if the dictionary is empty
+
+Dim vArray As Variant &apos; Return value
+Dim sKey As String &apos; Tempry key
+Dim vKeys As Variant &apos; Array of keys
+Dim lCount As Long &apos; Counter
+Const cstThisSub = &quot;Dictionary.ConvertToArray&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ vArray = Array()
+ If Count = 0 Then
+ Else
+ ReDim vArray(0 To Count - 1, 0 To 1)
+ lCount = -1
+ vKeys = Keys
+ For Each sKey in vKeys
+ lCount = lCount + 1
+ vArray(lCount, 0) = sKey
+ vArray(lCount, 1) = Item(sKey)
+ Next sKey
+ End If
+
+Finally:
+ ConvertToArray = vArray()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ConvertToArray
+
+REM -----------------------------------------------------------------------------
+Public Function ConvertToJson(ByVal Optional Indent As Variant) As Variant
+&apos;&apos;&apos; Convert the content of the dictionary to a JSON string
+&apos;&apos;&apos; JSON = JavaScript Object Notation: https://en.wikipedia.org/wiki/JSON
+&apos;&apos;&apos; Limitations
+&apos;&apos;&apos; Allowed item types: String, Boolean, numbers, Null and Empty
+&apos;&apos;&apos; Arrays containing above types are allowed
+&apos;&apos;&apos; Dates are converted into strings (not within arrays)
+&apos;&apos;&apos; Other types are converted to their string representation (cfr. SF_String.Represent)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Indent:
+&apos;&apos;&apos; If indent is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level.
+&apos;&apos;&apos; An indent level &lt;= 0 will only insert newlines.
+&apos;&apos;&apos; &quot;&quot;, (the default) selects the most compact representation.
+&apos;&apos;&apos; Using a positive integer indent indents that many spaces per level.
+&apos;&apos;&apos; If indent is a string (such as Chr(9)), that string is used to indent each level.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the JSON string
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myDict.Add(&quot;p0&quot;, 12.5)
+&apos;&apos;&apos; myDict.Add(&quot;p1&quot;, &quot;a string àé&quot;&quot;ê&quot;)
+&apos;&apos;&apos; myDict.Add(&quot;p2&quot;, DateSerial(2020,9,28))
+&apos;&apos;&apos; myDict.Add(&quot;p3&quot;, True)
+&apos;&apos;&apos; myDict.Add(&quot;p4&quot;, Array(1,2,3))
+&apos;&apos;&apos; MsgBox a.ConvertToJson() &apos; {&quot;p0&quot;: 12.5, &quot;p1&quot;: &quot;a string \u00e0\u00e9\&quot;\u00ea&quot;, &quot;p2&quot;: &quot;2020-09-28&quot;, &quot;p3&quot;: true, &quot;p4&quot;: [1, 2, 3]}
+
+Dim sJson As String &apos; Return value
+Dim vArray As Variant &apos; Array of property values
+Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
+Dim sKey As String &apos; Tempry key
+Dim vKeys As Variant &apos; Array of keys
+Dim vItem As Variant &apos; Tempry item
+Dim iVarType As Integer &apos; Extended VarType
+Dim lCount As Long &apos; Counter
+Dim vIndent As Variant &apos; Python alias of Indent
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Dictionary__ConvertToJson&quot;
+
+Const cstThisSub = &quot;Dictionary.ConvertToJson&quot;
+Const cstSubArgs = &quot;[Indent=Null]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Indent) Or IsEmpty(INDENT) Then Indent = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Indent, &quot;Indent&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
+ End If
+ sJson = &quot;&quot;
+
+Try:
+ vArray = Array()
+ If Count = 0 Then
+ Else
+ ReDim vArray(0 To Count - 1)
+ lCount = -1
+ vKeys = Keys
+ For Each sKey in vKeys
+ &apos; Check item type
+ vItem = Item(sKey)
+ iVarType = SF_Utils._VarTypeExt(vItem)
+ Select Case iVarType
+ Case V_STRING, V_BOOLEAN, V_NUMERIC, V_NULL, V_EMPTY
+ Case V_DATE
+ vItem = SF_Utils._CDateToIso(vItem)
+ Case &gt;= V_ARRAY
+ Case Else
+ vItem = SF_Utils._Repr(vItem)
+ End Select
+ &apos; Build in each array entry a (Name, Value) pair
+ Set oPropertyValue = SF_Utils._MakePropertyValue(sKey, vItem)
+ lCount = lCount + 1
+ Set vArray(lCount) = oPropertyValue
+ Next sKey
+ End If
+
+ &apos;Pass array to Python script for the JSON conversion
+ With ScriptForge.SF_Session
+ vIndent = Indent
+ If VarType(Indent) = V_STRING Then
+ If Len(Indent) = 0 Then vIndent = Null
+ End If
+ sJson = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, vArray, vIndent)
+ End With
+
+Finally:
+ ConvertToJson = sJson
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ConvertToJson
+
+REM -----------------------------------------------------------------------------
+Public Function ConvertToPropertyValues() As Variant
+&apos;&apos;&apos; Store the content of the dictionary in an array of PropertyValues
+&apos;&apos;&apos; Key stored in Name, Item stored in Value
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a zero-based 1D array(0:Count - 1). Each entry is a com.sun.star.beans.PropertyValue
+&apos;&apos;&apos; Name: the key in the dictionary
+&apos;&apos;&apos; Value:
+&apos;&apos;&apos; Dates are converted to UNO dates
+&apos;&apos;&apos; Empty arrays are replaced by Null
+&apos;&apos;&apos; an empty array if the dictionary is empty
+
+Dim vArray As Variant &apos; Return value
+Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
+Dim sKey As String &apos; Tempry key
+Dim vKeys As Variant &apos; Array of keys
+Dim lCount As Long &apos; Counter
+Const cstThisSub = &quot;Dictionary.ConvertToPropertyValues&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ vArray = Array()
+ If Count = 0 Then
+ Else
+ ReDim vArray(0 To Count - 1)
+ lCount = -1
+ vKeys = Keys
+ For Each sKey in vKeys
+ &apos; Build in each array entry a (Name, Value) pair
+ Set oPropertyValue = SF_Utils._MakePropertyValue(sKey, Item(sKey))
+ lCount = lCount + 1
+ Set vArray(lCount) = oPropertyValue
+ Next sKey
+ End If
+
+Finally:
+ ConvertToPropertyValues = vArray()
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ConvertToPropertyValues
+
+REM -----------------------------------------------------------------------------
+Public Function Exists(Optional ByVal Key As Variant) As Boolean
+&apos;&apos;&apos; Determine if a key exists in the dictionary
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Key: the key value (string)
+&apos;&apos;&apos; Returns: True if key exists
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; If myDict.Exists(&quot;SomeKey&quot;) Then &apos; don&apos;t add again
+
+Dim vItem As Variant &apos; Item part in MapKeys
+Const cstThisSub = &quot;Dictionary.Exists&quot;
+Const cstSubArgs = &quot;Key&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Exists = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ &apos; Dirty but preferred to go through whole collection
+ On Local Error GoTo NotFound
+ vItem = MapKeys(Key)
+ NotFound:
+ Exists = ( Not ( Err = 5 ) And vItem &gt; 0 )
+ On Local Error GoTo 0
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.Exists
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant _
+ , Optional ByVal Key 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; Key: mandatory if PropertyName = &quot;Item&quot;, ignored otherwise
+&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
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDict.GetProperty(&quot;Count&quot;)
+
+Const cstThisSub = &quot;Dictionary.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, [Key]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+Check:
+ If IsMissing(Key) Or IsEmpty(Key) Then Key = &quot;&quot;
+ 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:
+ GetProperty = _PropertyGet(PropertyName, Key)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function ImportFromJson(Optional ByVal InputStr As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Adds the content of a Json string into the current dictionary
+&apos;&apos;&apos; JSON = JavaScript Object Notation: https://en.wikipedia.org/wiki/JSON
+&apos;&apos;&apos; Limitations
+&apos;&apos;&apos; The JSON string may contain numbers, strings, booleans, null values and arrays containing those types
+&apos;&apos;&apos; It must not contain JSON objects, i.e. sub-dictionaries
+&apos;&apos;&apos; An attempt is made to convert strings to dates if they fit one of next patterns:
+&apos;&apos;&apos; YYYY-MM-DD, HH:MM:SS or YYYY-MM-DD HH:MM:SS
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the json string to import
+&apos;&apos;&apos; Overwrite: when True entries with same name may exist in the dictionary and their values are overwritten
+&apos;&apos;&apos; Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
+&apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim s As String
+&apos;&apos;&apos; s = &quot;{&apos;firstName&apos;: &apos;John&apos;,&apos;lastName&apos;: &apos;Smith&apos;,&apos;isAlive&apos;: true,&apos;age&apos;: 66, &apos;birth&apos;: &apos;1954-09-28 20:15:00&apos;&quot; _
+&apos;&apos;&apos; &amp; &quot;,&apos;address&apos;: {&apos;streetAddress&apos;: &apos;21 2nd Street&apos;,&apos;city&apos;: &apos;New York&apos;,&apos;state&apos;: &apos;NY&apos;,&apos;postalCode&apos;: &apos;10021-3100&apos;}&quot; _
+&apos;&apos;&apos; &amp; &quot;,&apos;phoneNumbers&apos;: [{&apos;type&apos;: &apos;home&apos;,&apos;number&apos;: &apos;212 555-1234&apos;},{&apos;type&apos;: &apos;office&apos;,&apos;number&apos;: &apos;646 555-4567&apos;}]&quot; _
+&apos;&apos;&apos; &amp; &quot;,&apos;children&apos;: [&apos;Q&apos;,&apos;M&apos;,&apos;G&apos;,&apos;T&apos;],&apos;spouse&apos;: null}&quot;
+&apos;&apos;&apos; s = Replace(s, &quot;&apos;&quot;, &quot;&quot;&quot;&quot;)
+&apos;&apos;&apos; myDict.ImportFromJson(s, OverWrite := True)
+&apos;&apos;&apos; &apos; The (sub)-dictionaries &quot;address&quot; and &quot;phoneNumbers(0) and (1) are reduced to Empty
+
+Dim bImport As Boolean &apos; Return value
+Dim vArray As Variant &apos; JSON string converted to array
+Dim vArrayEntry As Variant &apos; A single entry in vArray
+Dim vKey As Variant &apos; Tempry key
+Dim vItem As Variant &apos; Tempry item
+Dim bExists As Boolean &apos; True when an entry exists
+Dim dDate As Date &apos; String converted to Date
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Dictionary__ImportFromJson&quot;
+
+Const cstThisSub = &quot;Dictionary.ImportFromJson&quot;
+Const cstSubArgs = &quot;InputStr, [Overwrite=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bImport = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoYo Finally
+ End If
+
+Try:
+ With ScriptForge.SF_Session
+ vArray = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, InputStr)
+ End With
+ If Not IsArray(vArray) Then GoTo Finally &apos; Conversion error or nothing to do
+
+ &apos; vArray = Array of subarrays = 2D DataArray (cfr. Calc)
+ For Each vArrayEntry In vArray
+ vKey = vArrayEntry(0)
+ If VarType(vKey) = V_STRING Then &apos; Else skip
+ vItem = vArrayEntry(1)
+ If Overwrite Then bExists = Exists(vKey) Else bExists = False
+ &apos; When the item matches a date pattern, convert it to a date
+ If VarType(vItem) = V_STRING Then
+ dDate = SF_Utils._CStrToDate(vItem)
+ If dDate &gt; -1 Then vItem = dDate
+ End If
+ If bExists Then
+ ReplaceItem(vKey, vItem)
+ Else
+ Add(vKey, vItem) &apos; Key controls are done in Add
+ End If
+ End If
+ Next vArrayEntry
+
+ bImport = True
+
+Finally:
+ ImportFromJson = bImport
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ImportFromJson
+
+REM -----------------------------------------------------------------------------
+Public Function ImportFromPropertyValues(Optional ByVal PropertyValues As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Adds the content of an array of PropertyValues into the current dictionary
+&apos;&apos;&apos; Names contain Keys, Values contain Items
+&apos;&apos;&apos; UNO dates are replaced by Basic dates
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyValues: a zero-based 1D array. Each entry is a com.sun.star.beans.PropertyValue
+&apos;&apos;&apos; Overwrite: when True entries with same name may exist in the dictionary and their values are overwritten
+&apos;&apos;&apos; Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
+&apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
+
+Dim bImport As Boolean &apos; Return value
+Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
+Dim vItem As Variant &apos; Tempry item
+Dim sObjectType As String &apos; UNO object type of dates
+Dim bExists As Boolean &apos; True when an entry exists
+Const cstThisSub = &quot;Dictionary.ImportFromPropertyValues&quot;
+Const cstSubArgs = &quot;PropertyValues, [Overwrite=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bImport = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If IsArray(PropertyValues) Then
+ If Not SF_Utils._ValidateArray(PropertyValues, &quot;PropertyValues&quot;, 1, V_OBJECT, True) Then GoTo Finally
+ Else
+ If Not SF_Utils._Validate(PropertyValues, &quot;PropertyValues&quot;, V_OBJECT) Then GoTo Finally
+ End If
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoYo Finally
+ End If
+
+Try:
+ If Not IsArray(PropertyValues) Then PropertyValues = Array(PropertyValues)
+ With oPropertyValue
+ For Each oPropertyValue In PropertyValues
+ If Overwrite Then bExists = Exists(.Name) Else bExists = False
+ If SF_Session.UnoObjectType(oPropertyValue) = &quot;com.sun.star.beans.PropertyValue&quot; Then
+ If IsUnoStruct(.Value) Then
+ sObjectType = SF_Session.UnoObjectType(.Value)
+ Select Case sObjectType
+ Case &quot;com.sun.star.util.DateTime&quot; : vItem = CDateFromUnoDateTime(.Value)
+ Case &quot;com.sun.star.util.Date&quot; : vItem = CDateFromUnoDate(.Value)
+ Case &quot;com.sun.star.util.Time&quot; : vItem = CDateFromUnoTime(.Value)
+ Case Else : vItem = .Value
+ End Select
+ Else
+ vItem = .Value
+ End If
+ If bExists Then
+ ReplaceItem(.Name, vItem)
+ Else
+ Add(.Name, vItem) &apos; Key controls are done in Add
+ End If
+ End If
+ Next oPropertyValue
+ End With
+ bImport = True
+
+Finally:
+ ImportFromPropertyValues = bImport
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ImportFromPropertyValues
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list or methods of the Dictionary class as an array
+
+ Methods = Array( _
+ &quot;Add&quot; _
+ , &quot;ConvertToArray&quot; _
+ , &quot;ConvertToJson&quot; _
+ , &quot;ConvertToPropertyValues&quot; _
+ , &quot;Exists&quot; _
+ , &quot;ImportFromJson&quot; _
+ , &quot;ImportFromPropertyValues&quot; _
+ , &quot;Remove&quot; _
+ , &quot;RemoveAll&quot; _
+ , &quot;ReplaceItem&quot; _
+ , &quot;ReplaceKey&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Dictionary.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Dictionary class as an array
+
+ Properties = Array( _
+ &quot;Count&quot; _
+ , &quot;Item&quot; _
+ , &quot;Items&quot; _
+ , &quot;Keys&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Dictionary.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Remove(Optional ByVal Key As Variant) As Boolean
+&apos;&apos;&apos; Remove an existing dictionary entry based on its key
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Key: must exist in the dictionary
+&apos;&apos;&apos; Returns: True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNKEYERROR: the key does not exist
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDict.Remove(&quot;OldKey&quot;)
+
+Dim lIndex As Long &apos; To remove entry in the MapItems array
+Const cstThisSub = &quot;Dictionary.Remove&quot;
+Const cstSubArgs = &quot;Key&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Remove = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
+ End If
+ If Not Exists(Key) Then GoTo CatchUnknown
+
+Try:
+ lIndex = MapKeys.Item(Key)
+ MapKeys.Remove(Key)
+ Erase MapItems(lIndex) &apos; Is now Empty
+ _MapRemoved = _MapRemoved + 1
+ Remove = True
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchUnknown:
+ SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.Remove
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveAll() As Boolean
+&apos;&apos;&apos; Remove all the entries from the dictionary
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns: True if successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDict.RemoveAll()
+
+Dim vKeys As Variant &apos; Array of keys
+Dim sColl As String &apos; A collection key in MapKeys
+Const cstThisSub = &quot;Dictionary.RemoveAll&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ RemoveAll = False
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ vKeys = Keys
+ For Each sColl In vKeys
+ MapKeys.Remove(sColl)
+ Next sColl
+ Erase MapKeys
+ Erase MapItems
+ &apos; Make dictionary ready to receive new entries
+ Call Class_Initialize()
+ RemoveAll = True
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.RemoveAll
+
+REM -----------------------------------------------------------------------------
+Public Function ReplaceItem(Optional ByVal Key As Variant _
+ , Optional ByVal Value As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Replace the item value
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Key: must exist in the dictionary
+&apos;&apos;&apos; Returns: True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNKEYERROR: the old key does not exist
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDict.ReplaceItem(&quot;Key&quot;, NewValue)
+
+Dim oItemMap As ItemMap &apos; Content to update in the MapItems array
+Dim lIndex As Long &apos; Entry in the MapItems array
+Const cstThisSub = &quot;Dictionary.ReplaceItem&quot;
+Const cstSubArgs = &quot;Key, Value&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ ReplaceItem = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
+ If IsArray(Value) Then
+ If Not SF_Utils._ValidateArray(Value, &quot;Value&quot;) Then GoTo Catch
+ Else
+ If Not SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Catch
+ End If
+ End If
+ If Not Exists(Key) Then GoTo CatchUnknown
+
+Try:
+ &apos; Find entry in MapItems and update it with the new value
+ lIndex = MapKeys.Item(Key)
+ oItemMap = MapItems(lIndex)
+ oItemMap.Value = Value
+ ReplaceItem = True
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchUnknown:
+ SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ReplaceItem
+
+REM -----------------------------------------------------------------------------
+Public Function ReplaceKey(Optional ByVal Key As Variant _
+ , Optional ByVal Value As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Replace existing key
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Key: must exist in the dictionary
+&apos;&apos;&apos; Value: must not exist in the dictionary
+&apos;&apos;&apos; Returns: True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNKEYERROR: the old key does not exist
+&apos;&apos;&apos; DUPLICATEKEYERROR: the new key exists
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDict.ReplaceKey(&quot;OldKey&quot;, &quot;NewKey&quot;)
+
+Dim oItemMap As ItemMap &apos; Content to update in the MapItems array
+Dim lIndex As Long &apos; Entry in the MapItems array
+Const cstThisSub = &quot;Dictionary.ReplaceKey&quot;
+Const cstSubArgs = &quot;Key, Value&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ ReplaceKey = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
+ If Not SF_Utils._Validate(Value, &quot;Value&quot;, V_STRING) Then GoTo Catch
+ End If
+ If Not Exists(Key) Then GoTo CatchUnknown
+ If Value = Space(Len(Value)) Then GoTo CatchInvalid
+ If Exists(Value) Then GoTo CatchDuplicate
+
+Try:
+ &apos; Remove the Key entry and create a new one in MapKeys
+ With MapKeys
+ lIndex = .Item(Key)
+ .Remove(Key)
+ .Add(lIndex, Value)
+ End With
+ oItemMap = MapItems(lIndex)
+ oItemMap.Key = Value
+ ReplaceKey = True
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchUnknown:
+ SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
+ GoTo Finally
+CatchDuplicate:
+ SF_Exception.RaiseFatal(DUPLICATEKEYERROR, &quot;Value&quot;, Value)
+ GoTo Finally
+CatchInvalid:
+ SF_Exception.RaiseFatal(INVALIDKEYERROR, &quot;Key&quot;)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary.ReplaceKey
+
+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;Dictionary.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; ScriptForge.SF_Dictionary.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String _
+ , Optional pvKey As Variant _
+ )
+&apos;&apos;&apos; Return the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+&apos;&apos;&apos; pvKey: the key to retrieve, numeric or string
+
+Dim vItemMap As Variant &apos; Entry in the MapItems array
+Dim vArray As Variant &apos; To get Keys or Values
+Dim i As Long
+Dim cstThisSub As String
+Dim cstSubArgs As String
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ cstThisSub = &quot;SF_Dictionary.get&quot; &amp; psProperty
+ If IsMissing(pvKey) Then cstSubArgs = &quot;&quot; Else cstSubArgs = &quot;[Key]&quot;
+
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Count&quot;)
+ _PropertyGet = _MapSize - _MapRemoved
+ Case UCase(&quot;Item&quot;)
+ If Not SF_Utils._Validate(pvKey, &quot;Key&quot;, V_STRING) Then GoTo Catch
+ If Exists(pvKey) Then _PropertyGet = MapItems(MapKeys(pvKey)).Value Else _PropertyGet = Empty
+ Case UCase(&quot;Keys&quot;), UCase(&quot;Items&quot;)
+ vArray = Array()
+ If _MapSize - _MapRemoved - 1 &gt;= 0 Then
+ ReDim vArray(0 To (_MapSize - _MapRemoved - 1))
+ i = -1
+ For each vItemMap In MapItems()
+ If Not IsEmpty(vItemMap) Then
+ i = i + 1
+ If UCase(psProperty) = &quot;KEYS&quot; Then vArray(i) = vItemMap.Key Else vArray(i) = vItemMap.Value
+ End If
+ Next vItemMap
+ End If
+ _PropertyGet = vArray
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Dictionary._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Dictionary instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Dictionary] (key1:value1, key2:value2, ...)
+
+Dim sDict As String &apos; Return value
+Dim vKeys As Variant &apos; Array of keys
+Dim sKey As String &apos; Tempry key
+Dim vItem As Variant &apos; Tempry item
+Const cstDictEmpty = &quot;[Dictionary] ()&quot;
+Const cstDict = &quot;[Dictionary]&quot;
+Const cstMaxLength = 50 &apos; Maximum length for items
+Const cstSeparator = &quot;, &quot;
+
+ _Repr = &quot;&quot;
+
+ If Count = 0 Then
+ sDict = cstDictEmpty
+ Else
+ sDict = cstDict &amp; &quot; (&quot;
+ vKeys = Keys
+ For Each sKey in vKeys
+ vItem = Item(sKey)
+ sDict = sDict &amp; sKey &amp; &quot;:&quot; &amp; SF_Utils._Repr(vItem, cstMaxLength) &amp; cstSeparator
+ Next sKey
+ sDict = Left(sDict, Len(sDict) - Len(cstSeparator)) &amp; &quot;)&quot; &apos; Suppress last comma
+ End If
+
+ _Repr = sDict
+
+End Function &apos; ScriptForge.SF_Dictionary._Repr
+
+REM ============================================ END OF SCRIPTFORGE.SF_DICTIONARY
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Exception.xba b/wizards/source/scriptforge/SF_Exception.xba
new file mode 100644
index 000000000..11e97b02b
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Exception.xba
@@ -0,0 +1,1381 @@
+<?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_Exception" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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; Exception (aka SF_Exception)
+&apos;&apos;&apos; =========
+&apos;&apos;&apos; Generic singleton class for Basic code debugging and error handling
+&apos;&apos;&apos;
+&apos;&apos;&apos; Errors may be generated by
+&apos;&apos;&apos; the Basic run-time error detection
+&apos;&apos;&apos; in the ScriptForge code =&gt; RaiseAbort()
+&apos;&apos;&apos; in a user code =&gt; Raise()
+&apos;&apos;&apos; an error detection implemented
+&apos;&apos;&apos; in the ScriptForge code =&gt; RaiseFatal()
+&apos;&apos;&apos; in a user code =&gt; Raise() or RaiseWarning()
+&apos;&apos;&apos;
+&apos;&apos;&apos; When a run-time error occurs, the properties of the Exception object are filled
+&apos;&apos;&apos; with information that uniquely identifies the error and information that can be used to handle it
+&apos;&apos;&apos; The SF_Exception object is in this context similar to the VBA Err object
+&apos;&apos;&apos; See https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/err-object
+&apos;&apos;&apos; The Number property identifies the error: it can be a numeric value or a string
+&apos;&apos;&apos; Numeric values up to 2000 are considered Basic run-time errors
+&apos;&apos;&apos;
+&apos;&apos;&apos; The &quot;console&quot; logs events, actual variable values, errors, ... It is an easy mean
+&apos;&apos;&apos; to debug Basic programs especially when the IDE is not usable, f.i. in Calc user defined functions
+&apos;&apos;&apos; or during control events processing
+&apos;&apos;&apos; =&gt; DebugPrint()
+&apos;&apos;&apos;
+&apos;&apos;&apos; The usual behaviour of the application when an error occurs is:
+&apos;&apos;&apos; 1. Log the error in the console
+&apos;&apos;&apos; 2, Inform the user about the error with either a standard or a customized message
+&apos;&apos;&apos; 3. Optionally, stop the execution of the current macro
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_exception.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+&apos; SF_Utils
+Const MISSINGARGERROR = &quot;MISSINGARGERROR&quot;
+Const ARGUMENTERROR = &quot;ARGUMENTERROR&quot;
+Const ARRAYERROR = &quot;ARRAYERROR&quot;
+Const FILEERROR = &quot;FILEERROR&quot;
+
+&apos; SF_Array
+Const ARRAYSEQUENCEERROR = &quot;ARRAYSEQUENCEERROR&quot;
+Const ARRAYINSERTERROR = &quot;ARRAYINSERTERROR&quot;
+Const ARRAYINDEX1ERROR = &quot;ARRAYINDEX1ERROR&quot;
+Const ARRAYINDEX2ERROR = &quot;ARRAYINDEX2ERROR&quot;
+Const CSVPARSINGERROR = &quot;CSVPARSINGERROR&quot;
+Const CSVOVERFLOWWARNING = &quot;CSVOVERFLOWWARNING&quot;
+
+&apos; SF_Dictionary
+Const DUPLICATEKEYERROR = &quot;DUPLICATEKEYERROR&quot;
+Const UNKNOWNKEYERROR = &quot;UNKNOWNKEYERROR&quot;
+Const INVALIDKEYERROR = &quot;INVALIDKEYERROR&quot;
+
+&apos; SF_FileSystem
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot;
+Const UNKNOWNFOLDERERROR = &quot;UNKNOWNFOLDERERROR&quot;
+Const NOTAFILEERROR = &quot;NOTAFILEERROR&quot;
+Const NOTAFOLDERERROR = &quot;NOTAFOLDERERROR&quot;
+Const OVERWRITEERROR = &quot;OVERWRITEERROR&quot;
+Const READONLYERROR = &quot;READONLYERROR&quot;
+Const NOFILEMATCHERROR = &quot;NOFILEMATCHFOUND&quot;
+Const FOLDERCREATIONERROR = &quot;FOLDERCREATIONERROR&quot;
+
+&apos; SF_Services
+Const UNKNOWNSERVICEERROR = &quot;UNKNOWNSERVICEERROR&quot;
+Const SERVICESNOTLOADEDERROR = &quot;SERVICESNOTLOADEDERROR&quot;
+
+&apos; SF_Session
+Const CALCFUNCERROR = &quot;CALCFUNCERROR&quot;
+Const NOSCRIPTERROR = &quot;NOSCRIPTERROR&quot;
+Const SCRIPTEXECERROR = &quot;SCRIPTEXECERROR&quot;
+Const WRONGEMAILERROR = &quot;WRONGEMAILERROR&quot;
+Const SENDMAILERROR = &quot;SENDMAILERROR&quot;
+
+&apos; SF_TextStream
+Const FILENOTOPENERROR = &quot;FILENOTOPENERROR&quot;
+Const FILEOPENMODEERROR = &quot;FILEOPENMODEERROR&quot;
+Const ENDOFFILEERROR = &quot;ENDOFFILEERROR&quot;
+
+&apos; SF_UI
+Const DOCUMENTERROR = &quot;DOCUMENTERROR&quot;
+Const DOCUMENTCREATIONERROR = &quot;DOCUMENTCREATIONERROR&quot;
+Const DOCUMENTOPENERROR = &quot;DOCUMENTOPENERROR&quot;
+Const BASEDOCUMENTOPENERROR = &quot;BASEDOCUMENTOPENERROR&quot;
+
+&apos; SF_Document
+Const DOCUMENTDEADERROR = &quot;DOCUMENTDEADERROR&quot;
+Const DOCUMENTSAVEERROR = &quot;DOCUMENTSAVEERROR&quot;
+Const DOCUMENTSAVEASERROR = &quot;DOCUMENTSAVEASERROR&quot;
+Const DOCUMENTREADONLYERROR = &quot;DOCUMENTREADONLYERROR&quot;
+Const DBCONNECTERROR = &quot;DBCONNECTERROR&quot;
+
+&apos; SF_Calc
+Const CALCADDRESSERROR = &quot;CALCADDRESSERROR&quot;
+Const DUPLICATESHEETERROR = &quot;DUPLICATESHEETERROR&quot;
+Const OFFSETADDRESSERROR = &quot;OFFSETADDRESSERROR&quot;
+Const DUPLICATECHARTERROR = &quot;DUPLICATECHARTERROR&quot;
+Const RANGEEXPORTERROR = &quot;RANGEEXPORTERROR&quot;
+
+&apos; SF_Chart
+Const CHARTEXPORTERROR = &quot;CHARTEXPORTERROR&quot;
+
+&apos; SF_Form
+Const FORMDEADERROR = &quot;FORMDEADERROR&quot;
+Const CALCFORMNOTFOUNDERROR = &quot;CALCFORMNOTFOUNDERROR&quot;
+Const WRITERFORMNOTFOUNDERROR = &quot;WRITERFORMNOTFOUNDERROR&quot;
+Const BASEFORMNOTFOUNDERROR = &quot;BASEFORMNOTFOUNDERROR&quot;
+Const SUBFORMNOTFOUNDERROR = &quot;SUBFORMNOTFOUNDERROR&quot;
+Const FORMCONTROLTYPEERROR = &quot;FORMCONTROLTYPEERROR&quot;
+
+&apos; SF_Dialog
+Const DIALOGNOTFOUNDERROR = &quot;DIALOGNOTFOUNDERROR&quot;
+Const DIALOGDEADERROR = &quot;DIALOGDEADERROR&quot;
+Const CONTROLTYPEERROR = &quot;CONTROLTYPEERROR&quot;
+Const TEXTFIELDERROR = &quot;TEXTFIELDERROR&quot;
+
+&apos; SF_Database
+Const DBREADONLYERROR = &quot;DBREADONLYERROR&quot;
+Const SQLSYNTAXERROR = &quot;SQLSYNTAXERROR&quot;
+
+&apos; Python
+Const PYTHONSHELLERROR = &quot;PYTHONSHELLERROR&quot;
+
+&apos; SF_UnitTest
+Const UNITTESTLIBRARYERROR = &quot;UNITTESTLIBRARYERROR&quot;
+Const UNITTESTMETHODERROR = &quot;UNITTESTMETHODERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+&apos; User defined errors
+Private _Number As Variant &apos; Error number/code (Integer or String)
+Private _Source As Variant &apos; Where the error occurred: a module, a Sub/Function, ...
+Private _Description As String &apos; The error message
+
+&apos; System run-time errors
+Private _SysNumber As Long &apos; Alias of Err
+Private _SysSource As Long &apos; Alias of Erl
+Private _SysDescription As String &apos; Alias of Error$
+
+REM ============================================================ MODULE CONSTANTS
+
+Const RUNTIMEERRORS = 2000 &apos; Upper limit of Basic run-time errors
+Const CONSOLENAME = &quot;ConsoleLines&quot; &apos; Name of control in the console dialog
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Exception Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Description() As Variant
+&apos;&apos;&apos; Returns the description of the last error that has occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myException.Description
+ Description = _PropertyGet(&quot;Description&quot;)
+End Property &apos; ScriptForge.SF_Exception.Description (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Description(ByVal pvDescription As Variant)
+&apos;&apos;&apos; Set the description of the last error that has occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myException.Description = &quot;Not smart to divide by zero&quot;
+ _PropertySet &quot;Description&quot;, pvDescription
+End Property &apos; ScriptForge.SF_Exception.Description (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Number() As Variant
+&apos;&apos;&apos; Returns the code of the last error that has occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myException.Number
+ Number = _PropertyGet(&quot;Number&quot;)
+End Property &apos; ScriptForge.SF_Exception.Number (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Number(ByVal pvNumber As Variant)
+&apos;&apos;&apos; Set the code of the last error that has occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myException.Number = 11 &apos; Division by 0
+ _PropertySet &quot;Number&quot;, pvNumber
+End Property &apos; ScriptForge.SF_Exception.Number (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Source() As Variant
+&apos;&apos;&apos; Returns the location of the last error that has occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myException.Source
+ Source = _PropertyGet(&quot;Source&quot;)
+End Property &apos; ScriptForge.SF_Exception.Source (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Source(ByVal pvSource As Variant)
+&apos;&apos;&apos; Set the location of the last error that has occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myException.Source = 123 &apos; Line # 123. Source may also be a string
+ _PropertySet &quot;Source&quot;, pvSource
+End Property &apos; ScriptForge.SF_Exception.Source (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_Exception&quot;
+End Property &apos; ScriptForge.SF_String.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.Exception&quot;
+End Property &apos; ScriptForge.SF_Exception.ServiceName
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Sub Clear()
+&apos;&apos;&apos; Reset the current error status and clear the SF_Exception object
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; On Local Error GoTo Catch
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; Catch:
+&apos;&apos;&apos; SF_Exception.Clear() &apos; Deny the error
+
+Const cstThisSub = &quot;Exception.Clear&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+
+Try:
+ With SF_Exception
+ ._Number = Empty
+ ._Source = Empty
+ ._Description = &quot;&quot;
+ ._SysNumber = 0
+ ._SysSource = 0
+ ._SysDescription = &quot;&quot;
+ End With
+
+Finally:
+ On Error GoTo 0
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Exception.Clear
+
+REM -----------------------------------------------------------------------------
+Public Sub Console(Optional ByVal Modal As Variant, _
+ Optional ByRef _Context As Variant _
+ )
+&apos;&apos;&apos; Display the console messages in a modal or non-modal dialog
+&apos;&apos;&apos; If the dialog is already active, when non-modal, it is brought to front
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Modal: Boolean. Default = True
+&apos;&apos;&apos; _Context: From Python, the XComponentXontext (FOR INTERNAL USE ONLY)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; SF_Exception.Console()
+
+Dim bConsoleActive As Boolean &apos; When True, dialog is active
+Dim oModalBtn As Object &apos; Modal close button
+Dim oNonModalBtn As Object &apos; Non modal close button
+Const cstThisSub = &quot;Exception.Console&quot;
+Const cstSubArgs = &quot;[Modal=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Finally &apos; Never interrupt processing
+
+Check:
+ If IsMissing(Modal) Or IsEmpty(Modal) Then Modal = True
+ If IsMissing(_Context) Or IsEmpty(_Context) Then _Context = Nothing
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Modal, &quot;Modal&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ With _SF_
+ bConsoleActive = False
+ If Not IsNull(.ConsoleDialog) Then bConsoleActive = .ConsoleDialog._IsStillAlive(False) &apos; False to not raise an error
+ If bConsoleActive And Modal = False Then
+ &apos; Bring to front
+ .ConsoleDialog.Activate()
+ Else
+ &apos; Initialize dialog and fill with actual data
+ &apos; The dual modes (modal and non-modal) require to have 2 close buttons o/w only 1 is visible
+ &apos; - a usual OK button
+ &apos; - a Default button triggering the Close action
+ Set .ConsoleDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, &quot;GlobalScope&quot;, &quot;ScriptForge&quot;, &quot;dlgConsole&quot;, _Context)
+ &apos; Setup labels and visibility
+ Set oModalBtn = .ConsoleDialog.Controls(&quot;CloseModalButton&quot;)
+ Set oNonModalBtn = .ConsoleDialog.Controls(&quot;CloseNonModalButton&quot;)
+ oModalBtn.Visible = Modal
+ oNonModalBtn.Visible = CBool(Not Modal)
+ &apos; Load console lines
+ _ConsoleRefresh()
+ .ConsoleDialog.Execute(Modal)
+ &apos; Terminate the modal dialog
+ If Modal Then
+ Set .ConsoleControl = .ConsoleControl.Dispose()
+ Set .ConsoleDialog = .ConsoleDialog.Dispose()
+ End If
+ End If
+ End With
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception.Console
+
+REM -----------------------------------------------------------------------------
+Public Sub ConsoleClear(Optional ByVal Keep)
+&apos;&apos;&apos; Clear the console keeping an optional number of recent messages
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Keep: the number of messages to keep
+&apos;&apos;&apos; If Keep is bigger than the number of messages stored in the console,
+&apos;&apos;&apos; the console is not cleared
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; SF_Exception.ConsoleClear(5)
+
+Dim lConsole As Long &apos; UBound of ConsoleLines
+Const cstThisSub = &quot;Exception.ConsoleClear&quot;
+Const cstSubArgs = &quot;[Keep=0]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Finally &apos; Never interrupt processing
+
+Check:
+ If IsMissing(Keep) Or IsEmpty(Keep) Then Keep = 0
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Keep, &quot;Keep&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ With _SF_
+ If Keep &lt;= 0 Then
+ .ConsoleLines = Array()
+ Else
+ lConsole = UBound(.ConsoleLines)
+ If Keep &lt; lConsole + 1 Then .ConsoleLines = SF_Array.Slice(.ConsoleLines, lConsole - Keep + 1)
+ End If
+ End With
+
+ &apos; If active, the console dialog needs to be refreshed
+ _ConsoleRefresh()
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception.ConsoleClear
+
+REM -----------------------------------------------------------------------------
+Public Function ConsoleToFile(Optional ByVal FileName As Variant) As Boolean
+&apos;&apos;&apos; Export the content of the console to a text file
+&apos;&apos;&apos; If the file exists and the console is not empty, it is overwritten without warning
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: the complete file name to export to. If it exists, is overwritten without warning
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the file could be created
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Exception.ConsoleToFile(&quot;myFile.txt&quot;)
+
+Dim bExport As Boolean &apos; Return value
+Dim oFile As Object &apos; Output file handler
+Dim sLine As String &apos; A single line
+Const cstThisSub = &quot;Exception.ConsoleToFile&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExport = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+
+ If UBound(_SF_.ConsoleLines) &gt; -1 Then
+ Set oFile = SF_FileSystem.CreateTextFile(FileName, Overwrite := True)
+ If Not IsNull(oFile) Then
+ With oFile
+ For Each sLine In _SF_.ConsoleLines
+ .WriteLine(sLine)
+ Next sLine
+ .CloseFile()
+ End With
+ End If
+ bExport = True
+ End If
+
+Finally:
+ If Not IsNull(oFile) Then Set oFile = oFile.Dispose()
+ ConsoleToFile = bExport
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Exception.ConsoleToFile
+
+REM -----------------------------------------------------------------------------
+Public Sub DebugDisplay(ParamArray pvArgs() As Variant)
+&apos;&apos;&apos; Display the list of arguments in a readable form in a message box
+&apos;&apos;&apos; Arguments are separated by a LINEFEED character
+&apos;&apos;&apos; The maximum length of each individual argument = 1024 characters
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Any number of arguments of any type
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Exception.DebugDisplay(a, Array(1, 2, 3), , &quot;line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot;, DateSerial(2020, 04, 09))
+
+Dim sOutputMsg As String &apos; Line to display
+Dim sOutputCon As String &apos; Line to write in console
+Dim sArgMsg As String &apos; Single argument
+Dim sArgCon As String &apos; Single argument
+Dim i As Integer
+Const cstTab = 4
+Const cstMaxLength = 1024
+Const cstThisSub = &quot;Exception.DebugDisplay&quot;
+Const cstSubArgs = &quot;Arg0, [Arg1, ...]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error Goto Finally &apos; Never interrupt processing
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+Try:
+ &apos; Build new console line
+ sOutputMsg = &quot;&quot; : sOutputCon = &quot;&quot;
+ For i = 0 To UBound(pvArgs)
+ If IsError(pvArgs(i)) Then pvArgs(i) = &quot;&quot;
+ sArgMsg = Iif(i = 0, &quot;&quot;, SF_String.sfNEWLINE) &amp; SF_Utils._Repr(pvArgs(i), cstMaxLength) &apos;Do not use SF_String.Represent()
+ sArgCon = Iif(i = 0, &quot;&quot;, SF_String.sfTAB) &amp; SF_Utils._Repr(pvArgs(i), cstMaxLength)
+ sOutputMsg = sOutputMsg &amp; sArgMsg
+ sOutputCon = sOutputCon &amp; sArgCon
+ Next i
+
+ &apos; Add to actual console
+ _SF_._AddToConsole(SF_String.ExpandTabs(sOutputCon, cstTab))
+ &apos; Display the message
+ MsgBox(sOutputMsg, MB_OK + MB_ICONINFORMATION, &quot;DebugDisplay&quot;)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception.DebugDisplay
+
+REM -----------------------------------------------------------------------------
+Public Sub DebugPrint(ParamArray pvArgs() As Variant)
+&apos;&apos;&apos; Print the list of arguments in a readable form in the console
+&apos;&apos;&apos; Arguments are separated by a TAB character (simulated by spaces)
+&apos;&apos;&apos; The maximum length of each individual argument = 1024 characters
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Any number of arguments of any type
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Exception.DebugPrint(a, Array(1, 2, 3), , &quot;line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot;, DateSerial(2020, 04, 09))
+
+Dim sOutput As String &apos; Line to write in console
+Dim sArg As String &apos; Single argument
+Dim i As Integer
+Const cstTab = 4
+Const cstMaxLength = 1024
+Const cstThisSub = &quot;Exception.DebugPrint&quot;
+Const cstSubArgs = &quot;Arg0, [Arg1, ...]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error Goto Finally &apos; Never interrupt processing
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+Try:
+ &apos; Build new console line
+ sOutput = &quot;&quot;
+ For i = 0 To UBound(pvArgs)
+ If IsError(pvArgs(i)) Then pvArgs(i) = &quot;&quot;
+ sArg = Iif(i = 0, &quot;&quot;, SF_String.sfTAB) &amp; SF_Utils._Repr(pvArgs(i), cstMaxLength) &apos;Do not use SF_String.Represent()
+ sOutput = sOutput &amp; sArg
+ Next i
+
+ &apos; Add to actual console
+ _SF_._AddToConsole(SF_String.ExpandTabs(sOutput, cstTab))
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception.DebugPrint
+
+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; ARGUMENTERROR The property does not exist
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myException.GetProperty(&quot;MyProperty&quot;)
+
+Const cstThisSub = &quot;Exception.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Exception.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Exception service as an array
+
+ Methods = Array( _
+ &quot;Clear&quot; _
+ , &quot;Console&quot; _
+ , &quot;ConsoleClear&quot; _
+ , &quot;ConsoleToFile&quot; _
+ , &quot;DebugPrint&quot; _
+ , &quot;Raise&quot; _
+ , &quot;RaiseAbort&quot; _
+ , &quot;RaiseFatal&quot; _
+ , &quot;RaiseWarning&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Exception.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;Description&quot; _
+ , &quot;Number&quot; _
+ , &quot;Source&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Exception.Properties
+
+REM -----------------------------------------------------------------------------
+Public Sub PythonPrint(ParamArray pvArgs() As Variant)
+&apos;&apos;&apos; Display the list of arguments in a readable form in the Python console
+&apos;&apos;&apos; Arguments are separated by a TAB character (simulated by spaces)
+&apos;&apos;&apos; The maximum length of each individual argument = 1024 characters
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Any number of arguments of any type
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_Exception.PythonPrint(a, Array(1, 2, 3), , &quot;line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot;, DateSerial(2020, 04, 09))
+
+Dim sOutput As String &apos; Line to write in console
+Dim sArg As String &apos; Single argument
+Dim i As Integer
+Const cstTab = 4
+Const cstMaxLength = 1024
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Exception__PythonPrint&quot;
+Const cstThisSub = &quot;Exception.PythonPrint&quot;
+Const cstSubArgs = &quot;Arg0, [Arg1, ...]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error Goto Finally &apos; Never interrupt processing
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+Try:
+ &apos; Build new console line
+ sOutput = &quot;&quot;
+ For i = 0 To UBound(pvArgs)
+ If IsError(pvArgs(i)) Then pvArgs(i) = &quot;&quot;
+ sArg = Iif(i = 0, &quot;&quot;, SF_String.sfTAB) &amp; SF_Utils._Repr(pvArgs(i), cstMaxLength)
+ sOutput = sOutput &amp; sArg
+ Next i
+
+ &apos; Add to actual console
+ sOutput = SF_String.ExpandTabs(sOutput, cstTab)
+ _SF_._AddToConsole(sOutput)
+ &apos; Display the message in the Python shell console
+ With ScriptForge.SF_Session
+ .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, sOutput)
+ End With
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception.PythonPrint
+
+REM -----------------------------------------------------------------------------
+Public Sub Raise(Optional ByVal Number As Variant _
+ , Optional ByVal Source As Variant _
+ , Optional ByVal Description As Variant _
+ )
+&apos;&apos;&apos; Generate a run-time error. An error message is displayed to the user and logged
+&apos;&apos;&apos; in the console. The execution is STOPPED
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Number: the error number, may be numeric or string
+&apos;&apos;&apos; If numeric and &lt;= 2000, it is considered a LibreOffice Basic run-time error (default = Err)
+&apos;&apos;&apos; Source: the line where the error occurred (default = Erl) or any string describing the location of the error
+&apos;&apos;&apos; Description: the error message to log in the console and to display to the user
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; On Local Error GoTo Catch
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; Catch:
+&apos;&apos;&apos; SF_Exception.Raise() &apos; Standard behaviour
+&apos;&apos;&apos; SF_Exception.Raise(11) &apos; Force division by zero
+&apos;&apos;&apos; SF_Exception.Raise(&quot;MYAPPERROR&quot;, &quot;myFunction&quot;, &quot;Application error&quot;)
+&apos;&apos;&apos; SF_Exception.Raise(,, &quot;To divide by zero is not a good idea !&quot;)
+
+Dim sMessage As String &apos; Error message to log and to display
+Dim L10N As Object &apos; Alias to LocalizedInterface
+Const cstThisSub = &quot;Exception.Raise&quot;
+Const cstSubArgs = &quot;[Number=Err], [Source=Erl], [Description]&quot;
+
+ &apos; Save Err, Erl, .. values before any On Error ... statement
+ SF_Exception._CaptureSystemError()
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Number) Or IsEmpty(Number) Then Number = -1
+ If IsMissing(Source) Or IsEmpty(Source) Then Source = -1
+ If IsMissing(Description) Or IsEmpty(Description) Then Description = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Number, &quot;Number&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
+ If Not SF_Utils._Validate(Source, &quot;Source&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
+ If Not SF_Utils._Validate(Description, &quot;Description&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ With SF_Exception
+ If Number &gt;= 0 Then .Number = Number
+ If VarType(Source) = V_STRING Then
+ If Len(Source) &gt; 0 Then .Source = Source
+ ElseIf Source &gt;= 0 Then &apos; -1 = Default =&gt; no change
+ .Source = Source
+ End If
+ If Len(Description) &gt; 0 Then .Description = Description
+
+ &apos; Log and display
+ Set L10N = _SF_._GetLocalizedInterface()
+ sMessage = L10N.GetText(&quot;LONGERRORDESC&quot;, .Number, .Source, .Description)
+ .DebugPrint(sMessage)
+ If _SF_.DisplayEnabled Then MsgBox L10N.GetText(&quot;ERRORNUMBER&quot;, .Number) _
+ &amp; SF_String.sfNewLine &amp; L10N.GetText(&quot;ERRORLOCATION&quot;, .Source) _
+ &amp; SF_String.sfNewLine &amp; .Description _
+ , MB_OK + MB_ICONSTOP _
+ , L10N.GetText(&quot;ERRORNUMBER&quot;, .Number)
+ .Clear()
+ End With
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ If _SF_.StopWhenError Then
+ _SF_._StackReset()
+ Stop
+ End If
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Exception.Raise
+
+REM -----------------------------------------------------------------------------
+Public Sub RaiseAbort(Optional ByVal Source As Variant)
+&apos;&apos;&apos; Manage a run-time error that occurred inside the ScriptForge piece of software itself.
+&apos;&apos;&apos; The event is logged.
+&apos;&apos;&apos; The execution is STOPPED
+&apos;&apos;&apos; For INTERNAL USE only
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: the line where the error occurred
+
+Dim sLocation As String &apos; Common header in error messages: location of error
+Dim vLocation As Variant &apos; Split array (library, module, method)
+Dim sMessage As String &apos; Error message to log and to display
+Dim L10N As Object &apos; Alias to LocalizedInterface
+Const cstTabSize = 4
+Const cstThisSub = &quot;Exception.RaiseAbort&quot;
+Const cstSubArgs = &quot;[Source=Erl]&quot;
+
+ &apos; Save Err, Erl, .. values before any On Error ... statement
+ SF_Exception._CaptureSystemError()
+ On Local Error Resume Next
+
+Check:
+ If IsMissing(Source) Or IsEmpty(Source) Then Source = &quot;&quot;
+
+Try:
+ With SF_Exception
+
+ &apos; Prepare message header
+ Set L10N = _SF_._GetLocalizedInterface()
+ If Len(_SF_.MainFunction) &gt; 0 Then &apos; MainFunction = [Library.]Module.Method
+ vLocation = Split(_SF_.MainFunction, &quot;.&quot;)
+ If UBound(vLocation) &lt; 2 Then vLocation = SF_Array.Prepend(vLocation, &quot;ScriptForge&quot;)
+ sLocation = L10N.GetText(&quot;VALIDATESOURCE&quot;, vLocation(0), vLocation(1), vLocation(2)) &amp; &quot;\n\n\n&quot;
+ Else
+ sLocation = &quot;&quot;
+ End If
+
+ &apos; Log and display
+ sMessage = L10N.GetText(&quot;LONGERRORDESC&quot;, .Number, .Source, .Description)
+ .DebugPrint(sMessage)
+ If _SF_.DisplayEnabled Then
+ sMessage = sLocation _
+ &amp; L10N.GetText(&quot;INTERNALERROR&quot;) _
+ &amp; L10N.GetText(&quot;ERRORLOCATION&quot;, Source &amp; &quot;/&quot; &amp; .Source) &amp; SF_String.sfNewLine &amp; .Description _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; L10N.GetText(&quot;STOPEXECUTION&quot;)
+ MsgBox SF_String.ExpandTabs(SF_String.Unescape(sMessage), cstTabSize) _
+ , MB_OK + MB_ICONSTOP _
+ , L10N.GetText(&quot;ERRORNUMBER&quot;, .Number)
+ End If
+
+ .Clear()
+ End With
+
+Finally:
+ _SF_._StackReset()
+ If _SF_.StopWhenError Then Stop
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Exception.RaiseAbort
+
+REM -----------------------------------------------------------------------------
+Public Sub RaiseFatal(Optional ByVal ErrorCode As Variant _
+ , ParamArray pvArgs _
+ )
+&apos;&apos;&apos; Generate a run-time error caused by an anomaly in a user script detected by ScriptForge
+&apos;&apos;&apos; The message is logged in the console. The execution is STOPPED
+&apos;&apos;&apos; For INTERNAL USE only
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ErrorCode: as a string, the unique identifier of the error
+&apos;&apos;&apos; pvArgs: the arguments to insert in the error message
+
+Dim sLocation As String &apos; Common header in error messages: location of error
+Dim sService As String &apos; Service name having detected the error
+Dim sMethod As String &apos; Method name having detected the error
+Dim vLocation As Variant &apos; Split array (library, module, method)
+Dim sMessage As String &apos; Message to log and display
+Dim L10N As Object &apos; Alias of LocalizedInterface
+Dim sAlt As String &apos; Alternative error messages
+Dim iButtons As Integer &apos; MB_OK or MB_YESNO
+Dim iMsgBox As Integer &apos; Return value of the message box
+
+Const cstTabSize = 4
+Const cstThisSub = &quot;Exception.RaiseFatal&quot;
+Const cstSubArgs = &quot;ErrorCode, [Arg0[, Arg1 ...]]&quot;
+Const cstStop = &quot;⏻&quot; &apos; Chr(9211)
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(ErrorCode) Or IsEmpty(ErrorCode) Then ErrorCode = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(ErrorCode, &quot;ErrorCode&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set L10N = _SF_._GetLocalizedInterface()
+ &apos; Location header common to all error messages
+ If Len(_SF_.MainFunction) &gt; 0 Then &apos; MainFunction = [Library.]Module.Method
+ vLocation = Split(_SF_.MainFunction, &quot;.&quot;)
+ If UBound(vLocation) &lt; 2 Then vLocation = SF_Array.Prepend(vLocation, &quot;ScriptForge&quot;)
+ sService = vLocation(1)
+ sMethod = vLocation(2)
+ sLocation = L10N.GetText(&quot;VALIDATESOURCE&quot;, vLocation(0), sService, sMethod) _
+ &amp; &quot;\n&quot; &amp; L10N.GetText(&quot;VALIDATEARGS&quot;, _RightCaseArgs(_SF_.MainFunctionArgs))
+ Else
+ sService = &quot;&quot;
+ sMethod = &quot;&quot;
+ sLocation = &quot;&quot;
+ End If
+
+ With L10N
+ Select Case UCase(ErrorCode)
+ Case MISSINGARGERROR &apos; SF_Utils._Validate(Name)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEMISSING&quot;, pvArgs(0))
+ Case ARGUMENTERROR &apos; SF_Utils._Validate(Value, Name, Types, Values, Regex, Class)
+ pvArgs(1) = _RightCase(pvArgs(1))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(1)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATIONRULES&quot;)
+ If Len(pvArgs(2)) &gt; 0 Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATETYPES&quot;, pvArgs(1), pvArgs(2))
+ If Len(pvArgs(3)) &gt; 0 Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEVALUES&quot;, pvArgs(1), pvArgs(3))
+ If Len(pvArgs(4)) &gt; 0 Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEREGEX&quot;, pvArgs(1), pvArgs(4))
+ If Len(pvArgs(5)) &gt; 0 Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATECLASS&quot;, pvArgs(1), pvArgs(5))
+ sMessage = sMessage &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEACTUAL&quot;, pvArgs(1), pvArgs(0))
+ Case ARRAYERROR &apos; SF_Utils._ValidateArray(Value, Name, Dimensions, Types, NotNull)
+ pvArgs(1) = _RightCase(pvArgs(1))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(1)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATIONRULES&quot;) _
+ &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEARRAY&quot;, pvArgs(1))
+ If pvArgs(2) &gt; 0 Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEDIMS&quot;, pvArgs(1), pvArgs(2))
+ If Len(pvArgs(3)) &gt; 0 Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEALLTYPES&quot;, pvArgs(1), pvArgs(3))
+ If pvArgs(4) Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATENOTNULL&quot;, pvArgs(1))
+ sMessage = sMessage &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEACTUAL&quot;, pvArgs(1), pvArgs(0))
+ Case FILEERROR &apos; SF_Utils._ValidateFile(Value, Name, WildCards)
+ pvArgs(1) = _RightCase(pvArgs(1))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(1)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATIONRULES&quot;) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEFILE&quot;, pvArgs(1))
+ sAlt = &quot;VALIDATEFILE&quot; &amp; SF_FileSystem.FileNaming
+ sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(sAlt, pvArgs(1))
+ If pvArgs(2) Then sMessage = sMessage &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEWILDCARD&quot;, pvArgs(1))
+ sMessage = sMessage &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEACTUAL&quot;, pvArgs(1), pvArgs(0))
+ Case ARRAYSEQUENCEERROR &apos; SF_Array.RangeInit(From, UpTo, ByStep)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;ARRAYSEQUENCE&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case ARRAYINSERTERROR &apos; SF_Array.AppendColumn/Row/PrependColumn/Row(VectorName, Array_2D, Vector)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;ARRAYINSERT&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case ARRAYINDEX1ERROR &apos; SF_Array.ExtractColumn/Row(IndexName, Array_2D, Index)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;ARRAYINDEX1&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case ARRAYINDEX2ERROR &apos; SF_Array.Slice(From, UpTo)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;ARRAYINDEX2&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case CSVPARSINGERROR &apos; SF_Array.ImportFromCSVFile(FileName, LineNumber, Line)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;CSVPARSING&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case DUPLICATEKEYERROR &apos; SF_Dictionary.Add/ReplaceKey(&quot;Key&quot;, Key)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DUPLICATEKEY&quot;, pvArgs(0), pvArgs(1))
+ Case UNKNOWNKEYERROR &apos; SF_Dictionary.Remove/ReplaceItem/ReplaceKey(&quot;Key&quot;, Key)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;UNKNOWNKEY&quot;, pvArgs(0), pvArgs(1))
+ Case INVALIDKEYERROR &apos; SF_Dictionary.Add/ReplaceKey(Key)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;INVALIDKEY&quot;)
+ Case UNKNOWNFILEERROR &apos; SF_FileSystem.CopyFile/MoveFile/DeleteFile/CreateScriptService(&quot;L10N&quot;)(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;UNKNOWNFILE&quot;, pvArgs(0), pvArgs(1))
+ Case UNKNOWNFOLDERERROR &apos; SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;UNKNOWNFOLDER&quot;, pvArgs(0), pvArgs(1))
+ Case NOTAFILEERROR &apos; SF_FileSystem.CopyFile/MoveFile/DeleteFile(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;NOTAFILE&quot;, pvArgs(0), pvArgs(1))
+ Case NOTAFOLDERERROR &apos; SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;NOTAFOLDER&quot;, pvArgs(0), pvArgs(1))
+ Case OVERWRITEERROR &apos; SF_FileSystem.Copy+Move/File+Folder/CreateTextFile/OpenTextFile(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;OVERWRITE&quot;, pvArgs(0), pvArgs(1))
+ Case READONLYERROR &apos; SF_FileSystem.Copy+Move+Delete/File+Folder(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;READONLY&quot;, pvArgs(0), pvArgs(1))
+ Case NOFILEMATCHERROR &apos; SF_FileSystem.Copy+Move+Delete/File+Folder(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;NOFILEMATCH&quot;, pvArgs(0), pvArgs(1))
+ Case FOLDERCREATIONERROR &apos; SF_FileSystem.CreateFolder(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;FOLDERCREATION&quot;, pvArgs(0), pvArgs(1))
+ Case UNKNOWNSERVICEERROR &apos; SF_Services.CreateScriptService(ArgName, Value, Library, Service)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;UNKNOWNSERVICE&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case SERVICESNOTLOADEDERROR &apos; SF_Services.CreateScriptService(ArgName, Value, Library)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SERVICESNOTLOADED&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case CALCFUNCERROR &apos; SF_Session.ExecuteCalcFunction(CalcFunction)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, _RightCase(&quot;CalcFunction&quot;)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;CALCFUNC&quot;, pvArgs(0))
+ Case NOSCRIPTERROR &apos; SF_Session._GetScript(Language, &quot;Scope&quot;, Scope, &quot;Script&quot;, Script)
+ pvArgs(1) = _RightCase(pvArgs(1)) : pvArgs(3) = _RightCase(pvArgs(3))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, _RightCase(&quot;Script&quot;)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;NOSCRIPT&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4))
+ Case SCRIPTEXECERROR &apos; SF_Session.ExecuteBasicScript(&quot;Script&quot;, Script, Cause)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SCRIPTEXEC&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case WRONGEMAILERROR &apos; SF_Session.SendMail(Arg, Email)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;WRONGEMAIL&quot;, pvArgs(1))
+ Case SENDMAILERROR &apos; SF_Session.SendMail()
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SENDMAIL&quot;)
+ Case FILENOTOPENERROR &apos; SF_TextStream._IsFileOpen(FileName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;FILENOTOPEN&quot;, pvArgs(0))
+ Case FILEOPENMODEERROR &apos; SF_TextStream._IsFileOpen(FileName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;FILEOPENMODE&quot;, pvArgs(0), pvArgs(1))
+ Case ENDOFFILEERROR &apos; SF_TextStream.ReadLine/ReadAll/SkipLine(FileName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;ENDOFFILE&quot;, pvArgs(0))
+ Case DOCUMENTERROR &apos; SF_UI.GetDocument(ArgName, WindowName)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENT&quot;, pvArgs(0), pvArgs(1))
+ Case DOCUMENTCREATIONERROR &apos; SF_UI.Create(Arg1Name, DocumentType, Arg2Name, TemplateFile)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENTCREATION&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case DOCUMENTOPENERROR &apos; SF_UI.OpenDocument(Arg1Name, FileName, Arg2Name, Password, Arg3Name, FilterName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENTOPEN&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4), pvArgs(5))
+ Case BASEDOCUMENTOPENERROR &apos; SF_UI.OpenBaseDocument(Arg1Name, FileName, Arg2Name, RegistrationName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;BASEDOCUMENTOPEN&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case DOCUMENTDEADERROR &apos; SF_Document._IsStillAlive(FileName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENTDEAD&quot;, pvArgs(0))
+ Case DOCUMENTSAVEERROR &apos; SF_Document.Save(Arg1Name, FileName)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENTSAVE&quot;, pvArgs(0), pvArgs(1))
+ Case DOCUMENTSAVEASERROR &apos; SF_Document.SaveAs(Arg1Name, FileName, Arg2, Overwrite, Arg3, FilterName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENTSAVEAS&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4), pvArgs(5))
+ Case DOCUMENTREADONLYERROR &apos; SF_Document.update property(&quot;Document&quot;, FileName)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DOCUMENTREADONLY&quot;, pvArgs(0), pvArgs(1))
+ Case DBCONNECTERROR &apos; SF_Base.GetDatabase(&quot;User&quot;, User, &quot;Password&quot;, Password, FileName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DBCONNECT&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4))
+ Case CALCADDRESSERROR &apos; SF_Calc._ParseAddress(Address, &quot;Range&quot;/&quot;Sheet&quot;, Scope, Document)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;CALCADDRESS&quot; &amp; Iif(pvArgs(0) = &quot;Sheet&quot;, &quot;1&quot;, &quot;2&quot;), pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case DUPLICATESHEETERROR &apos; SF_Calc.InsertSheet(arg, SheetName, Document)
+ pvArgs(0) = _RightCase(pvArgs(0))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DUPLICATESHEET&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case OFFSETADDRESSERROR &apos; SF_Calc.RangeOffset(&quot;Range&quot;, Range, &quot;Rows&quot;, Rows, &quot;Columns&quot;, Columns, &quot;Height&quot;, Height, &quot;Width&quot;, Width, &quot;Document, Document)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
+ pvArgs(6) = _RightCase(pvArgs(6)) : pvArgs(8) = _RightCase(pvArgs(8)) : pvArgs(10) = _RightCase(pvArgs(10))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;OFFSETADDRESS&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4) _
+ , pvArgs(5), pvArgs(6), pvArgs(7), pvArgs(8), pvArgs(9), pvArgs(10), pvArgs(11))
+ Case DUPLICATECHARTERROR &apos; SF_Calc.CreateChart(chart, ChartName, sheet, SheetName, Document, file)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DUPLICATECHART&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4), pvArgs(5))
+ Case RANGEEXPORTERROR &apos; SF_Calc.ExportRangeToFile(Arg1Name, FileName, Arg2, Overwrite)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;RANGEEXPORT&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case CHARTEXPORTERROR &apos; SF_Chart.ExportToFile(Arg1Name, FileName, Arg2, Overwrite)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;CHARTEXPORT&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case FORMDEADERROR &apos; SF_Form._IsStillAlive(FormName, DocumentName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;FORMDEAD&quot;, pvArgs(0), pvArgs(1))
+ Case CALCFORMNOTFOUNDERROR &apos; SF_Calc.Forms(Index, SheetName, Document)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;CALCFORMNOTFOUND&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case WRITERFORMNOTFOUNDERROR &apos; SF_Document.Forms(Index, Document)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;WRITERFORMNOTFOUND&quot;, pvArgs(0), pvArgs(1))
+ Case BASEFORMNOTFOUNDERROR &apos; SF_Base.Forms(Index, FormDocument, BaseDocument)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;BASEFORMNOTFOUND&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case SUBFORMNOTFOUNDERROR &apos; SF_Form.Subforms(Subform, Mainform)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SUBFORMNOTFOUND&quot;, pvArgs(0), pvArgs(1))
+ Case FORMCONTROLTYPEERROR &apos; SF_FormControl._SetProperty(ControlName, FormName, ControlType, Property)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;FORMCONTROLTYPE&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case DIALOGNOTFOUNDERROR &apos; SF_Dialog._NewDialog(Service, DialogName, WindowName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
+ pvArgs(6) = _RightCase(pvArgs(6))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DIALOGNOTFOUND&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4) _
+ , pvArgs(5), pvArgs(6), pvArgs(7))
+ Case DIALOGDEADERROR &apos; SF_Dialog._IsStillAlive(DialogName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DIALOGDEAD&quot;, pvArgs(0))
+ Case CONTROLTYPEERROR &apos; SF_DialogControl._SetProperty(ControlName, DialogName, ControlType, Property)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;CONTROLTYPE&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
+ Case TEXTFIELDERROR &apos; SF_DialogControl.WriteLine(ControlName, DialogName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;TEXTFIELD&quot;, pvArgs(0), pvArgs(1))
+ Case DBREADONLYERROR &apos; SF_Database.RunSql()
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DBREADONLY&quot;, vLocation(2))
+ Case SQLSYNTAXERROR &apos; SF_Database._ExecuteSql(SQL)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SQLSYNTAX&quot;, pvArgs(0))
+ Case PYTHONSHELLERROR &apos; SF_Exception.PythonShell (Python only)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;PYTHONSHELL&quot;)
+ Case UNITTESTLIBRARYERROR &apos; SFUnitTests._NewUnitTest(LibraryName)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;UNITTESTLIBRARY&quot;, pvArgs(0))
+ Case UNITTESTMETHODERROR &apos; SFUnitTests.SF_UnitTest(Method)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;UNITTESTMETHOD&quot;, pvArgs(0))
+ Case Else
+ End Select
+ End With
+
+ &apos; Log fatal event
+ _SF_._AddToConsole(sMessage)
+
+ &apos; Display fatal event, if relevant (default)
+ If _SF_.DisplayEnabled Then
+ If _SF_.StopWhenError Then sMessage = sMessage &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; L10N.GetText(&quot;STOPEXECUTION&quot;)
+ &apos; Do you need more help ?
+ If Len(sMethod) &gt; 0 Then
+ sMessage = sMessage &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; L10N.GetText(&quot;NEEDMOREHELP&quot;, sMethod)
+ iButtons = MB_YESNO + MB_DEFBUTTON2
+ Else
+ iButtons = MB_OK
+ End If
+ iMsgBox = MsgBox(SF_String.ExpandTabs(SF_String.Unescape(sMessage), cstTabSize) _
+ , iButtons + MB_ICONEXCLAMATION _
+ , L10N.GetText(&quot;ERRORNUMBER&quot;, ErrorCode) _
+ )
+ &apos; If more help needed ...
+ If iMsgBox = IDYES Then _OpenHelpInBrowser(sService, sMethod)
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ _SF_._StackReset()
+ If _SF_.StopWhenError Then Stop
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Exception.RaiseFatal
+
+REM -----------------------------------------------------------------------------
+Public Sub RaiseWarning(Optional ByVal Number As Variant _
+ , Optional ByVal Source As Variant _
+ , Optional ByVal Description As Variant _
+ )
+&apos;&apos;&apos; Generate a run-time error. An error message is displayed to the user and logged
+&apos;&apos;&apos; in the console. The execution is NOT STOPPED
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Number: the error number, may be numeric or string
+&apos;&apos;&apos; If numeric and &lt;= 2000, it is considered a LibreOffice Basic run-time error (default = Err)
+&apos;&apos;&apos; Source: the line where the error occurred (default = Erl) or any string describing the location of the error
+&apos;&apos;&apos; Description: the error message to log in the console and to display to the user
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful. Anyway, the execution continues
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; On Local Error GoTo Catch
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; Catch:
+&apos;&apos;&apos; SF_Exception.RaiseWarning() &apos; Standard behaviour
+&apos;&apos;&apos; SF_Exception.RaiseWarning(11) &apos; Force division by zero
+&apos;&apos;&apos; SF_Exception.RaiseWarning(&quot;MYAPPERROR&quot;, &quot;myFunction&quot;, &quot;Application error&quot;)
+&apos;&apos;&apos; SF_Exception.RaiseWarning(,, &quot;To divide by zero is not a good idea !&quot;)
+
+Dim bStop As Boolean &apos; Alias for stop switch
+Const cstThisSub = &quot;Exception.RaiseWarning&quot;
+Const cstSubArgs = &quot;[Number=Err], [Source=Erl], [Description]&quot;
+
+ &apos; Save Err, Erl, .. values before any On Error ... statement
+ SF_Exception._CaptureSystemError()
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Number) Or IsEmpty(Number) Then Number = -1
+ If IsMissing(Source) Or IsEmpty(Source) Then Source = -1
+ If IsMissing(Description) Or IsEmpty(Description) Then Description = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Number, &quot;Number&quot;, Array(V_STRING, V_NUMERIC, V_EMPTY)) Then GoTo Finally
+ If Not SF_Utils._Validate(Source, &quot;Source&quot;, Array(V_STRING, V_NUMERIC, V_EMPTY)) Then GoTo Finally
+ If Not SF_Utils._Validate(Description, &quot;Description&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ bStop = _SF_.StopWhenError &apos; Store current value to reset it before leaving the Sub
+ _SF_.StopWhenError = False
+ SF_Exception.Raise(Number, Source, Description)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ _SF_.StopWhenError = bStop
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Exception.RaiseWarning
+
+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;Exception.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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Exception.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Sub _CaptureSystemError()
+&apos;&apos;&apos; Store system error status in system error properties
+&apos;&apos;&apos; Called at each invocation of an error management property or method
+&apos;&apos;&apos; Reset by SF_Exception.Clear()
+
+ If Err &gt; 0 And _SysNumber = 0 Then
+ _SysNumber = Err
+ _SysSource = Erl
+ _SysDescription = Error$
+ End If
+
+End Sub &apos; ScriptForge.SF_Exception._CaptureSystemError
+
+REM -----------------------------------------------------------------------------
+Public Sub _CloseConsole(Optional ByRef poEvent As Object)
+&apos;&apos;&apos; Close the console when opened in non-modal mode
+&apos;&apos;&apos; Triggered by the CloseNonModalButton from the dlgConsole dialog
+
+ On Local Error GoTo Finally
+
+Try:
+ With _SF_
+ If Not IsNull(.ConsoleDialog) Then
+ If .ConsoleDialog._IsStillAlive(False) Then &apos; False to not raise an error
+ Set .ConsoleControl = .ConsoleControl.Dispose()
+ Set .ConsoleDialog = .ConsoleDialog.Dispose()
+ End If
+ End If
+ End With
+
+Finally:
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception._CloseConsole
+
+REM -----------------------------------------------------------------------------
+Private Sub _ConsoleRefresh()
+&apos;&apos;&apos; Reload the content of the console in the dialog
+&apos;&apos;&apos; Needed when console first loaded or when totally or partially cleared
+
+ With _SF_
+ &apos; Do nothing if console inactive
+ If IsNull(.ConsoleDialog) Then GoTo Finally
+ If Not .ConsoleDialog._IsStillAlive(False) Then &apos; False to not generate an error when dead
+ Set .ConsoleControl = .ConsoleControl.Dispose()
+ Set .ConsoleDialog = Nothing
+ GoTo Finally
+ End If
+ &apos; Store the relevant text in the control
+ If IsNull(.ConsoleControl) Then Set .ConsoleControl = .ConsoleDialog.Controls(CONSOLENAME)
+ .ConsoleControl.Value = &quot;&quot;
+ If UBound(.ConsoleLines) &gt;= 0 Then .ConsoleControl.WriteLine(Join(.ConsoleLines, SF_String.sfNEWLINE))
+ End With
+
+Finally:
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception._ConsoleRefresh
+
+REM -----------------------------------------------------------------------------
+Private Sub _OpenHelpInBrowser(ByVal psService As String, ByVal psMethod As String)
+&apos;&apos;&apos; Open the help page and help anchor related to the given ScriptForge service and method
+
+Dim sUrl As String &apos; URL to open
+Const cstURL = &quot;https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_%1.html?&amp;DbPAR=BASIC#%2&quot;
+
+ On Local Error GoTo Finally &apos; No reason to risk abort here
+Try:
+ sUrl = SF_String.ReplaceStr(cstURL, Array(&quot;%1&quot;, &quot;%2&quot;), Array(LCase(psService), psMethod))
+ SF_Session.OpenUrlInBrowser(sUrl)
+
+Finally:
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Exception._OpenHelpInBrowser
+
+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 cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SF_Exception.get&quot; &amp; psProperty
+
+ SF_Exception._CaptureSystemError()
+
+ Select Case psProperty
+ Case &quot;Description&quot;
+ If _Description = &quot;&quot; Then _PropertyGet = _SysDescription Else _PropertyGet = _Description
+ Case &quot;Number&quot;
+ If IsEmpty(_Number) Then _PropertyGet = _SysNumber Else _PropertyGet = _Number
+ Case &quot;Source&quot;
+ If IsEmpty(_Source) Then _PropertyGet = _SysSource Else _PropertyGet = _Source
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ Exit Function
+End Function &apos; ScriptForge.SF_Exception._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(Optional ByVal psProperty As String _
+ , Optional ByVal pvValue As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set a new value to the named property
+&apos;&apos;&apos; Applicable only to user defined errors
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+&apos;&apos;&apos; pvValue: the new value
+
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SF_Exception.set&quot; &amp; psProperty
+ _PropertySet = False
+
+ SF_Exception._CaptureSystemError()
+
+ &apos; Argument validation must be manual to preserve system error status
+ &apos; If wrong VarType then property set is ignored
+ Select Case psProperty
+ Case &quot;Description&quot;
+ If VarType(pvValue) = V_STRING Then _Description = pvValue
+ Case &quot;Number&quot;
+ Select Case SF_Utils._VarTypeExt(pvValue)
+ Case V_STRING
+ _Number = pvValue
+ Case V_NUMERIC
+ _Number = CLng(pvValue)
+ If _Number &lt;= RUNTIMEERRORS And Len(_Description) = 0 Then _Description = Error(_Number)
+ Case V_EMPTY
+ _Number = Empty
+ Case Else
+ End Select
+ Case &quot;Source&quot;
+ Select Case SF_Utils._VarTypeExt(pvValue)
+ Case V_STRING
+ _Source = pvValue
+ Case V_NUMERIC
+ _Source = CLng(pvValue)
+ Case Else
+ End Select
+ Case Else
+ End Select
+
+ _PropertySet = True
+
+Finally:
+ Exit Function
+End Function &apos; ScriptForge.SF_Exception._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Exception instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Exception]: A readable string&quot;
+
+ _Repr = &quot;[Exception]: &quot; &amp; _Number &amp; &quot; (&quot; &amp; _Description &amp; &quot;)&quot;
+
+End Function &apos; ScriptForge.SF_Exception._Repr
+
+REM -----------------------------------------------------------------------------
+Private Function _RightCase(psString As String) As String
+&apos;&apos;&apos; Return the input argument in lower case only when the procedure in execution
+&apos;&apos;&apos; has been triggered from a Python script
+&apos;&apos;&apos; Indeed, Python requires lower case arguments
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psString: probably an identifier in ProperCase
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The input argument in lower case or left unchanged depending on the execution context
+
+Try:
+ If _SF_.TriggeredByPython Then _RightCase = LCase(psString) Else _RightCase = psString
+
+Finally:
+ Exit Function
+End Function &apos; ScriptForge.SF_Exception._RightCase
+
+REM -----------------------------------------------------------------------------
+Private Function _RightCaseArgs(psString As String) As String
+&apos;&apos;&apos; Return the input argument unchanged when the execution context is Basic
+&apos;&apos;&apos; When it is Python, the argument names are lowercased.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psString: one of the cstSubArgs strings located in each official method
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The input string in which the argument names are put in lower case when called from Python scripts
+
+Dim sSubArgs As String &apos; Return value
+Dim vArgs As Variant &apos; Input string split on the comma character
+Dim sSingleArg As String &apos; Single vArgs item
+Dim vSingleArgs As Variant &apos; vSingleArg split on equal sign
+Dim i As Integer
+
+Const cstComma = &quot;,&quot;
+Const cstEqual = &quot;=&quot;
+
+Try:
+ If Len(psString) = 0 Then
+ sSubArgs = &quot;&quot;
+ ElseIf _SF_.TriggeredByPython Then
+ vArgs = SF_String.SplitNotQuoted(psString, cstComma, QuoteChar := &quot;&quot;&quot;&quot;)
+ For i = 0 To UBound(vArgs)
+ sSingleArg = vArgs(i)
+ vSingleArgs = Split(sSingleArg, cstEqual)
+ vSingleArgs(0) = LCase(vSingleArgs(0))
+ vArgs(i) = join(vSingleArgs, cstEqual)
+ Next i
+ sSubArgs = Join(vArgs, cstComma)
+ Else
+ sSubArgs = psString
+ End If
+
+Finally:
+ _RightCaseArgs = sSubArgs
+ Exit Function
+End Function &apos; ScriptForge.SF_Exception._RightCaseArgs
+
+REM ============================================ END OF SCRIPTFORGE.SF_EXCEPTION
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_FileSystem.xba b/wizards/source/scriptforge/SF_FileSystem.xba
new file mode 100644
index 000000000..39ea4888e
--- /dev/null
+++ b/wizards/source/scriptforge/SF_FileSystem.xba
@@ -0,0 +1,2128 @@
+<?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_FileSystem" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_FileSystem
+&apos;&apos;&apos; =============
+&apos;&apos;&apos; Class implementing the file system service
+&apos;&apos;&apos; for common file and folder handling routines
+&apos;&apos;&apos; Including copy and move of files and folders, with or without wildcards
+&apos;&apos;&apos; The design choices are largely inspired by
+&apos;&apos;&apos; https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object
+&apos;&apos;&apos; The File and Folder classes have been found redundant with the current class and have not been implemented
+&apos;&apos;&apos; The implementation is mainly based on the XSimpleFileAccess UNO interface
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1ucb_1_1XSimpleFileAccess.html
+&apos;&apos;&apos;
+&apos;&apos;&apos; Subclasses:
+&apos;&apos;&apos; SF_TextStream
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; File and folder names may be expressed either in the (preferable because portable) URL form
+&apos;&apos;&apos; or in the more usual operating system notation (e.g. C:\... for Windows)
+&apos;&apos;&apos; The notation, both for arguments and for returned values
+&apos;&apos;&apos; is determined by the FileNaming property: either &quot;URL&quot; (default) or &quot;SYS&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; FileName: the full name of the file including the path without any ending path separator
+&apos;&apos;&apos; FolderName: the full name of the folder including the path and the ending path separator
+&apos;&apos;&apos; Name: the last component of the File- or FolderName including its extension
+&apos;&apos;&apos; BaseName: the last component of the File- or FolderName without its extension
+&apos;&apos;&apos; NamePattern: any of the above names containing wildcards in its last component
+&apos;&apos;&apos; Admitted wildcards are: the &quot;?&quot; represents any single character
+&apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim FSO As Variant
+&apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_filesystem.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
+Const UNKNOWNFOLDERERROR = &quot;UNKNOWNFOLDERERROR&quot; &apos; Source folder or Destination folder does not exist
+Const NOTAFILEERROR = &quot;NOTAFILEERROR&quot; &apos; Destination is a folder, not a file
+Const NOTAFOLDERERROR = &quot;NOTAFOLDERERROR&quot; &apos; Destination is a file, not a folder
+Const OVERWRITEERROR = &quot;OVERWRITEERROR&quot; &apos; Destination can not be overwritten
+Const READONLYERROR = &quot;READONLYERROR&quot; &apos; Destination has its read-only attribute set
+Const NOFILEMATCHERROR = &quot;NOFILEMATCHFOUND&quot; &apos; No file matches Source containing wildcards
+Const FOLDERCREATIONERROR = &quot;FOLDERCREATIONERROR&quot; &apos; FolderName is an existing folder or file
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos;&apos;&apos; TextStream open modes
+Const cstForReading = 1
+Const cstForWriting = 2
+Const cstForAppending = 8
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_FileSystem Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ConfigFolder() As String
+&apos;&apos;&apos; Return the configuration folder of LibreOffice
+
+Const cstThisSub = &quot;FileSystem.getConfigFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ ConfigFolder = SF_FileSystem._GetConfigFolder(&quot;user&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.ConfigFolder
+
+REM -----------------------------------------------------------------------------
+Property Get ExtensionsFolder() As String
+&apos;&apos;&apos; Return the folder containing the extensions installed for the current user
+
+Dim oMacro As Object &apos; /singletons/com.sun.star.util.theMacroExpander
+Const cstThisSub = &quot;FileSystem.getExtensionsFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ Set oMacro = SF_Utils._GetUNOService(&quot;MacroExpander&quot;)
+ ExtensionsFolder = SF_FileSystem._ConvertFromUrl(oMacro.ExpandMacros(&quot;$UNO_USER_PACKAGES_CACHE&quot;) &amp; &quot;/&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.ExtensionsFolder
+
+REM -----------------------------------------------------------------------------
+Property Get FileNaming() As Variant
+&apos;&apos;&apos; Return the current files and folder notation, either &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
+&apos;&apos;&apos; &quot;ANY&quot;: methods receive either URL or native file names, but always return URL file names
+&apos;&apos;&apos; &quot;URL&quot;: methods expect URL arguments and return URL strings (when relevant)
+&apos;&apos;&apos; &quot;SYS&quot;: idem but operating system notation
+
+Const cstThisSub = &quot;FileSystem.getFileNaming&quot;
+ SF_Utils._EnterFunction(cstThisSub)
+ FileNaming = _SF_.FileSystemNaming
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.FileNaming (get)
+
+REM -----------------------------------------------------------------------------
+Property Let FileNaming(ByVal pvNotation As Variant)
+&apos;&apos;&apos; Set the files and folders notation: &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
+
+Const cstThisSub = &quot;FileSystem.setFileNaming&quot;
+ SF_Utils._EnterFunction(cstThisSub)
+ If VarType(pvNotation) = V_STRING Then
+ Select Case UCase(pvNotation)
+ Case &quot;ANY&quot;, &quot;URL&quot;, &quot;SYS&quot; : _SF_.FileSystemNaming = UCase(pvNotation)
+ Case Else &apos; Unchanged
+ End Select
+ End If
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.FileNaming (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ForAppending As Integer
+&apos;&apos;&apos; Convenient constant (see documentation)
+ ForAppending = cstForAppending
+End Property &apos; ScriptForge.SF_FileSystem.ForAppending
+
+REM -----------------------------------------------------------------------------
+Property Get ForReading As Integer
+&apos;&apos;&apos; Convenient constant (see documentation)
+ ForReading = cstForReading
+End Property &apos; ScriptForge.SF_FileSystem.ForReading
+
+REM -----------------------------------------------------------------------------
+Property Get ForWriting As Integer
+&apos;&apos;&apos; Convenient constant (see documentation)
+ ForWriting = cstForWriting
+End Property &apos; ScriptForge.SF_FileSystem.ForWriting
+
+REM -----------------------------------------------------------------------------
+Property Get HomeFolder() As String
+&apos;&apos;&apos; Return the user home folder
+
+Const cstThisSub = &quot;FileSystem.getHomeFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ HomeFolder = SF_FileSystem._GetConfigFolder(&quot;home&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.HomeFolder
+
+REM -----------------------------------------------------------------------------
+Property Get InstallFolder() As String
+&apos;&apos;&apos; Return the installation folder of LibreOffice
+
+Const cstThisSub = &quot;FileSystem.getInstallFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ InstallFolder = SF_FileSystem._GetConfigFolder(&quot;inst&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.InstallFolder
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_FileSystem&quot;
+End Property &apos; ScriptForge.SF_FileSystem.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.FileSystem&quot;
+End Property &apos; ScriptForge.SF_FileSystem.ServiceName
+
+REM -----------------------------------------------------------------------------
+Property Get TemplatesFolder() As String
+&apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for templates files
+
+Dim sPath As String &apos; Template property of com.sun.star.util.PathSettings
+Const cstThisSub = &quot;FileSystem.getTemplatesFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template
+ TemplatesFolder = SF_FileSystem._ConvertFromUrl(Split(sPath, &quot;;&quot;)(0) &amp; &quot;/&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.TemplatesFolder
+
+REM -----------------------------------------------------------------------------
+Property Get TemporaryFolder() As String
+&apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for temporary files
+
+Const cstThisSub = &quot;FileSystem.getTemporaryFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ TemporaryFolder = SF_FileSystem._GetConfigFolder(&quot;temp&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.TemporaryFolder
+
+REM -----------------------------------------------------------------------------
+Property Get UserTemplatesFolder() As String
+&apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for User templates files
+
+Dim sPath As String &apos; Template_writable property of com.sun.star.util.PathSettings
+Const cstThisSub = &quot;FileSystem.getUserTemplatesFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template_writable
+ UserTemplatesFolder = SF_FileSystem._ConvertFromUrl(sPath &amp; &quot;/&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.UserTemplatesFolder
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function BuildPath(Optional ByVal FolderName As Variant _
+ , Optional ByVal Name As Variant _
+ ) As String
+&apos;&apos;&apos; Combines a folder path and the name of a file and returns the combination with a valid path separator
+&apos;&apos;&apos; Inserts an additional path separator between the foldername and the name, only if necessary
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: Path with which Name is combined. Path need not specify an existing folder
+&apos;&apos;&apos; Name: To be appended to the existing path.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The path concatenated with the file name after insertion of a path separator, if necessary
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.BuildPath(&quot;C:\Windows&quot;, &quot;Notepad.exe&quot;) returns C:\Windows\Notepad.exe
+
+Dim sBuild As String &apos; Return value
+Dim sFile As String &apos; Alias for Name
+Const cstFileProtocol = &quot;file:///&quot;
+Const cstThisSub = &quot;FileSystem.BuildPath&quot;
+Const cstSubArgs = &quot;FolderName, Name&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sBuild = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Finally
+ End If
+ FolderName = SF_FileSystem._ConvertToUrl(FolderName)
+
+Try:
+ &apos; Add separator if necessary. FolderName is now in URL notation
+ If Len(FolderName) &gt; 0 Then
+ If Right(FolderName, 1) &lt;&gt; &quot;/&quot; Then sBuild = FolderName &amp; &quot;/&quot; Else sBuild = FolderName
+ Else
+ sBuild = cstFileProtocol
+ End If
+ &apos; Encode the file name
+ sFile = ConvertToUrl(Name)
+ &apos; Some file names produce http://file.name.suffix/
+ If Left(sFile, 7) = &quot;http://&quot; Then sFile = cstFileProtocol &amp; Mid(sFile, 8, Len(sFile) - 8)
+ &apos; Combine both parts
+ If Left(sFile, Len(cstFileProtocol)) = cstFileProtocol Then sBuild = sBuild &amp; Mid(sFile, Len(cstFileProtocol) + 1) Else sBuild = sBuild &amp; sFile
+
+Finally:
+ BuildPath = SF_FileSystem._ConvertFromUrl(sBuild)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.BuildPath
+
+REM -----------------------------------------------------------------------------
+Public Function CompareFiles(Optional ByVal FileName1 As Variant _
+ , Optional ByVal FileName2 As Variant _
+ , Optional ByVal CompareContents As Variant _
+ )
+&apos;&apos;&apos; Compare 2 files and return True if they seem identical
+&apos;&apos;&apos; The comparison may be based on the file attributes, like modification time,
+&apos;&apos;&apos; or on their contents.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName1: The 1st file to compare
+&apos;&apos;&apos; FileName2: The 2nd file to compare
+&apos;&apos;&apos; CompareContents: When True, the contents of the files are compared. Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when the files seem identical
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR One of the files does not exist
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; MsgBox FSO.CompareFiles(&quot;C:\myFile1.txt&quot;, &quot;C:\myFile2.txt&quot;, CompareContents := True)
+
+Dim bCompare As Boolean &apos; Return value
+Dim sFile As String &apos; Alias of FileName1 and 2
+Dim iFile As Integer &apos; 1 or 2
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__CompareFiles&quot;
+
+Const cstThisSub = &quot;FileSystem.CompareFiles&quot;
+Const cstSubArgs = &quot;FileName1, FileName2, [CompareContents=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCompare = False
+
+Check:
+ If IsMissing(CompareContents) Or IsEmpty(CompareContents) Then CompareContents = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName1, &quot;FileName1&quot;, False) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(FileName2, &quot;FileName2&quot;, False) Then GoTo Finally
+ If Not SF_Utils._Validate(CompareContents, &quot;CompareContents&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+ &apos; Do the files exist ? Otherwise raise error
+ sFile = FileName1 : iFile = 1
+ If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
+ sFile = FileName2 : iFile = 2
+ If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
+
+Try:
+ With ScriptForge.SF_Session
+ bCompare = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , _ConvertFromUrl(FileName1) _
+ , _ConvertFromUrl(FileName2) _
+ , CompareContents)
+ End With
+
+Finally:
+ CompareFiles = bCompare
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot; &amp; iFile, sFile)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CompareFiles
+
+REM -----------------------------------------------------------------------------
+Public Function CopyFile(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Copies one or more files from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be copied
+&apos;&apos;&apos; Destination: FileName where the single Source file is to be copied
+&apos;&apos;&apos; or FolderName where the multiple files from Source are to be copied
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Overwrite: If True (default), files may be overwritten
+&apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one file has been copied
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.CopyFile(&quot;C:\Windows\*.*&quot;, &quot;C:\Temp\&quot;, Overwrite := False) &apos; Only files are copied, subfolders are not
+
+Dim bCopy As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.CopyFile&quot;
+Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCopy = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ bCopy = SF_FileSystem._CopyMove(&quot;CopyFile&quot;, Source, Destination, Overwrite)
+
+Finally:
+ CopyFile = bCopy
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CopyFile
+
+REM -----------------------------------------------------------------------------
+Public Function CopyFolder(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Copies one or more folders from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be copied
+&apos;&apos;&apos; Destination: FolderName where the single Source folder is to be copied
+&apos;&apos;&apos; or FolderName where the multiple folders from Source are to be copied
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Overwrite: If True (default), folders and their content may be overwritten
+&apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one folder has been copied
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.CopyFolder(&quot;C:\Windows\*&quot;, &quot;C:\Temp\&quot;, Overwrite := False)
+
+Dim bCopy As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.CopyFolder&quot;
+Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCopy = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ bCopy = SF_FileSystem._CopyMove(&quot;CopyFolder&quot;, Source, Destination, Overwrite)
+
+Finally:
+ CopyFolder = bCopy
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CopyFolder
+
+REM -----------------------------------------------------------------------------
+Public Function CreateFolder(Optional ByVal FolderName As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given folder name could be created successfully
+&apos;&apos;&apos; The parent folder does not need to exist beforehand
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: a string representing the folder to create. It must not exist
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if FolderName is a valid folder name, does not exist and creation was successful
+&apos;&apos;&apos; False otherwise including when FolderName is a file
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FOLDERCREATIONERROR FolderName is an existing folder or file
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.CreateFolder(&quot;C:\NewFolder\&quot;)
+
+Dim bCreate As Boolean &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.CreateFolder&quot;
+Const cstSubArgs = &quot;FolderName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCreate = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If SF_FileSystem.FolderExists(FolderName) Then GoTo CatchExists
+ If SF_FileSystem.FileExists(FolderName) Then GoTo CatchExists
+ oSfa.createFolder(SF_FileSystem._ConvertToUrl(FolderName))
+ bCreate = True
+
+Finally:
+ CreateFolder = bCreate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchExists:
+ SF_Exception.RaiseFatal(FOLDERCREATIONERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CreateFolder
+
+REM -----------------------------------------------------------------------------
+Public Function CreateTextFile(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Encoding As Variant _
+ ) As Object
+&apos;&apos;&apos; Creates a specified file and returns a TextStream object that can be used to write to the file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to create
+&apos;&apos;&apos; Overwrite: Boolean value that indicates if an existing file can be overwritten (default = True)
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
+&apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; OVERWRITEERROR File exists, creation impossible
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.CreateTextFile(&quot;C:\Temp\ThisFile.txt&quot;, Overwrite := True)
+
+Dim oTextStream As Object &apos; Return value
+Const cstThisSub = &quot;FileSystem.CreateTextFile&quot;
+Const cstSubArgs = &quot;FileName, [Overwrite=True], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oTextStream = Nothing
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
+ If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ 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(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ With SF_FileSystem
+ If .FileExists(FileName) Then
+ If Overwrite Then .DeleteFile(FileName) Else GoTo CatchOverWrite
+ End If
+
+Try:
+ Set oTextStream = .OpenTextFile(FileName, .ForWriting, Create := True, Encoding := Encoding)
+ End With
+
+Finally:
+ Set CreateTextFile = oTextStream
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchOverWrite:
+ SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CreateTextFile
+
+REM -----------------------------------------------------------------------------
+Public Function DeleteFile(Optional ByVal FileName As Variant) As Boolean
+&apos;&apos;&apos; Deletes one or more files
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: FileName or NamePattern which can include wildcard characters, for one or more files to be deleted
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one file has been deleted
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a FileName using wildcard characters doesn&apos;t match any files.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR FileName does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches FileName containing wildcards
+&apos;&apos;&apos; NOTAFILEERROR Argument is a folder, not a file
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.DeleteFile(&quot;C:\Temp\*.*&quot;) &apos; Only files are deleted, subfolders are not
+
+Dim bDelete As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.DeleteFile&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bDelete = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, True) Then GoTo Finally
+ End If
+
+Try:
+ bDelete = SF_FileSystem._Delete(&quot;DeleteFile&quot;, FileName)
+
+Finally:
+ DeleteFile = bDelete
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.DeleteFile
+
+REM -----------------------------------------------------------------------------
+Public Function DeleteFolder(Optional ByVal FolderName As Variant) As Boolean
+&apos;&apos;&apos; Deletes one or more Folders
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: FolderName or NamePattern which can include wildcard characters, for one or more Folders to be deleted
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one folder has been deleted
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a FolderName using wildcard characters doesn&apos;t match any folders.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFOLDERERROR FolderName does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No folder matches FolderName containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Argument is a file, not a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.DeleteFolder(&quot;C:\Temp\*&quot;) &apos; Only folders are deleted, files in the parent folder are not
+
+Dim bDelete As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.DeleteFolder&quot;
+Const cstSubArgs = &quot;FolderName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bDelete = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;, True) Then GoTo Finally
+ End If
+
+Try:
+ bDelete = SF_FileSystem._Delete(&quot;DeleteFolder&quot;, FolderName)
+
+Finally:
+ DeleteFolder = bDelete
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.DeleteFolder
+
+REM -----------------------------------------------------------------------------
+Public Function ExtensionFolder(Optional ByVal Extension As Variant) As String
+&apos;&apos;&apos; Return the folder where the given extension is installed. The argument must
+&apos;&apos;&apos; be in the list of extensions provided by the SF_Platform.Extensions property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Extension: a valid extension name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The requested folder using the FileNaming notation
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox FSO.ExtensionFolder(&quot;apso.python.script.organizer&quot;)
+
+Dim sFolder As String &apos; Return value
+Static vExtensions As Variant &apos; Cached list of existing extension names
+Dim oPackage As Object &apos; /singletons/com.sun.star.deployment.PackageInformationProvider
+Const cstThisSub = &quot;FileSystem.ExtensionFolder&quot;
+Const cstSubArgs = &quot;Extension&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFolder = &quot;&quot;
+
+Check:
+ If IsEmpty(vExtensions) Then vExtensions = SF_Platform.Extensions
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Extension, &quot;Extension&quot;, V_STRING, vExtensions) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Search an individual folder
+ Set oPackage = SF_Utils._GetUnoService(&quot;PackageInformationProvider&quot;)
+ sFolder = oPackage.getPackageLocation(Extension)
+
+Finally:
+ ExtensionFolder = SF_FileSystem._ConvertFromUrl(sFolder)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.ExtensionFolder
+
+REM -----------------------------------------------------------------------------
+Public Function FileExists(Optional ByVal FileName As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given file exists
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if FileName is a valid File name and it exists
+&apos;&apos;&apos; False otherwise including when FileName is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; If FSO.FileExists(&quot;C:\Notepad.exe&quot;) Then ...
+
+Dim bExists As Boolean &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.FileExists&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExists = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ bExists = oSfa.exists(FileName) And Not oSfa.isFolder(FileName)
+
+Finally:
+ FileExists = bExists
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.FileExists
+
+REM -----------------------------------------------------------------------------
+Public Function Files(Optional ByVal FolderName As Variant _
+ , Optional ByVal Filter As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return an array of the FileNames stored in the given folder. The folder must exist
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: the folder to explore
+&apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant files (default = &quot;&quot;)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array of strings, each entry is the FileName of an existing file
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
+&apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Variant
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.Files(&quot;C:\Windows\&quot;)
+
+Dim vFiles As Variant &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFolderName As String &apos; URL lias for FolderName
+Dim sFile As String &apos; Single file
+Dim i As Long
+
+Const cstThisSub = &quot;FileSystem.Files&quot;
+Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vFiles = Array()
+
+Check:
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ End If
+ sFolderName = SF_FileSystem._ConvertToUrl(FolderName)
+ If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
+ If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
+
+Try:
+ &apos; Get files
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ vFiles = oSfa.getFolderContents(sFolderName, False)
+ &apos; Adjust notations
+ For i = 0 To UBound(vFiles)
+ sFile = SF_FileSystem._ConvertFromUrl(vFiles(i))
+ vFiles(i) = sFile
+ Next i
+ &apos; Reduce list to those passing the filter
+ If Len(Filter) &gt; 0 Then
+ For i = 0 To UBound(vFiles)
+ sFile = SF_FileSystem.GetName(vFiles(i))
+ If Not SF_String.IsLike(sFile, Filter) Then vFiles(i) = &quot;&quot;
+ Next i
+ vFiles = Sf_Array.TrimArray(vFiles)
+ End If
+
+Finally:
+ Files = vFiles
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchFile:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+CatchFolder:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.Files
+
+REM -----------------------------------------------------------------------------
+Public Function FolderExists(Optional ByVal FolderName As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given folder name exists
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: a string representing a folder
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if FolderName is a valid folder name and it exists
+&apos;&apos;&apos; False otherwise including when FolderName is a file
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; If FSO.FolderExists(&quot;C:\&quot;) Then ...
+
+Dim bExists As Boolean &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.FolderExists&quot;
+Const cstSubArgs = &quot;FolderName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExists = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ End If
+ FolderName = SF_FileSystem._ConvertToUrl(FolderName)
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ bExists = oSfa.isFolder(FolderName)
+
+Finally:
+ FolderExists = bExists
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.FolderExists
+
+REM -----------------------------------------------------------------------------
+Public Function GetBaseName(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns the BaseName part of the last component of a File- or FolderName, without its extension
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The BaseName of the given argument in native operating system format. May be empty
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetBaseName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad
+
+Dim sBase As String &apos; Return value
+Dim sExt As String &apos; Extension
+Dim sName As String &apos; Last component of FileName
+Dim vName As Variant &apos; Array of trunks of sName
+Const cstThisSub = &quot;FileSystem.GetBaseName&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sBase = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ sName = SF_FileSystem.GetName(FileName)
+ If Len(sName) &gt; 0 Then
+ If InStr(sName, &quot;.&quot;) &gt; 0 Then
+ vName = Split(sName, &quot;.&quot;)
+ sExt = vName(UBound(vName))
+ sBase = Left(sName, Len(sName) - Len(sExt) - 1)
+ Else
+ sBase = sName
+ End If
+ End If
+
+Finally:
+ GetBaseName = sBase
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetBaseName
+
+REM -----------------------------------------------------------------------------
+Public Function GetExtension(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns the extension part of a File- or FolderName, without the dot (.).
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The extension without a leading dot. May be empty
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetExtension(&quot;C:\Windows\Notepad.exe&quot;) returns exe
+
+Dim sExt As String &apos; Return value
+Dim sName As String &apos; Last component of FileName
+Dim vName As Variant &apos; Array of trunks of sName
+Const cstThisSub = &quot;FileSystem.GetExtension&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sExt = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ sName = SF_FileSystem.GetName(FileName)
+ If Len(sName) &gt; 0 And InStr(sName, &quot;.&quot;) &gt; 0 Then
+ vName = Split(sName, &quot;.&quot;)
+ sExt = vName(UBound(vName))
+ End If
+
+Finally:
+ GetExtension = sExt
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetExtension
+
+REM -----------------------------------------------------------------------------
+Public Function GetFileLen(Optional ByVal FileName As Variant) As Currency
+&apos;&apos;&apos; Return file size in bytes with four decimals &apos;&apos;&apos;
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; File size if FileName exists
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Print SF_FileSystem.GetFileLen(&quot;C:\pagefile.sys&quot;)
+
+Dim curSize As Currency &apos; Return value
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__GetFilelen&quot;
+Const cstThisSub = &quot;FileSystem.GetFileLen&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ curSize = 0
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ If SF_FileSystem.FileExists(FileName) Then
+ With ScriptForge.SF_Session
+ curSize = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , _ConvertFromUrl(FileName))
+ End With
+ Else
+ GoTo CatchNotExists
+ End If
+
+Finally:
+ GetFileLen = curSize
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetFileLen
+
+REM -----------------------------------------------------------------------------
+Public Function GetFileModified(Optional ByVal FileName As Variant) As Variant
+&apos;&apos;&apos; Returns the last modified date for the given file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing an existing file
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The modification date and time as a Basic Date
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Date
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetFileModified(&quot;C:\Temp\myDoc.odt&quot;)
+
+Dim dModified As Date &apos; Return value
+Dim oModified As New com.sun.star.util.DateTime
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.GetFileModified&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ dModified = 0
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If SF_FileSystem.FileExists(FileName) Then
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+ Set oModified = oSfa.getDateTimeModified(FileName)
+ dModified = CDateFromUnoDateTime(oModified)
+ Else
+ GoTo CatchNotExists
+ End If
+
+Finally:
+ GetFileModified = dModified
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetFileModified
+
+REM -----------------------------------------------------------------------------
+Public Function GetName(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns the last component of a File- or FolderName
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The last component of the full file name in native operating system format
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad.exe
+
+Dim sName As String &apos; Return value
+Dim vFile As Variant &apos; Array of components
+Const cstThisSub = &quot;FileSystem.GetName&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sName = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+
+Try:
+ If Len(FileName) &gt; 0 Then
+ If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
+ vFile = Split(FileName, &quot;/&quot;)
+ sName = ConvertFromUrl(vFile(UBound(vFile))) &apos; Always in SYS format
+ End If
+
+Finally:
+ GetName = sName
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetName
+
+REM -----------------------------------------------------------------------------
+Public Function GetParentFolderName(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns a string containing the name of the parent folder of the last component in a specified File- or FolderName
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A FolderName including its final path separator
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetParentFolderName(&quot;C:\Windows\Notepad.exe&quot;) returns C:\Windows\
+
+Dim sFolder As String &apos; Return value
+Dim sName As String &apos; Last component of FileName
+Dim vFile As Variant &apos; Array of file components
+Const cstThisSub = &quot;FileSystem.GetParentFolderName&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFolder = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+
+Try:
+ If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
+ vFile = Split(FileName, &quot;/&quot;)
+ If UBound(vFile) &gt;= 0 Then vFile(UBound(vFile)) = &quot;&quot;
+ sFolder = Join(vFile, &quot;/&quot;)
+ If sFolder = &quot;&quot; Or Right(sFolder, 1) &lt;&gt; &quot;/&quot; Then sFolder = sFolder &amp; &quot;/&quot;
+
+Finally:
+ GetParentFolderName = SF_FileSystem._ConvertFromUrl(sFolder)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetParentFolderName
+
+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;FileSystem.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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 UCase(&quot;ConfigFolder&quot;) : GetProperty = ConfigFolder
+ Case UCase(&quot;ExtensionsFolder&quot;) : GetProperty = ExtensionsFolder
+ Case UCase(&quot;FileNaming&quot;) : GetProperty = FileNaming
+ Case UCase(&quot;HomeFolder&quot;) : GetProperty = HomeFolder
+ Case UCase(&quot;InstallFolder&quot;) : GetProperty = InstallFolder
+ Case UCase(&quot;TemplatesFolder&quot;) : GetProperty = TemplatesFolder
+ Case UCase(&quot;TemporaryFolder&quot;) : GetProperty = TemporaryFolder
+ Case UCase(&quot;UserTemplatesFolder&quot;) : GetProperty = UserTemplatesFolder
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetTempName() As String
+&apos;&apos;&apos; Returns a randomly generated temporary file name that is useful for performing
+&apos;&apos;&apos; operations that require a temporary file : the method does not create any file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A FileName as a String that can be used f.i. with CreateTextFile()
+&apos;&apos;&apos; The FileName does not have any suffix
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetTempName() &amp; &quot;.txt&quot;
+
+Dim sFile As String &apos; Return value
+Dim sTempDir As String &apos; The path to a temporary folder
+Dim lRandom As Long &apos; Random integer
+
+Const cstThisSub = &quot;FileSystem.GetTempName&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFile = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ lRandom = SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN&quot;, 1, 999999)
+ sFile = SF_FileSystem.TemporaryFolder &amp; &quot;SF_&quot; &amp; Right(&quot;000000&quot; &amp; lRandom, 6)
+
+Finally:
+ GetTempName = SF_FileSystem._ConvertFromUrl(sFile)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetTempName
+
+REM -----------------------------------------------------------------------------
+Public Function HashFile(Optional ByVal FileName As Variant _
+ , Optional ByVal Algorithm As Variant _
+ ) As String
+&apos;&apos;&apos; Return an hexadecimal string representing a checksum of the given file
+&apos;&apos;&apos; Next algorithms are supported: MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file
+&apos;&apos;&apos; Algorithm: The hashing algorithm to use
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The requested checksum as a string. Hexadecimal digits are lower-cased
+&apos;&apos;&apos; A zero-length string when an error occurred
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Print SF_FileSystem.HashFile(&quot;C:\pagefile.sys&quot;, &quot;MD5&quot;)
+
+Dim sHash As String &apos; Return value
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__HashFile&quot;
+Const cstThisSub = &quot;FileSystem.HashFile&quot;
+Const cstSubArgs = &quot;FileName, Algorithm=&quot;&quot;MD5&quot;&quot;|&quot;&quot;SHA1&quot;&quot;|&quot;&quot;SHA224&quot;&quot;|&quot;&quot;SHA256&quot;&quot;|&quot;&quot;SHA384&quot;&quot;|&quot;&quot;SHA512&quot;&quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sHash = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Algorithm, &quot;Algorithm&quot;, V_STRING _
+ , Array(&quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA224&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot;)) Then GoTo Finally
+ End If
+
+Try:
+ If SF_FileSystem.FileExists(FileName) Then
+ With ScriptForge.SF_Session
+ sHash = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , _ConvertFromUrl(FileName), LCase(Algorithm))
+ End With
+ Else
+ GoTo CatchNotExists
+ End If
+
+Finally:
+ HashFile = sHash
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.HashFile
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list or methods of the FileSystem service as an array
+
+ Methods = Array(&quot;BuildPath&quot; _
+ , &quot;CompareFiles&quot; _
+ , &quot;CopyFile&quot; _
+ , &quot;CopyFolder&quot; _
+ , &quot;CreateFolder&quot; _
+ , &quot;CreateTextFile&quot; _
+ , &quot;DeleteFile&quot; _
+ , &quot;DeleteFolder&quot; _
+ , &quot;ExtensionFolder&quot; _
+ , &quot;FileExists&quot; _
+ , &quot;Files&quot; _
+ , &quot;FolderExists&quot; _
+ , &quot;GetBaseName&quot; _
+ , &quot;GetExtension&quot; _
+ , &quot;GetFileLen&quot; _
+ , &quot;GetFileModified&quot; _
+ , &quot;GetName&quot; _
+ , &quot;GetParentFolderName&quot; _
+ , &quot;GetTempName&quot; _
+ , &quot;HashFile&quot; _
+ , &quot;MoveFile&quot; _
+ , &quot;MoveFolder&quot; _
+ , &quot;OpenTextFile&quot; _
+ , &quot;PickFile&quot; _
+ , &quot;PickFolder&quot; _
+ , &quot;SubFolders&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_FileSystem.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function MoveFile(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Moves one or more files from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be moved
+&apos;&apos;&apos; Destination: FileName where the single Source file is to be moved
+&apos;&apos;&apos; If Source and Destination have the same parent folder MoveFile amounts to renaming the Source
+&apos;&apos;&apos; or FolderName where the multiple files from Source are to be moved
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one file has been moved
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.MoveFile(&quot;C:\Temp1\*.*&quot;, &quot;C:\Temp2\&quot;) &apos; Only files are moved, subfolders are not
+
+Dim bMove As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.MoveFile&quot;
+Const cstSubArgs = &quot;Source, Destination&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMove = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ End If
+
+Try:
+ bMove = SF_FileSystem._CopyMove(&quot;MoveFile&quot;, Source, Destination, False)
+
+Finally:
+ MoveFile = bMove
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.MoveFile
+
+REM -----------------------------------------------------------------------------
+Public Function MoveFolder(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Moves one or more folders from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be moved
+&apos;&apos;&apos; Destination: FolderName where the single Source folder is to be moved
+&apos;&apos;&apos; FolderName must not exist
+&apos;&apos;&apos; or FolderName where the multiple folders from Source are to be moved
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one folder has been moved
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.MoveFolder(&quot;C:\Temp1\*&quot;, &quot;C:\Temp2\&quot;)
+
+Dim bMove As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.MoveFolder&quot;
+Const cstSubArgs = &quot;Source, Destination&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMove = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ End If
+
+Try:
+ bMove = SF_FileSystem._CopyMove(&quot;MoveFolder&quot;, Source, Destination, False)
+
+Finally:
+ MoveFolder = bMove
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.MoveFolder
+
+REM -----------------------------------------------------------------------------
+Public Function OpenTextFile(Optional ByVal FileName As Variant _
+ , Optional ByVal IOMode As Variant _
+ , Optional ByVal Create As Variant _
+ , Optional ByVal Encoding As Variant _
+ ) As Object
+&apos;&apos;&apos; Opens a specified file and returns a TextStream object that can be used to read from, write to, or append to the file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to open
+&apos;&apos;&apos; IOMode: Indicates input/output mode. Can be one of three constants: ForReading, ForWriting, or ForAppending
+&apos;&apos;&apos; Create: Boolean value that indicates whether a new file can be created if the specified filename doesn&apos;t exist.
+&apos;&apos;&apos; The value is True if a new file and its parent folders may be created; False if they aren&apos;t created (default)
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
+&apos;&apos;&apos; The method does not check if the file is really a text file
+&apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice nor if it is the right one
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR File does not exist
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading)
+&apos;&apos;&apos; If Not IsNull(myFile) Then &apos; ... Go ahead with reading text lines
+
+Dim oTextStream As Object &apos; Return value
+Dim bExists As Boolean &apos; File to open does exist
+Const cstThisSub = &quot;FileSystem.OpenTextFile&quot;
+Const cstSubArgs = &quot;FileName, [IOMode=1], [Create=False], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oTextStream = Nothing
+
+Check:
+ With SF_FileSystem
+ If IsMissing(IOMode) Or IsEmpty(IOMode) Then IOMode = ForReading
+ If IsMissing(Create) Or IsEmpty(Create) Then Create = False
+ If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(IOMode, &quot;IOMode&quot;, V_NUMERIC _
+ , Array(ForReading, ForWriting, ForAppending)) _
+ Then GoTo Finally
+ If Not SF_Utils._Validate(Create, &quot;Create&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ bExists = .FileExists(FileName)
+ Select Case IOMode
+ Case ForReading : If Not bExists Then GoTo CatchNotExists
+ Case Else : If Not bExists And Not Create Then GoTo CatchNotExists
+ End Select
+
+ If IOMode = ForAppending And Not bExists Then IOMode = ForWriting
+ End With
+
+Try:
+ &apos; Create and initialize TextStream class instance
+ Set oTextStream = New SF_TextStream
+ With oTextStream
+ .[Me] = oTextStream
+ .[_Parent] = SF_FileSystem
+ ._FileName = SF_FileSystem._ConvertToUrl(FileName)
+ ._IOMode = IOMode
+ ._Encoding = Encoding
+ ._FileExists = bExists
+ ._Initialize()
+ End With
+
+Finally:
+ Set OpenTextFile = oTextStream
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.OpenTextFile
+
+REM -----------------------------------------------------------------------------
+Public Function PickFile(Optional ByVal DefaultFile As Variant _
+ , Optional ByVal Mode As Variant _
+ , Optional ByVal Filter As Variant _
+ ) As String
+&apos;&apos;&apos; Returns the file selected with a FilePicker dialog box
+&apos;&apos;&apos; The mode, OPEN or SAVE, and the filter may be preset
+&apos;&apos;&apos; If mode = SAVE and the picked file exists, a warning message will be displayed
+&apos;&apos;&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming §10.4
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DefaultFile: Folder part: the FolderName from which to start. Default = the last selected folder
+&apos;&apos;&apos; File part: the default file to open or save
+&apos;&apos;&apos; Mode: &quot;OPEN&quot; (input file) or &quot;SAVE&quot; (output file)
+&apos;&apos;&apos; Filter: by default only files having the given suffix will be displayed. Default = all suffixes
+&apos;&apos;&apos; The filter combo box will contain the given SuffixFilter (if not &quot;*&quot;) and &quot;*.*&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The selected FileName in URL format or &quot;&quot; if the dialog was cancelled
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.PickFile(&quot;C:\&quot;, &quot;OPEN&quot;, &quot;txt&quot;) &apos; Only *.txt files are displayed
+
+Dim oFileDialog As Object &apos; com.sun.star.ui.dialogs.FilePicker
+Dim oFileAccess As object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim oPath As Object &apos; com.sun.star.util.PathSettings
+Dim iAccept As Integer &apos; Result of dialog execution
+Dim sInitPath As String &apos; Current working directory
+Dim sBaseFile As String
+Dim iMode As Integer &apos; Numeric alias for SelectMode
+Dim sFile As String &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.PickFile&quot;
+Const cstSubArgs = &quot;[DefaultFile=&quot;&quot;&quot;&quot;], [Mode=&quot;&quot;OPEN&quot;&quot;|&quot;&quot;SAVE&quot;&quot;],[Filter=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFile = &quot;&quot;
+
+Check:
+ If IsMissing(DefaultFile) Or IsEmpty(DefaultFile) Then DefaultFile = &quot;&quot;
+ If IsMissing(Mode) Or IsEmpty(Mode) Then Mode = &quot;OPEN&quot;
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(DefaultFile, &quot;DefaultFile&quot;, , True) Then GoTo Finally
+ If Not SF_Utils._Validate(Mode, &quot;Mode&quot;, V_STRING, Array(&quot;OPEN&quot;, &quot;SAVE&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ End If
+ DefaultFile = SF_FileSystem._ConvertToUrl(DefaultFile)
+
+Try:
+ &apos; Derive numeric equivalent of the Mode argument: https://api.libreoffice.org/docs/idl/ref/TemplateDescription_8idl.html
+ With com.sun.star.ui.dialogs.TemplateDescription
+ If Mode = &quot;OPEN&quot; Then iMode = .FILEOPEN_SIMPLE Else iMode = .FILESAVE_AUTOEXTENSION
+ End With
+
+ &apos; Activate the filepicker dialog
+ Set oFileDialog = SF_Utils._GetUNOService(&quot;FilePicker&quot;)
+ With oFileDialog
+ .Initialize(Array(iMode))
+
+ &apos; Set filters
+ If Len(Filter) &gt; 0 Then .appendFilter(&quot;*.&quot; &amp; Filter, &quot;*.&quot; &amp; Filter) &apos; Twice: required by API
+ .appendFilter(&quot;*.*&quot;, &quot;*.*&quot;)
+ If Len(Filter) &gt; 0 Then .setCurrentFilter(&quot;*.&quot; &amp; Filter) Else .setCurrentFilter(&quot;*.*&quot;)
+
+ &apos; Set initial folder
+ If Len(DefaultFile) = 0 Then &apos; TODO: SF_Session.WorkingFolder
+ Set oPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;)
+ sInitPath = oPath.Work &apos; Probably My Documents
+ Else
+ sInitPath = SF_FileSystem._ParseUrl(ConvertToUrl(DefaultFile)).Path
+ End If
+
+ &apos; Set default values
+ Set oFileAccess = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
+ If oFileAccess.exists(sInitPath) Then .SetDisplayDirectory(sInitPath)
+ sBaseFile = SF_FileSystem.GetName(DefaultFile)
+ .setDefaultName(sBaseFile)
+
+ &apos; Get selected file
+ iAccept = .Execute()
+ If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then sFile = .getSelectedFiles()(0)
+ End With
+
+Finally:
+ PickFile = SF_FileSystem._ConvertFromUrl(sFile)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.PickFile
+
+REM -----------------------------------------------------------------------------
+Public Function PickFolder(Optional ByVal DefaultFolder As Variant _
+ , Optional ByVal FreeText As Variant _
+ ) As String
+&apos;&apos;&apos; Display a FolderPicker dialog box
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DefaultFolder: the FolderName from which to start. Default = the last selected folder
+&apos;&apos;&apos; FreeText: text to display in the dialog. Default = &quot;&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The selected FolderName in URL or operating system format
+&apos;&apos;&apos; The zero-length string if the dialog was cancelled
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.PickFolder(&quot;C:\&quot;, &quot;Choose a folder or press Cancel&quot;)
+
+Dim oFolderDialog As Object &apos; com.sun.star.ui.dialogs.FolderPicker
+Dim iAccept As Integer &apos; Value returned by the dialog (OK, Cancel, ..)
+Dim sFolder As String &apos; Return value &apos;
+
+Const cstThisSub = &quot;FileSystem.PickFolder&quot;
+Const cstSubArgs = &quot;[DefaultFolder=&quot;&quot;&quot;&quot;], [FreeText=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFolder = &quot;&quot;
+
+Check:
+ If IsMissing(DefaultFolder) Or IsEmpty(DefaultFolder) Then DefaultFolder = &quot;&quot;
+ If IsMissing(FreeText) Or IsEmpty(FreeText) Then FreeText = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(DefaultFolder, &quot;DefaultFolder&quot;, , True) Then GoTo Finally
+ If Not SF_Utils._Validate(FreeText, &quot;FreeText&quot;, V_STRING) Then GoTo Finally
+ End If
+ DefaultFolder = SF_FileSystem._ConvertToUrl(DefaultFolder)
+
+Try:
+ Set oFolderDialog = SF_Utils._GetUNOService(&quot;FolderPicker&quot;)
+ If Not IsNull(oFolderDialog) Then
+ With oFolderDialog
+ If Len(DefaultFolder) &gt; 0 Then .DisplayDirectory = ConvertToUrl(DefaultFolder)
+ .Description = FreeText
+ iAccept = .Execute()
+ &apos; https://api.libreoffice.org/docs/idl/ref/ExecutableDialogResults_8idl.html
+ If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then
+ .DisplayDirectory = .Directory &apos; Set the next default initial folder to the selected one
+ sFolder = .Directory &amp; &quot;/&quot;
+ End If
+ End With
+ End If
+
+Finally:
+ PickFolder = SF_FileSystem._ConvertFromUrl(sFolder)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.PickFolder
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the FileSystem module as an array
+
+ Properties = Array( _
+ &quot;ConfigFolder&quot; _
+ , &quot;ExtensionsFolder&quot; _
+ , &quot;FileNaming&quot; _
+ , &quot;HomeFolder&quot; _
+ , &quot;InstallFolder&quot; _
+ , &quot;TemplatesFolder&quot; _
+ , &quot;TemporaryFolder&quot; _
+ , &quot;UserTemplatesFolder&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_FileSystem.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;FileSystem.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 UCase(&quot;FileNaming&quot;) : FileNaming = Value
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function SubFolders(Optional ByVal FolderName As Variant _
+ , Optional ByVal Filter As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return an array of the FolderNames stored in the given folder. The folder must exist
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: the folder to explore
+&apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant folders (default = &quot;&quot;)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array of strings, each entry is the FolderName of an existing folder
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
+&apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Variant
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.SubFolders(&quot;C:\Windows\&quot;)
+
+Dim vSubFolders As Variant &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFolderName As String &apos; URL lias for FolderName
+Dim sFolder As String &apos; Single folder
+Dim i As Long
+
+Const cstThisSub = &quot;FileSystem.SubFolders&quot;
+Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSubFolders = Array()
+
+Check:
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ End If
+ sFolderName = SF_FileSystem._ConvertToUrl(FolderName)
+ If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
+ If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
+
+Try:
+ &apos; Get SubFolders
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ vSubFolders = oSfa.getFolderContents(sFolderName, True)
+ &apos; List includes files; remove them or adjust notations of folders
+ For i = 0 To UBound(vSubFolders)
+ sFolder = SF_FileSystem._ConvertFromUrl(vSubFolders(i) &amp; &quot;/&quot;)
+ If SF_FileSystem.FileExists(sFolder) Then vSubFolders(i) = &quot;&quot; Else vSubFolders(i) = sFolder
+ &apos; Reduce list to those passing the filter
+ If Len(Filter) &gt; 0 And Len(vSubFolders(i)) &gt; 0 Then
+ sFolder = SF_FileSystem.GetName(vSubFolders(i))
+ If Not SF_String.IsLike(sFolder, Filter) Then vSubFolders(i) = &quot;&quot;
+ End If
+ Next i
+ vSubFolders = SF_Array.TrimArray(vSubFolders)
+
+Finally:
+ SubFolders = vSubFolders
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchFile:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+CatchFolder:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.SubFolders
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertFromUrl(psFile) As String
+&apos;&apos;&apos; Execute the builtin ConvertFromUrl function only when relevant
+&apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) = &quot;SYS&quot;
+&apos;&apos;&apos; Called at the bottom of methods returning file names
+&apos;&apos;&apos; Remark: psFile might contain wildcards
+
+Const cstQuestion = &quot;$QUESTION$&quot;, cstStar = &quot;$STAR$&quot; &apos; Special tokens to replace wildcards
+
+ If SF_FileSystem.FileNaming = &quot;SYS&quot; Then
+ _ConvertFromUrl = Replace(Replace( _
+ ConvertFromUrl(Replace(Replace(psFile, &quot;?&quot;, cstQuestion), &quot;*&quot;, cstStar)) _
+ , cstQuestion, &quot;?&quot;), cstStar, &quot;*&quot;)
+ Else
+ _ConvertFromUrl = psFile
+ End If
+
+End Function &apos; ScriptForge.FileSystem._ConvertFromUrl
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertToUrl(psFile) As String
+&apos;&apos;&apos; Execute the builtin ConvertToUrl function only when relevant
+&apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) = &quot;SYS&quot;
+&apos;&apos;&apos; Called at the top of methods receiving file names as arguments
+&apos;&apos;&apos; Remark: psFile might contain wildcards
+
+ If SF_FileSystem.FileNaming = &quot;URL&quot; Then
+ _ConvertToUrl = psFile
+ Else
+ &apos; ConvertToUrl encodes &quot;?&quot;
+ _ConvertToUrl = Replace(ConvertToUrl(psFile), &quot;%3F&quot;, &quot;?&quot;)
+ End If
+
+End Function &apos; ScriptForge.FileSystem._ConvertToUrl
+
+REM -----------------------------------------------------------------------------
+Private Function _CopyMove(psMethod As String _
+ , psSource As String _
+ , psDestination As String _
+ , pbOverWrite As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Checks the arguments and executes the given method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
+&apos;&apos;&apos; psSource: Either File/FolderName
+&apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be copied
+&apos;&apos;&apos; psDestination: FileName or FolderName for copy/move of a single file/folder
+&apos;&apos;&apos; Otherwise a destination FolderName. If it does not exist, it is created
+&apos;&apos;&apos; pbOverWrite: If True, files/folders may be overwritten
+&apos;&apos;&apos; Must be False for Move operations
+&apos;&apos;&apos; Next checks are done:
+&apos;&apos;&apos; With wildcards (multiple files/folders):
+&apos;&apos;&apos; - Parent folder of source must exist
+&apos;&apos;&apos; - Destination must not be a file
+&apos;&apos;&apos; - Parent folder of Destination must exist
+&apos;&apos;&apos; - If the Destination folder does not exist a new folder is created,
+&apos;&apos;&apos; - At least one file matches the wildcards expression
+&apos;&apos;&apos; - Destination files/folder must not exist if pbOverWrite = False
+&apos;&apos;&apos; - Destination files/folders must not have the read-only attribute set
+&apos;&apos;&apos; - Destination files must not be folders, destination folders must not be files
+&apos;&apos;&apos; Without wildcards (single file/folder):
+&apos;&apos;&apos; - Source file/folder must exist and be a file/folder
+&apos;&apos;&apos; - Parent folder of Destination must exist
+&apos;&apos;&apos; - Destination must not be an existing folder/file
+&apos;&apos;&apos; - Destination file/folder must not exist if pbOverWrite = False
+&apos;&apos;&apos; - Destination file must not have the read-only attribute set
+
+Dim bCopyMove As Boolean &apos; Return value
+Dim bCopy As Boolean &apos; True if Copy, False if Move
+Dim bFile As Boolean &apos; True if File, False if Folder
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim bWildCards As Boolean &apos; True if wildcards found in Source
+Dim bCreateFolder As Boolean &apos; True when the destination folder should be created
+Dim bDestExists As Boolean &apos; True if destination exists
+Dim sSourceUrl As String &apos; Alias for Source
+Dim sDestinationUrl As String &apos; Alias for Destination
+Dim sDestinationFile As String &apos; Destination FileName
+Dim sParentFolder As String &apos; Parent folder of Source
+Dim vFiles As Variant &apos; Array of candidates for copy/move
+Dim sFile As String &apos; Single file/folder
+Dim sName As String &apos; Name (last component) of file
+Dim i As Long
+
+ &apos; Error handling left to calling routine
+ bCopyMove = False
+ bCopy = ( Left(psMethod, 4) = &quot;Copy&quot; )
+ bFile = ( Right(psMethod, 4) = &quot;File&quot; )
+ bWildCards = ( InStr(psSource, &quot;*&quot;) + InStr(psSource, &quot;?&quot;) + InStr(psSource, &quot;%3F&quot;) &gt; 0 ) &apos;ConvertToUrl() converts sometimes &quot;?&quot; to &quot;%3F&quot;
+ bDestExists = False
+
+ With SF_FileSystem
+
+Check:
+ If bWildCards Then
+ sParentFolder = .GetParentFolderName(psSource)
+ If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
+ If .FileExists(psDestination) Then GoTo CatchFileNotFolder
+ If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
+ bCreateFolder = Not .FolderExists(psDestination)
+ Else
+ Select Case bFile
+ Case True &apos; File
+ If Not .FileExists(psSource) Then GoTo CatchFileNotExists
+ If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchSourceFolderNotExists
+ If .FolderExists(psDestination) Then GoTo CatchFolderNotFile
+ bDestExists = .FileExists(psDestination)
+ If pbOverWrite = False And bDestExists = True Then GoTo CatchDestinationExists
+ bCreateFolder = False
+ Case False &apos; Folder
+ If Not .FolderExists(psSource) Then GoTo CatchSourceFolderNotExists
+ If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
+ If .FileExists(psDestination) Then GoTo CatchFileNotFolder
+ bDestExists = .FolderExists(psDestination)
+ If pbOverWrite = False And bDestExists Then GoTo CatchDestinationExists
+ bCreateFolder = Not bDestExists
+ End Select
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If bWildCards Then
+ If bFile Then vFiles = .Files(sParentFolder, .GetName(psSource)) Else vFiles = .SubFolders(sParentFolder, .GetName(psSource))
+ If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
+ &apos; Go through the candidates
+ If bCreateFolder Then .CreateFolder(psDestination)
+ For i = 0 To UBound(vFiles)
+ sFile = vFiles(i)
+ sDestinationFile = .BuildPath(psDestination, .GetName(sFile))
+ If bFile Then bDestExists = .FileExists(sDestinationFile) Else bDestExists = .FolderExists(sDestinationFile)
+ If pbOverWrite = False Then
+ If bDestExists Then GoTo CatchDestinationExists
+ If .FolderExists(sDestinationFile) Then GoTo CatchDestinationExists
+ End If
+ sSourceUrl = ._ConvertToUrl(sFile)
+ sDestinationUrl = ._ConvertToUrl(sDestinationFile)
+ If bDestExists Then
+ If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
+ End If
+ Select Case bCopy
+ Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
+ Case False : oSfa.move(sSourceUrl, sDestinationUrl)
+ End Select
+ Next i
+ Else
+ sSourceUrl = ._ConvertToUrl(psSource)
+ sDestinationUrl = ._ConvertToUrl(psDestination)
+ If bDestExists Then
+ If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
+ End If
+ If bCreateFolder Then .CreateFolder(psDestination)
+ Select Case bCopy
+ Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
+ Case False : oSfa.move(sSourceUrl, sDestinationUrl)
+ End Select
+ End If
+
+ End With
+
+ bCopyMove = True
+
+Finally:
+ _CopyMove = bCopyMove
+ Exit Function
+CatchFileNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;Source&quot;, psSource)
+ GoTo Finally
+CatchSourceFolderNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Source&quot;, psSource)
+ GoTo Finally
+CatchDestFolderNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchFolderNotFile:
+ SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchDestinationExists:
+ SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchNoMatch:
+ SF_Exception.RaiseFatal(NOFILEMATCHERROR, &quot;Source&quot;, psSource)
+ GoTo Finally
+CatchFileNotFolder:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchDestinationReadOnly:
+ SF_Exception.RaiseFatal(READONLYERROR, &quot;Destination&quot;, Iif(bWildCards, sDestinationFile, psDestination))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem._CopyMove
+
+REM -----------------------------------------------------------------------------
+Public Function _CountTextLines(ByVal psFileName As String _
+ , Optional ByVal pbIncludeBlanks As Boolean _
+ ) As Long
+&apos;&apos;&apos; Convenient function to count the number of lines in a textfile
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psFileName: the file in FileNaming notation
+&apos;&apos;&apos; pbIncludeBlanks: if True (default), zero-length lines are included
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The number of lines, f.i. to ease array sizing. -1 if file reading error
+
+Dim lLines As Long &apos; Return value
+Dim oFile As Object &apos; File handler
+Dim sLine As String &apos; The last line read
+
+Try:
+ lLines = 0
+ If IsMissing(pbIncludeBlanks) Then pbIncludeBlanks = True
+ Set oFile = SF_FileSystem.OpenTextFile(psFileName, ForReading)
+ With oFile
+ If Not IsNull(oFile) Then
+ Do While Not .AtEndOfStream
+ sLine = .ReadLine()
+ lLines = lLines + Iif(Len(sLine) &gt; 0 Or pbIncludeBlanks, 1, 0)
+ Loop
+ End If
+ .CloseFile()
+ Set oFile = .Dispose()
+ End With
+
+Finally:
+ _CountTextLines = lLines
+ Exit Function
+End Function &apos; ScriptForge.SF_FileSystem._CountTextLines
+
+REM -----------------------------------------------------------------------------
+Private Function _Delete(psMethod As String _
+ , psFile As String _
+ ) As Boolean
+&apos;&apos;&apos; Checks the argument and executes the given psMethod
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
+&apos;&apos;&apos; psFile: Either File/FolderName
+&apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be deleted
+&apos;&apos;&apos; Next checks are done:
+&apos;&apos;&apos; With wildcards (multiple files/folders):
+&apos;&apos;&apos; - Parent folder of File must exist
+&apos;&apos;&apos; - At least one file matches the wildcards expression
+&apos;&apos;&apos; - Files or folders to delete must not have the read-only attribute set
+&apos;&apos;&apos; Without wildcards (single file/folder):
+&apos;&apos;&apos; - File/folder must exist and be a file/folder
+&apos;&apos;&apos; - A file or folder to delete must not have the read-only attribute set
+
+Dim bDelete As Boolean &apos; Return value
+Dim bFile As Boolean &apos; True if File, False if Folder
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim bWildCards As Boolean &apos; True if wildcards found in File
+Dim sFileUrl As String &apos; Alias for File
+Dim sParentFolder As String &apos; Parent folder of File
+Dim vFiles As Variant &apos; Array of candidates for deletion
+Dim sFile As String &apos; Single file/folder
+Dim sName As String &apos; Name (last component) of file
+Dim i As Long
+
+ &apos; Error handling left to calling routine
+ bDelete = False
+ bFile = ( Right(psMethod, 4) = &quot;File&quot; )
+ bWildCards = ( InStr(psFile, &quot;*&quot;) + InStr(psFile, &quot;?&quot;) + InStr(psFile, &quot;%3F&quot;) &gt; 0 ) &apos;ConvertToUrl() converts sometimes &quot;?&quot; to &quot;%3F&quot;
+
+ With SF_FileSystem
+
+Check:
+ If bWildCards Then
+ sParentFolder = .GetParentFolderName(psFile)
+ If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
+ Else
+ Select Case bFile
+ Case True &apos; File
+ If .FolderExists(psFile) Then GoTo CatchFolderNotFile
+ If Not .FileExists(psFile) Then GoTo CatchFileNotExists
+ Case False &apos; Folder
+ If .FileExists(psFile) Then GoTo CatchFileNotFolder
+ If Not .FolderExists(psFile) Then GoTo CatchFolderNotExists
+ End Select
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If bWildCards Then
+ If bFile Then vFiles = .Files(sParentFolder) Else vFiles = .SubFolders(sParentFolder)
+ &apos; Select candidates
+ For i = 0 To UBound(vFiles)
+ If Not SF_String.IsLike(.GetName(vFiles(i)), .GetName(psFile)) Then vFiles(i) = &quot;&quot;
+ Next i
+ vFiles = SF_Array.TrimArray(vFiles)
+ If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
+ &apos; Go through the candidates
+ For i = 0 To UBound(vFiles)
+ sFile = vFiles(i)
+ sFileUrl = ._ConvertToUrl(sFile)
+ If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
+ oSfa.kill(sFileUrl)
+ Next i
+ Else
+ sFileUrl = ._ConvertToUrl(psFile)
+ If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
+ oSfa.kill(sFileUrl)
+ End If
+
+ End With
+
+ bDelete = True
+
+Finally:
+ _Delete = bDelete
+ Exit Function
+CatchFolderNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, psFile)
+ GoTo Finally
+CatchFileNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, psFile)
+ GoTo Finally
+CatchFolderNotFile:
+ SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;FileName&quot;, psFile)
+ GoTo Finally
+CatchNoMatch:
+ SF_Exception.RaiseFatal(NOFILEMATCHERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), psFile)
+ GoTo Finally
+CatchFileNotFolder:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, psFile)
+ GoTo Finally
+CatchReadOnly:
+ SF_Exception.RaiseFatal(READONLYERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), Iif(bWildCards, sFile, psFile))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem._Delete
+
+REM -----------------------------------------------------------------------------
+Private Function _GetConfigFolder(ByVal psFolder As String) As String
+&apos;&apos;&apos; Returns one of next configuration folders: see https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1util_1_1PathSubstitution.html
+&apos;&apos;&apos; inst =&gt; Installation path of LibreOffice
+&apos;&apos;&apos; prog =&gt; Program path of LibreOffice
+&apos;&apos;&apos; user =&gt; The user installation/config directory
+&apos;&apos;&apos; work =&gt; The work directory of the user. Under Windows this would be the &quot;MyDocuments&quot; subdirectory. Under Unix this would be the home-directory
+&apos;&apos;&apos; home =&gt; The home directory of the user. Under Unix this would be the home- directory.
+&apos;&apos;&apos; Under Windows this would be the CSIDL_PERSONAL directory, for example &quot;Documents and Settings\&lt;username&gt;\Documents&quot;
+&apos;&apos;&apos; temp =&gt; The current temporary directory
+
+Dim oSubst As Object &apos; com.sun.star.util.PathSubstitution
+Dim sConfig As String &apos; Return value
+
+ sConfig = &quot;&quot;
+ Set oSubst = SF_Utils._GetUNOService(&quot;PathSubstitution&quot;)
+ If Not IsNull(oSubst) Then sConfig = oSubst.getSubstituteVariableValue(&quot;$(&quot; &amp; psFolder &amp; &quot;)&quot;) &amp; &quot;/&quot;
+
+ _GetConfigFolder = SF_FileSystem._ConvertFromUrl(sConfig)
+
+End Function &apos; ScriptForge.FileSystem._GetConfigFolder
+
+REM -----------------------------------------------------------------------------
+Public Function _ParseUrl(psUrl As String) As Object
+&apos;&apos;&apos; Returns a com.sun.star.util.URL structure based on the argument
+
+Dim oParse As Object &apos; com.sun.star.util.URLTransformer
+Dim bParsed As Boolean &apos; True if parsing is successful
+Dim oUrl As New com.sun.star.util.URL &apos; Return value
+
+ oUrl.Complete = psUrl
+ Set oParse = SF_Utils._GetUNOService(&quot;URLTransformer&quot;)
+ bParsed = oParse.parseStrict(oUrl, &quot;&quot;)
+ If bParsed Then oUrl.Path = ConvertToUrl(oUrl.Path)
+
+ Set _ParseUrl = oUrl
+
+End Function &apos; ScriptForge.SF_FileSystem._ParseUrl
+
+REM -----------------------------------------------------------------------------
+Public Function _SFInstallFolder() As String
+&apos;&apos;&apos; Returns the installation folder of the ScriptForge library
+&apos;&apos;&apos; Either:
+&apos;&apos;&apos; - The library is present in [My Macros &amp; Dialogs]
+&apos;&apos;&apos; ($config)/basic/ScriptForge
+&apos;&apos;&apos; - The library is present in [LibreOffice Macros &amp; Dialogs]
+&apos;&apos;&apos; ($install)/share/basic/ScriptForge
+
+Dim sFolder As String &apos; Folder
+
+ _SFInstallFolder = &quot;&quot;
+
+ sFolder = BuildPath(ConfigFolder, &quot;basic/ScriptForge&quot;)
+ If Not FolderExists(sFolder) Then
+ sFolder = BuildPath(InstallFolder, &quot;share/basic/ScriptForge&quot;)
+ If Not FolderExists(sFolder) Then Exit Function
+ End If
+
+ _SFInstallFolder = _ConvertFromUrl(sFolder)
+
+End Function &apos; ScriptForge.SF_FileSystem._SFInstallFolder
+
+REM ============================================ END OF SCRIPTFORGE.SF_FileSystem
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_L10N.xba b/wizards/source/scriptforge/SF_L10N.xba
new file mode 100644
index 000000000..6bc6b236f
--- /dev/null
+++ b/wizards/source/scriptforge/SF_L10N.xba
@@ -0,0 +1,825 @@
+<?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_L10N" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+&apos;Option Private Module
+
+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; L10N (aka SF_L10N)
+&apos;&apos;&apos; ====
+&apos;&apos;&apos; Implementation of a Basic class for providing a number of services
+&apos;&apos;&apos; related to the translation of user interfaces into a huge number of languages
+&apos;&apos;&apos; with a minimal impact on the program code itself
+&apos;&apos;&apos;
+&apos;&apos;&apos; The design choices of this module are based on so-called PO-files
+&apos;&apos;&apos; PO-files (portable object files) have long been promoted in the free software industry
+&apos;&apos;&apos; as a mean of providing multilingual UIs. This is accomplished through the use of human-readable
+&apos;&apos;&apos; text files with a well defined structure that specifies, for any given language,
+&apos;&apos;&apos; the source language string and the localized string
+&apos;&apos;&apos;
+&apos;&apos;&apos; To read more about the PO format and its ecosystem of associated toolsets:
+&apos;&apos;&apos; https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html#PO-Files
+&apos;&apos;&apos; and, IMHO, a very good tutorial:
+&apos;&apos;&apos; http://pology.nedohodnik.net/doc/user/en_US/ch-about.html
+&apos;&apos;&apos;
+&apos;&apos;&apos; The main advantage of the PO format is the complete dissociation between the two
+&apos;&apos;&apos; very different profiles, i.e. the programmer and the translator(s).
+&apos;&apos;&apos; Being independent text files, one per language to support, the programmer may give away
+&apos;&apos;&apos; pristine PO template files (known as POT-files) for a translator to process.
+&apos;&apos;&apos;
+&apos;&apos;&apos; This class implements mainly 4 mechanisms:
+&apos;&apos;&apos; 1. AddText: for the programmer to build a set of words or sentences
+&apos;&apos;&apos; meant for being translated later
+&apos;&apos;&apos; 2. AddTextsFromDialog: to automatically execute AddText() on each fixed text of a dialog
+&apos;&apos;&apos; 3. ExportToPOTFile: All the above texts are exported into a pristine POT-file
+&apos;&apos;&apos; 4. GetText: At runtime get the text in the user language
+&apos;&apos;&apos; Note that the first two are optional: POT and PO-files may be built with a simple text editor
+&apos;&apos;&apos;
+&apos;&apos;&apos; Several instances of the L10N class may coexist
+&apos; The constraint however is that each instance should find its PO-files
+&apos;&apos;&apos; in a separate directory
+&apos;&apos;&apos; PO-files must be named with the targeted locale: f.i. &quot;en-US.po&quot; or &quot;fr-BE.po&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation syntax
+&apos;&apos;&apos; CreateScriptService(&quot;L10N&quot;[, FolderName[, Locale]])
+&apos;&apos;&apos; FolderName: the folder containing the PO-files (in SF_FileSystem.FileNaming notation)
+&apos;&apos;&apos; Locale: in the form la-CO (language-COUNTRY)
+&apos;&apos;&apos; Encoding: The character set that should be used (default = UTF-8)
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Locale2: fallback Locale to select if Locale po file does not exist (typically &quot;en-US&quot;)
+&apos;&apos;&apos; Encoding2: Encoding of the 2nd Locale file
+&apos;&apos;&apos; Service invocation examples:
+&apos;&apos;&apos; Dim myPO As Variant
+&apos;&apos;&apos; myPO = CreateScriptService(&quot;L10N&quot;) &apos; AddText, AddTextsFromDialog and ExportToPOTFile are allowed
+&apos;&apos;&apos; myPO = CreateScriptService(&quot;L10N&quot;, &quot;C:\myPOFiles\&quot;, &quot;fr-BE&quot;)
+&apos;&apos;&apos; &apos;All functionalities are available
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_l10n.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM =============================================================== PRIVATE TYPES
+
+&apos;&apos;&apos; The recognized elements of an entry in a PO file are (other elements are ignored) :
+&apos;&apos;&apos; #. Extracted comments (given by the programmer to the translator)
+&apos;&apos;&apos; #, flag (the kde-format flag when the string contains tokens)
+&apos;&apos;&apos; msgctxt Context (to store an acronym associated with the message, this is a distortion of the norm)
+&apos;&apos;&apos; msgid untranslated-string
+&apos;&apos;&apos; msgstr translated-string
+&apos;&apos;&apos; NB: plural forms are not supported
+
+Type POEntry
+ Comment As String
+ Flag As String
+ Context As String
+ MsgId As String
+ MsgStr As String
+End Type
+
+REM ================================================================== EXCEPTIONS
+
+Const DUPLICATEKEYERROR = &quot;DUPLICATEKEYERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be &quot;L10N&quot;
+Private ServiceName As String
+Private _POFolder As String &apos; PO files container
+Private _Locale As String &apos; la-CO
+Private _POFile As String &apos; PO file in URL format
+Private _Encoding As String &apos; Used to open the PO file, default = UTF-8
+Private _Dictionary As Object &apos; SF_Dictionary
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;L10N&quot;
+ ServiceName = &quot;ScriptForge.L10N&quot;
+ _POFolder = &quot;&quot;
+ _Locale = &quot;&quot;
+ _POFile = &quot;&quot;
+ Set _Dictionary = Nothing
+End Sub &apos; ScriptForge.SF_L10N Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+
+ If Not IsNull(_Dictionary) Then Set _Dictionary = _Dictionary.Dispose()
+ Call Class_Initialize()
+End Sub &apos; ScriptForge.SF_L10N Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_L10N Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Folder() As String
+&apos;&apos;&apos; Returns the FolderName containing the PO-files expressed as given by the current FileNaming
+&apos;&apos;&apos; property of the SF_FileSystem service. Default = URL format
+&apos;&apos;&apos; May be empty
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myPO.Folder
+
+ Folder = _PropertyGet(&quot;Folder&quot;)
+
+End Property &apos; ScriptForge.SF_L10N.Folder
+
+REM -----------------------------------------------------------------------------
+Property Get Languages() As Variant
+&apos;&apos;&apos; Returns a zero-based array listing all the BaseNames of the PO-files found in Folder,
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myPO.Languages
+
+ Languages = _PropertyGet(&quot;Languages&quot;)
+
+End Property &apos; ScriptForge.SF_L10N.Languages
+
+REM -----------------------------------------------------------------------------
+Property Get Locale() As String
+&apos;&apos;&apos; Returns the currently active language-COUNTRY combination. May be empty
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myPO.Locale
+
+ Locale = _PropertyGet(&quot;Locale&quot;)
+
+End Property &apos; ScriptForge.SF_L10N.Locale
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function AddText(Optional ByVal Context As Variant _
+ , Optional ByVal MsgId As Variant _
+ , Optional ByVal Comment As Variant _
+ , Optional ByVal MsgStr As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Add a new entry in the list of localizable text strings
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Context: when not empty, the key to retrieve the translated string via GetText. Default = &quot;&quot;
+&apos;&apos;&apos; MsgId: the untranslated string, i.e. the text appearing in the program code. Must not be empty
+&apos;&apos;&apos; The key to retrieve the translated string via GetText when Context is empty
+&apos;&apos;&apos; May contain placeholders (%1 ... %9) for dynamic arguments to be inserted in the text at run-time
+&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
+&apos;&apos;&apos; Comment: the so-called &quot;extracted-comments&quot; intended to inform/help translators
+&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
+&apos;&apos;&apos; MsgStr: (internal use only) the translated string
+&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myPO.AddText(, &quot;This is a text to be included in a POT file&quot;)
+
+Dim bAdd As Boolean &apos; Output buffer
+Dim sKey As String &apos; The key part of the new entry in the dictionary
+Dim vItem As POEntry &apos; The item part of the new entry in the dictionary
+Const cstPipe = &quot;|&quot; &apos; Pipe forbidden in MsgId&apos;s
+Const cstThisSub = &quot;L10N.AddText&quot;
+Const cstSubArgs = &quot;[Context=&quot;&quot;&quot;&quot;], MsgId, [Comment=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bAdd = False
+
+Check:
+ If IsMissing(Context) Or IsMissing(Context) Then Context = &quot;&quot;
+ If IsMissing(Comment) Or IsMissing(Comment) Then Comment = &quot;&quot;
+ If IsMissing(MsgStr) Or IsMissing(MsgStr) Then MsgStr = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Context, &quot;Context&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(MsgId, &quot;MsgId&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Comment, &quot;Comment&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(MsgStr, &quot;MsgStr&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(MsgId) = 0 Then GoTo Finally
+
+Try:
+ If Len(Context) &gt; 0 Then sKey = Context Else sKey = MsgId
+ If _Dictionary.Exists(sKey) Then GoTo CatchDuplicate
+
+ With vItem
+ .Comment = Comment
+ If InStr(MsgId, &quot;%&quot;) &gt; 0 Then .Flag = &quot;kde-format&quot; Else .Flag = &quot;&quot;
+ .Context = Replace(Context, cstPipe, &quot; &quot;)
+ .MsgId = Replace(MsgId, cstPipe, &quot; &quot;)
+ .MsgStr = MsgStr
+ End With
+ _Dictionary.Add(sKey, vItem)
+ bAdd = True
+
+Finally:
+ AddText = bAdd
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchDuplicate:
+ SF_Exception.RaiseFatal(DUPLICATEKEYERROR, Iif(Len(Context) &gt; 0, &quot;Context&quot;, &quot;MsgId&quot;), sKey)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N.AddText
+
+REM -----------------------------------------------------------------------------
+Public Function AddTextsFromDialog(Optional ByRef Dialog As Variant) As Boolean
+&apos;&apos;&apos; Add all fixed text strings of a dialog to the list of localizable text strings
+&apos;&apos;&apos; Added texts are:
+&apos;&apos;&apos; - the title of the dialog
+&apos;&apos;&apos; - the caption associated with next control types: Button, CheckBox, FixedLine, FixedText, GroupBox and RadioButton
+&apos;&apos;&apos; - the content of list- and comboboxes
+&apos;&apos;&apos; - the tip- or helptext displayed when the mouse is hovering the control
+&apos;&apos;&apos; The current method has method SFDialogs.SF_Dialog.GetTextsFromL10N as counterpart
+&apos;&apos;&apos; The targeted dialog must not be open when the current method is run
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Dialog: a SFDialogs.Dialog service instance
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myDialog As Object
+&apos;&apos;&apos; Set myDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, &quot;GlobalScope&quot;, &quot;XrayTool&quot;, &quot;DlgXray&quot;)
+&apos;&apos;&apos; myPO.AddTextsFromDialog(myDialog)
+
+Dim bAdd As Boolean &apos; Return value
+Dim vControls As Variant &apos; Array of control names
+Dim sControl As String &apos; A single control name
+Dim oControl As Object &apos; SFDialogs.DialogControl
+Dim sText As String &apos; The text to insert in the dictionary
+Dim sDialogComment As String &apos; The prefix in the comment to insert in the dictionary for the dialog
+Dim sControlComment As String &apos; The prefix in the comment to insert in the dictionary for a control
+Dim vSource As Variant &apos; RowSource property of dialog control as an array
+Dim i As Long
+
+Const cstThisSub = &quot;L10N.AddTextsFromDialog&quot;
+Const cstSubArgs = &quot;Dialog&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bAdd = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Dialog, &quot;Dialog&quot;, V_OBJECT, , , &quot;DIALOG&quot;) Then GoTo Finally
+ End If
+
+Try:
+ With Dialog
+ &apos; Store the title of the dialog
+ sDialogComment = &quot;Dialog =&gt; &quot; &amp; ._Container &amp; &quot; : &quot; &amp; ._Library &amp; &quot; : &quot; &amp; ._Name &amp; &quot; : &quot;
+ stext = .Caption
+ If Len(sText) &gt; 0 Then
+ If Not _ReplaceText(&quot;&quot;, sText, sDialogComment &amp; &quot;Caption&quot;) Then GoTo Catch
+ End If
+ &apos; Scan all controls
+ vControls = .Controls()
+ For Each sControl In vControls
+ Set oControl = .Controls(sControl)
+ sControlComment = sDialogComment &amp; sControl &amp; &quot;.&quot;
+ With oControl
+ &apos; Extract fixed texts
+ sText = .Caption
+ If Len(sText) &gt; 0 Then
+ If Not _ReplaceText(&quot;&quot;, sText, sControlComment &amp; &quot;Caption&quot;) Then GoTo Catch
+ End If
+ vSource = .RowSource &apos; List and comboboxes only
+ If IsArray(vSource) Then
+ For i = 0 To UBound(vSource)
+ If Len(vSource(i)) &gt; 0 Then
+ If Not _ReplaceText(&quot;&quot;, vSource(i), sControlComment &amp; &quot;RowSource[&quot; &amp; i &amp; &quot;]&quot;) Then GoTo Catch
+ End If
+ Next i
+ End If
+ sText = .TipText
+ If Len(sText) &gt; 0 Then
+ If Not _ReplaceText(&quot;&quot;, sText, sControlComment &amp; &quot;TipText&quot;) Then GoTo Catch
+ End If
+ End With
+ Next sControl
+ End With
+
+ bAdd = True
+
+Finally:
+ AddTextsFromDialog = bAdd
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N.AddTextsFromDialog
+
+REM -----------------------------------------------------------------------------
+Public Function ExportToPOTFile(Optional ByVal FileName As Variant _
+ , Optional ByVal Header As Variant _
+ , Optional ByVal Encoding As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Export a set of untranslated strings as a POT file
+&apos;&apos;&apos; The set of strings has been built either by a succession of AddText() methods
+&apos;&apos;&apos; or by a successful invocation of the L10N service with the FolderName argument
+&apos;&apos;&apos; The generated file should pass successfully the &quot;msgfmt --check &apos;the pofile&apos;&quot; GNU command
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: the complete file name to export to. If it exists, is overwritten without warning
+&apos;&apos;&apos; Header: Comments that will appear on top of the generated file. Do not include any leading &quot;#&quot;
+&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
+&apos;&apos;&apos; A standard header will be added anyway
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice probably does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myPO.ExportToPOTFile(&quot;myFile.pot&quot;, Header := &quot;Top comment\nSecond line of top comment&quot;)
+
+Dim bExport As Boolean &apos; Return value
+Dim oFile As Object &apos; Generated file handler
+Dim vLines As Variant &apos; Wrapped lines
+Dim sLine As String &apos; A single line
+Dim vItems As Variant &apos; Array of dictionary items
+Dim vItem As Variant &apos; POEntry type
+Const cstSharp = &quot;# &quot;, cstSharpDot = &quot;#. &quot;, cstFlag = &quot;#, kde-format&quot;
+Const cstTabSize = 4
+Const cstWrap = 70
+Const cstThisSub = &quot;L10N.ExportToPOTFile&quot;
+Const cstSubArgs = &quot;FileName, [Header=&quot;&quot;&quot;&quot;], [Encoding=&quot;&quot;UTF-8&quot;&quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExport = False
+
+Check:
+ If IsMissing(Header) Or IsEmpty(Header) Then Header = &quot;&quot;
+ If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Header, &quot;Header&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oFile = SF_FileSystem.CreateTextFile(FileName, Overwrite := True, Encoding := Encoding)
+ If Not IsNull(oFile) Then
+ With oFile
+ &apos; Standard header
+ .WriteLine(cstSharp)
+ .WriteLine(cstSharp &amp; &quot;This pristine POT file has been generated by LibreOffice/ScriptForge&quot;)
+ .WriteLine(cstSharp &amp; &quot;Full documentation is available on https://help.libreoffice.org/&quot;)
+ &apos; User header
+ If Len(Header) &gt; 0 Then
+ .WriteLine(cstSharp)
+ vLines = SF_String.Wrap(Header, cstWrap, cstTabSize)
+ For Each sLine In vLines
+ .WriteLine(cstSharp &amp; Replace(sLine, SF_String.sfLF, &quot;&quot;))
+ Next sLine
+ End If
+ &apos; Standard header
+ .WriteLine(cstSharp)
+ .WriteLine(&quot;msgid &quot;&quot;&quot;&quot;&quot;)
+ .WriteLine(&quot;msgstr &quot;&quot;&quot;&quot;&quot;)
+ .WriteLine(SF_String.Quote(&quot;Project-Id-Version: PACKAGE VERSION\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Report-Msgid-Bugs-To: &quot; _
+ &amp; &quot;https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&amp;bug_status=UNCONFIRMED&amp;component=UI\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;POT-Creation-Date: &quot; &amp; SF_STring.Represent(Now()) &amp; &quot;\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Last-Translator: FULL NAME &lt;EMAIL@ADDRESS&gt;\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Language-Team: LANGUAGE &lt;EMAIL@ADDRESS&gt;\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Language: en_US\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;MIME-Version: 1.0\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Content-Type: text/plain; charset=&quot; &amp; Encoding &amp; &quot;\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Content-Transfer-Encoding: 8bit\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;Plural-Forms: nplurals=2; plural=n &gt; 1;\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;X-Generator: LibreOffice - ScriptForge\n&quot;))
+ .WriteLine(SF_String.Quote(&quot;X-Accelerator-Marker: ~\n&quot;))
+ &apos; Individual translatable strings
+ vItems = _Dictionary.Items()
+ For Each vItem in vItems
+ .WriteBlankLines(1)
+ &apos; Comments
+ vLines = Split(vItem.Comment, &quot;\n&quot;)
+ For Each sLine In vLines
+ .WriteLine(cstSharpDot &amp; SF_String.ExpandTabs(SF_String.Unescape(sLine), cstTabSize))
+ Next sLine
+ &apos; Flag
+ If InStr(vItem.MsgId, &quot;%&quot;) &gt; 0 Then .WriteLine(cstFlag)
+ &apos; Context
+ If Len(vItem.Context) &gt; 0 Then
+ .WriteLine(&quot;msgctxt &quot; &amp; SF_String.Quote(vItem.Context))
+ End If
+ &apos; MsgId
+ vLines = SF_String.Wrap(vItem.MsgId, cstWrap, cstTabSize)
+ If UBound(vLines) = 0 Then
+ .WriteLine(&quot;msgid &quot; &amp; SF_String.Quote(SF_String.Escape(vLines(0))))
+ Else
+ .WriteLine(&quot;msgid &quot;&quot;&quot;&quot;&quot;)
+ For Each sLine in vLines
+ .WriteLine(SF_String.Quote(SF_String.Escape(sLine)))
+ Next sLine
+ End If
+ &apos; MsgStr
+ .WriteLine(&quot;msgstr &quot;&quot;&quot;&quot;&quot;)
+ Next vItem
+ .CloseFile()
+ End With
+ End If
+ bExport = True
+
+Finally:
+ If Not IsNull(oFile) Then Set oFile = oFile.Dispose()
+ ExportToPOTFile = bExport
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N.ExportToPOTFile
+
+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; ARGUMENTERROR The property does not exist
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myL10N.GetProperty(&quot;MyProperty&quot;)
+
+Const cstThisSub = &quot;L10N.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetText(Optional ByVal MsgId As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As String
+&apos;&apos;&apos; Get the translated string corresponding with the given argument
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MsgId: the identifier of the string or the untranslated string
+&apos;&apos;&apos; Either - the untranslated text (MsgId)
+&apos;&apos;&apos; - the reference to the untranslated text (Context)
+&apos;&apos;&apos; - both (Context|MsgId) : the pipe character is essential
+&apos;&apos;&apos; pvArgs(): a list of arguments present as %1, %2, ... in the (un)translated string)
+&apos;&apos;&apos; to be substituted in the returned string
+&apos;&apos;&apos; Any type is admitted but only strings, numbers or dates are relevant
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The translated string
+&apos;&apos;&apos; If not found the MsgId string or the Context string
+&apos;&apos;&apos; Anyway the substitution is done
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myPO.GetText(&quot;This is a text to be included in a POT file&quot;)
+&apos;&apos;&apos; &apos; Ceci est un text à inclure dans un fichier POT
+
+Dim sText As String &apos; Output buffer
+Dim sContext As String &apos; Context part of argument
+Dim sMsgId As String &apos; MsgId part of argument
+Dim vItem As POEntry &apos; Entry in the dictionary
+Dim vMsgId As Variant &apos; MsgId split on pipe
+Dim sKey As String &apos; Key of dictionary
+Dim sPercent As String &apos; %1, %2, ... placeholders
+Dim i As Long
+Const cstPipe = &quot;|&quot;
+Const cstThisSub = &quot;L10N.GetText&quot;
+Const cstSubArgs = &quot;MsgId, [Arg0, Arg1, ...]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sText = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(MsgId, &quot;MsgId&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(Trim(MsgId)) = 0 Then GoTo Finally
+ sText = MsgId
+
+Try:
+ &apos; Find and load entry from dictionary
+ If Left(MsgId, 1) = cstPipe then MsgId = Mid(MsgId, 2)
+ vMsgId = Split(MsgId, cstPipe)
+ sKey = vMsgId(0)
+ If Not _Dictionary.Exists(sKey) Then &apos; Not found
+ If UBound(vMsgId) = 0 Then sText = vMsgId(0) Else sText = Mid(MsgId, InStr(MsgId, cstPipe) + 1)
+ Else
+ vItem = _Dictionary.Item(sKey)
+ If Len(vItem.MsgStr) &gt; 0 Then sText = vItem.MsgStr Else sText = vItem.MsgId
+ End If
+
+ &apos; Substitute %i placeholders
+ For i = UBound(pvArgs) To 0 Step -1 &apos; Go downwards to not have a limit in number of args
+ sPercent = &quot;%&quot; &amp; (i + 1)
+ sText = Replace(sText, sPercent, SF_String.Represent(pvArgs(i)))
+ Next i
+
+Finally:
+ GetText = sText
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N.GetText
+
+REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Public Function _(Optional ByVal MsgId As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As String
+&apos;&apos;&apos; Get the translated string corresponding with the given argument
+&apos;&apos;&apos; Alias of GetText() - See above
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myPO._(&quot;This is a text to be included in a POT file&quot;)
+&apos;&apos;&apos; &apos; Ceci est un text à inclure dans un fichier POT
+
+Dim sText As String &apos; Output buffer
+Dim sPercent As String &apos; %1, %2, ... placeholders
+Dim i As Long
+Const cstPipe = &quot;|&quot;
+Const cstThisSub = &quot;L10N._&quot;
+Const cstSubArgs = &quot;MsgId, [Arg0, Arg1, ...]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sText = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(MsgId, &quot;MsgId&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(Trim(MsgId)) = 0 Then GoTo Finally
+
+Try:
+ &apos; Find and load entry from dictionary
+ sText = GetText(MsgId)
+
+ &apos; Substitute %i placeholders - done here, not in GetText(), because # of arguments is undefined
+ For i = 0 To UBound(pvArgs)
+ sPercent = &quot;%&quot; &amp; (i + 1)
+ sText = Replace(sText, sPercent, SF_String.Represent(pvArgs(i)))
+ Next i
+
+Finally:
+ _ = sText
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N._
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the L10N service as an array
+
+ Methods = Array( _
+ &quot;AddText&quot; _
+ , &quot;ExportToPOTFile&quot; _
+ , &quot;GetText&quot; _
+ , &quot;AddTextsFromDialog&quot; _
+ , &quot;_&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_L10N.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;Folder&quot; _
+ , &quot;Languages&quot; _
+ , &quot;Locale&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_L10N.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;L10N.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; ScriptForge.SF_L10N.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize(ByVal psPOFile As String _
+ , ByVal Encoding As String _
+ )
+&apos;&apos;&apos; Completes initialization of the current instance requested from CreateScriptService()
+&apos;&apos;&apos; Load the POFile in the dictionary, otherwise leave the dictionary empty
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psPOFile: the file to load the translated strings from
+&apos;&apos;&apos; Encoding: The character set that should be used. Default = UTF-8
+
+Dim oFile As Object &apos; PO file handler
+Dim sContext As String &apos; Collected context string
+Dim sMsgId As String &apos; Collected untranslated string
+Dim sComment As String &apos; Collected comment string
+Dim sMsgStr As String &apos; Collected translated string
+Dim sLine As String &apos; Last line read
+Dim iContinue As Integer &apos; 0 = None, 1 = MsgId, 2 = MsgStr
+Const cstMsgId = 1, cstMsgStr = 2
+
+Try:
+ &apos; Initialize dictionary anyway
+ Set _Dictionary = SF_Services.CreateScriptService(&quot;Dictionary&quot;)
+ Set _Dictionary.[_Parent] = [Me]
+
+ &apos; Load PO file
+ If Len(psPOFile) &gt; 0 Then
+ With SF_FileSystem
+ _POFolder = ._ConvertToUrl(.GetParentFolderName(psPOFile))
+ _Locale = .GetBaseName(psPOFile)
+ _POFile = ._ConvertToUrl(psPOFile)
+ End With
+ &apos; Load PO file
+ Set oFile = SF_FileSystem.OpenTextFile(psPOFile, IOMode := SF_FileSystem.ForReading, Encoding := Encoding)
+ If Not IsNull(oFile) Then
+ With oFile
+ &apos; The PO file is presumed valid =&gt; syntax check is not very strict
+ sContext = &quot;&quot; : sMsgId = &quot;&quot; : sComment = &quot;&quot; : sMsgStr = &quot;&quot;
+ Do While Not .AtEndOfStream
+ sLine = Trim(.ReadLine())
+ &apos; Trivial examination of line header
+ Select Case True
+ Case sLine = &quot;&quot;
+ If Len(sMsgId) &gt; 0 Then AddText(sContext, sMsgId, sComment, sMsgStr)
+ sContext = &quot;&quot; : sMsgId = &quot;&quot; : sComment = &quot;&quot; : sMsgStr = &quot;&quot;
+ iContinue = 0
+ Case Left(sLine, 3) = &quot;#. &quot;
+ sComment = sComment &amp; Iif(Len(sComment) &gt; 0, &quot;\n&quot;, &quot;&quot;) &amp; Trim(Mid(sLine, 4))
+ iContinue = 0
+ Case Left(sLine, 8) = &quot;msgctxt &quot;
+ sContext = SF_String.Unquote(Trim(Mid(sLine, 9)))
+ iContinue = 0
+ Case Left(sLine, 6) = &quot;msgid &quot;
+ sMsgId = SF_String.Unquote(Trim(Mid(sLine, 7)))
+ iContinue = cstMsgId
+ Case Left(sLine, 7) = &quot;msgstr &quot;
+ sMsgStr = sMsgStr &amp; SF_String.Unquote(Trim(Mid(sLine, 8)))
+ iContinue = cstMsgStr
+ Case Left(sLine, 1) = &quot;&quot;&quot;&quot;
+ If iContinue = cstMsgId Then
+ sMsgId = sMsgId &amp; SF_String.Unquote(sLine)
+ ElseIf iContinue = cstMsgStr Then
+ sMsgStr = sMsgStr &amp; SF_String.Unquote(sLine)
+ Else
+ iContinue = 0
+ End If
+ Case Else &apos; Skip line
+ iContinue = 0
+ End Select
+ Loop
+ &apos; Be sure to store the last entry
+ If Len(sMsgId) &gt; 0 Then AddText(sContext, sMsgId, sComment, sMsgStr)
+ .CloseFile()
+ Set oFile = .Dispose()
+ End With
+ End If
+ Else
+ _POFolder = &quot;&quot;
+ _Locale = &quot;&quot;
+ _POFile = &quot;&quot;
+ End If
+
+Finally:
+ Exit Sub
+End Sub &apos; ScriptForge.SF_L10N._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String)
+&apos;&apos;&apos; Return the value of the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+
+Dim vFiles As Variant &apos; Array of PO-files
+Dim i As Long
+Dim cstThisSub As String
+Dim cstSubArgs As String
+
+ cstThisSub = &quot;SF_L10N.get&quot; &amp; psProperty
+ cstSubArgs = &quot;&quot;
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ With SF_FileSystem
+ Select Case psProperty
+ Case &quot;Folder&quot;
+ If Len(_POFolder) &gt; 0 Then _PropertyGet = ._ConvertFromUrl(_POFolder) Else _PropertyGet = &quot;&quot;
+ Case &quot;Languages&quot;
+ If Len(_POFolder) &gt; 0 Then
+ vFiles = .Files(._ConvertFromUrl(_POFolder), &quot;*.po&quot;)
+ For i = 0 To UBound(vFiles)
+ vFiles(i) = SF_FileSystem.GetBaseName(vFiles(i))
+ Next i
+ Else
+ vFiles = Array()
+ End If
+ _PropertyGet = vFiles
+ Case &quot;Locale&quot;
+ _PropertyGet = _Locale
+ Case Else
+ _PropertyGet = Null
+ End Select
+ End With
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_L10N._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _ReplaceText(ByVal psContext As String _
+ , ByVal psMsgId As String _
+ , ByVal psComment As String _
+ ) As Boolean
+&apos;&apos;&apos; When the entry in the dictionary does not yet exist, equivalent to AddText
+&apos;&apos;&apos; When it exists already, extend the existing comment with the psComment argument
+&apos;&apos;&apos; Used from AddTextsFromDialog to manage identical strings without raising errors,
+&apos;&apos;&apos; e.g. when multiple dialogs have the same &quot;Close&quot; button
+
+Dim bAdd As Boolean &apos; Return value
+Dim sKey As String &apos; The key part of an entry in the dictionary
+Dim vItem As POEntry &apos; The item part of the new entry in the dictionary
+
+Try:
+ bAdd = False
+ If Len(psContext) &gt; 0 Then sKey = psContext Else sKey = psMsgId
+ If _Dictionary.Exists(sKey) Then
+ &apos; Load the entry, adapt comment and rewrite
+ vItem = _Dictionary.Item(sKey)
+ If Len(vItem.Comment) = 0 Then vItem.Comment = psComment Else vItem.Comment = vItem.Comment &amp; &quot;\n&quot; &amp; psComment
+ bAdd = _Dictionary.ReplaceItem(sKey, vItem)
+ Else
+ &apos; Add a new entry as usual
+ bAdd = AddText(psContext, psMsgId, psComment)
+ End If
+
+Finally:
+ _ReplaceText = bAdd
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_L10N._ReplaceText
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the L10N instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[L10N]: PO file&quot;
+
+ _Repr = &quot;[L10N]: &quot; &amp; _POFile
+
+End Function &apos; ScriptForge.SF_L10N._Repr
+
+REM ============================================ END OF SCRIPTFORGE.SF_L10N
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Platform.xba b/wizards/source/scriptforge/SF_Platform.xba
new file mode 100644
index 000000000..8403866ff
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Platform.xba
@@ -0,0 +1,451 @@
+<?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_Platform" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Platform
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Platform&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos;
+&apos;&apos;&apos; A collection of properties about the execution environment:
+&apos;&apos;&apos; - HW platform
+&apos;&apos;&apos; - Operating System
+&apos;&apos;&apos; - current user
+&apos;&apos;&apos; - LibreOffice version
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim platform As Variant
+&apos;&apos;&apos; platform = CreateScriptService(&quot;Platform&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_platform.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Array Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Architecture() As String
+&apos;&apos;&apos; Returns the actual bit architecture
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.Architecture &apos; 64bit
+ Architecture = _PropertyGet(&quot;Architecture&quot;)
+End Property &apos; ScriptForge.SF_Platform.Architecture (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ComputerName() As String
+&apos;&apos;&apos; Returns the computer&apos;s network name
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.ComputerName
+ ComputerName = _PropertyGet(&quot;ComputerName&quot;)
+End Property &apos; ScriptForge.SF_Platform.ComputerName (get)
+
+REM -----------------------------------------------------------------------------
+Property Get CPUCount() As Integer
+&apos;&apos;&apos; Returns the number of Central Processor Units
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.CPUCount &apos; 4
+ CPUCount = _PropertyGet(&quot;CPUCount&quot;)
+End Property &apos; ScriptForge.SF_Platform.CPUCount (get)
+
+REM -----------------------------------------------------------------------------
+Property Get CurrentUser() As String
+&apos;&apos;&apos; Returns the name of logged in user
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.CurrentUser
+ CurrentUser = _PropertyGet(&quot;CurrentUser&quot;)
+End Property &apos; ScriptForge.SF_Platform.CurrentUser (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Extensions() As Variant
+&apos;&apos;&apos; Returns the list of availableeExtensions as an unsorted array of unique strings
+&apos;&apos;&apos; To get the list sorted, use SF_Array.Sort()
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myExtensionsList = platform.Extensions
+ Extensions = _PropertyGet(&quot;Extensions&quot;)
+End Property &apos; ScriptForge.SF_Platform.Extensions (get)
+
+REM -----------------------------------------------------------------------------
+Property Get FilterNames() As Variant
+&apos;&apos;&apos; Returns the list of available document import and export filter names as an unsorted array of unique strings
+&apos;&apos;&apos; To get the list sorted, use SF_Array.Sort()
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myFilterNamesList = platform.FilterNames
+ FilterNames = _PropertyGet(&quot;FilterNames&quot;)
+End Property &apos; ScriptForge.SF_Platform.FilterNames (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Fonts() As Variant
+&apos;&apos;&apos; Returns the list of available fonts as an unsorted array of unique strings
+&apos;&apos;&apos; To get the list sorted, use SF_Array.Sort()
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myFontsList = platform.Fonts
+ Fonts = _PropertyGet(&quot;Fonts&quot;)
+End Property &apos; ScriptForge.SF_Platform.Fonts (get)
+
+REM -----------------------------------------------------------------------------
+Property Get FormatLocale() As String
+&apos;&apos;&apos; Returns the locale used for number and date formats, combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.FormatLocale
+ FormatLocale = _PropertyGet(&quot;FormatLocale&quot;)
+End Property &apos; ScriptForge.SF_Platform.FormatLocale (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Locale() As String
+&apos;&apos;&apos; Returns the locale of the operating system, combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.Locale
+ Locale = _PropertyGet(&quot;Locale&quot;)
+End Property &apos; ScriptForge.SF_Platform.Locale (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Machine() As String
+&apos;&apos;&apos; Returns the machine type like &apos;i386&apos; or &apos;x86_64&apos;
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.Machine
+ Machine = _PropertyGet(&quot;Machine&quot;)
+End Property &apos; ScriptForge.SF_Platform.Machine (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_Platform&quot;
+End Property &apos; ScriptForge.SF_Platform.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get OfficeLocale() As String
+&apos;&apos;&apos; Returns the locale of the user interface, combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.OfficeLocale
+ OfficeLocale = _PropertyGet(&quot;OfficeLocale&quot;)
+End Property &apos; ScriptForge.SF_Platform.OfficeLocale (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OfficeVersion() As String
+&apos;&apos;&apos; Returns the office software version in the form &apos;LibreOffice w.x.y.z (The Document Foundation)&apos;
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.OfficeVersion
+ OfficeVersion = _PropertyGet(&quot;OfficeVersion&quot;)
+End Property &apos; ScriptForge.SF_Platform.OfficeVersion (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OSName() As String
+&apos;&apos;&apos; Returns the name of the operating system like &apos;Linux&apos; or &apos;Windows&apos;
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.OSName
+ OSName = _PropertyGet(&quot;OSName&quot;)
+End Property &apos; ScriptForge.SF_Platform.OSName (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OSPlatform() As String
+&apos;&apos;&apos; Returns a single string identifying the underlying platform with as much useful and human-readable information as possible
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.OSPlatform &apos; Linux-4.15.0-117-generic-x86_64-with-Ubuntu-18.04-bionic
+ OSPlatform = _PropertyGet(&quot;OSPlatform&quot;)
+End Property &apos; ScriptForge.SF_Platform.OSPlatform (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OSRelease() As String
+&apos;&apos;&apos; Returns the operating system&apos;s release
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.OSRelease &apos; 4.15.0-117-generic
+ OSRelease = _PropertyGet(&quot;OSRelease&quot;)
+End Property &apos; ScriptForge.SF_Platform.OSRelease (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OSVersion() As String
+&apos;&apos;&apos; Returns the name of the operating system build or version
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.OSVersion &apos; #118-Ubuntu SMP Fri Sep 4 20:02:41 UTC 2020
+ OSVersion = _PropertyGet(&quot;OSVersion&quot;)
+End Property &apos; ScriptForge.SF_Platform.OSVersion (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Printers() As Variant
+&apos;&apos;&apos; Returns the list of available printers type as a zero-based array
+&apos;&apos;&apos; The default printer is put in the 1st position in the list (index = 0)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox join(platform.Printers, &quot;,&quot;)
+ Printers = _PropertyGet(&quot;Printers&quot;)
+End Property &apos; ScriptForge.SF_Platform.Printers (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Processor() As String
+&apos;&apos;&apos; Returns the (real) processor name, e.g. &apos;amdk6&apos;. Might return the same value as Machine
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.Processor
+ Processor = _PropertyGet(&quot;Processor&quot;)
+End Property &apos; ScriptForge.SF_Platform.Processor (get)
+
+REM -----------------------------------------------------------------------------
+Property Get PythonVersion() As String
+&apos;&apos;&apos; Returns the Python version as string &apos;Python major.minor.patchlevel&apos;
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.PythonVersion &apos; Python 3.7.7
+ PythonVersion = _PropertyGet(&quot;PythonVersion&quot;)
+End Property &apos; ScriptForge.SF_Platform.PythonVersion (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.Platform&quot;
+End Property &apos; ScriptForge.SF_Platform.ServiceName
+
+REM -----------------------------------------------------------------------------
+Property Get SystemLocale() As String
+&apos;&apos;&apos; Returns the locale of the operating system, combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox platform.SystemLocale
+ SystemLocale = _PropertyGet(&quot;SystemLocale&quot;)
+End Property &apos; ScriptForge.SF_Platform.SystemLocale (get)
+
+REM ===================================================================== METHODS
+
+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; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;Platform.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Platform.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( _
+ )
+
+End Function &apos; ScriptForge.SF_Platform.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Platform class as an array
+
+ Properties = Array( _
+ &quot;Architecture&quot; _
+ , &quot;ComputerName&quot; _
+ , &quot;CPUCount&quot; _
+ , &quot;CurrentUser&quot; _
+ , &quot;Extensions&quot; _
+ , &quot;FilterNames&quot; _
+ , &quot;Fonts&quot; _
+ , &quot;FormatLocale&quot; _
+ , &quot;Locale&quot; _
+ , &quot;Machine&quot; _
+ , &quot;OfficeLocale&quot; _
+ , &quot;OfficeVersion&quot; _
+ , &quot;OSName&quot; _
+ , &quot;OSPlatform&quot; _
+ , &quot;OSRelease&quot; _
+ , &quot;OSVersion&quot; _
+ , &quot;Printers&quot; _
+ , &quot;Processor&quot; _
+ , &quot;PythonVersion&quot; _
+ , &quot;SystemLocale&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Platform.Properties
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _GetPrinters() as Variant
+&apos;&apos;&apos; Returns the list of available printers.
+&apos;&apos;&apos; The default printer is put in the 1st position (index = 0)
+
+Dim oPrinterServer As Object &apos; com.sun.star.awt.PrinterServer
+Dim vPrinters As Variant &apos; Array of printer names
+Dim sDefaultPrinter As String &apos; The default printer
+Dim lDefault As Long &apos; Initial position of the default printer in the list
+
+ On Local Error GoTo Catch &apos; Prevent any error
+ vPrinters = Array()
+
+Try:
+ &apos; Find printers
+ Set oPrinterServer = SF_Utils._GetUNOService(&quot;PrinterServer&quot;)
+ With oPrinterServer
+ vPrinters = .getPrinterNames()
+ sDefaultPrinter = .getDefaultPrinterName()
+ End With
+
+ &apos; Put the default printer on top of the list
+ If Len(sDefaultPrinter) &gt; 0 Then
+ lDefault = SF_Array.IndexOf(vPrinters, sDefaultPrinter, CaseSensitive := True)
+ If lDefault &gt; 0 Then &apos; Invert 2 printers
+ vPrinters(lDefault) = vPrinters(0)
+ vPrinters(0) = sDefaultPrinter
+ End If
+ End If
+
+Finally:
+ _GetPrinters() = vPrinters()
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Platform._GetPrinters
+
+REM -----------------------------------------------------------------------------
+Public Function _GetProductName() as String
+&apos;&apos;&apos; Returns Office product and version numbers found in configuration registry
+&apos;&apos;&apos; Derived from the Tools library
+
+Dim oProdNameAccess as Object &apos; configmgr.RootAccess
+Dim sProdName as String
+Dim sVersion as String
+Dim sVendor As String
+
+ On Local Error GoTo Catch &apos; Prevent any error
+ _GetProductName = &quot;&quot;
+
+Try:
+ Set oProdNameAccess = SF_Utils._GetRegistryKeyContent(&quot;org.openoffice.Setup/Product&quot;)
+
+ sProdName = oProdNameAccess.ooName
+ sVersion = oProdNameAccess.ooSetupVersionAboutBox
+ sVendor = oProdNameAccess.ooVendor
+
+ _GetProductName = sProdName &amp; &quot; &quot; &amp; sVersion &amp; &quot; (&quot; &amp; sVendor &amp; &quot;)&quot;
+
+Finally:
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Platform._GetProductName
+
+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 sOSName As String &apos; Operating system
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oPrinterServer As Object &apos; com.sun.star.awt.PrinterServer
+Dim oToolkit As Object &apos; com.sun.star.awt.Toolkit
+Dim oDevice As Object &apos; com.sun.star.awt.XDevice
+Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
+Dim oFontDescriptors As Variant &apos; Array of com.sun.star.awt.FontDescriptor
+Dim sFonts As String &apos; Comma-separated list of fonts
+Dim sFont As String &apos; A single font name
+Dim vExtensionsList As Variant &apos; Array of extension descriptors
+Dim sExtensions As String &apos; Comma separated list of extensions
+Dim sExtension As String &apos; A single extension name
+Dim i As Long
+
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Platform&quot;
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;Platform.get&quot; &amp; psProperty
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case psProperty
+ Case &quot;Architecture&quot;, &quot;ComputerName&quot;, &quot;CPUCount&quot;, &quot;CurrentUser&quot;, &quot;Machine&quot; _
+ , &quot;OSPlatform&quot;, &quot;OSRelease&quot;, &quot;OSVersion&quot;, &quot;Processor&quot;, &quot;PythonVersion&quot;
+ With ScriptForge.SF_Session
+ _PropertyGet = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, psProperty)
+ End With
+ Case &quot;Extensions&quot;
+ Set vExtensionsList = SF_Utils._GetUnoService(&quot;PackageInformationProvider&quot;).ExtensionList
+ sExtensions = &quot;&quot;
+ For i = 0 To UBound(vExtensionsList)
+ sExtensions = sExtensions &amp; &quot;,&quot; &amp; vExtensionsList(i)(0)
+ Next i
+ If Len(sExtensions) &gt; 0 Then _PropertyGet = Split(Mid(sExtensions, 2), &quot;,&quot;) Else _PropertyGet = Array()
+ Case &quot;FilterNames&quot;
+ Set oFilterFactory = SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
+ _PropertyGet = oFilterFactory.getElementNames()
+ Case &quot;Fonts&quot;
+ Set oToolkit = SF_Utils._GetUnoService(&quot;Toolkit&quot;)
+ Set oDevice = oToolkit.createScreenCompatibleDevice(0, 0)
+ oFontDescriptors = oDevice.FontDescriptors()
+ sFonts = &quot;,&quot;
+ &apos; Select only not yet registered fonts
+ For i = 0 To UBound(oFontDescriptors)
+ sFont = oFontDescriptors(i).Name
+ If InStr(1, sFonts, &quot;,&quot; &amp; sFont &amp; &quot;,&quot;, 0) = 0 Then sFonts = sFonts &amp; sFont &amp; &quot;,&quot; &apos; Case-sensitive comparison
+ Next i
+ &apos; Remove leading and trailing commas
+ If Len(sFonts) &gt; 1 Then _PropertyGet = Split(Mid(sFonts, 2, Len(sFonts) - 2), &quot;,&quot;) Else _PropertyGet = Array()
+ Case &quot;FormatLocale&quot;
+ Set oLocale = SF_Utils._GetUNOService(&quot;FormatLocale&quot;)
+ _PropertyGet = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
+ Case &quot;OfficeLocale&quot;
+ Set oLocale = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
+ _PropertyGet = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
+ Case &quot;OfficeVersion&quot;
+ _PropertyGet = _GetProductName()
+ Case &quot;OSName&quot;
+ &apos; Calc INFO function preferred to Python script to avoid ScriptForge initialization risks when Python is not installed
+ sOSName = _SF_.OSName
+ If sOSName = &quot;&quot; Then
+ sOSName = SF_Session.ExecuteCalcFunction(&quot;INFO&quot;, &quot;system&quot;)
+ Select Case sOSName
+ Case &quot;WNT&quot; : sOSName = &quot;Windows&quot;
+ Case &quot;MACOSX&quot; : sOSName = &quot;macOS&quot;
+ Case &quot;LINUX&quot; : sOSName = &quot;Linux&quot;
+ Case &quot;SOLARIS&quot; : sOSName = &quot;Solaris&quot;
+ Case Else : sOSName = SF_String.Capitalize(sOSName)
+ End Select
+ EndIf
+ _PropertyGet = sOSName
+ Case &quot;Printers&quot;
+ _PropertyGet = _GetPrinters()
+ Case &quot;SystemLocale&quot;, &quot;Locale&quot;
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+ _PropertyGet = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Platform._PropertyGet
+
+REM ============================================ END OF SCRIPTFORGE.SF_PLATFORM
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba b/wizards/source/scriptforge/SF_PythonHelper.xba
new file mode 100644
index 000000000..99d9f86c6
--- /dev/null
+++ b/wizards/source/scriptforge/SF_PythonHelper.xba
@@ -0,0 +1,967 @@
+<?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_PythonHelper" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_PythonHelper (aka Basic)
+&apos;&apos;&apos; ===============
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Basic&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos;
+&apos;&apos;&apos; The &quot;Basic&quot; service must be called ONLY from a PYTHON script
+&apos;&apos;&apos; Service invocations: Next Python code lines are equivalent:
+&apos;&apos;&apos; bas = CreateScriptService(&apos;ScriptForge.Basic&apos;)
+&apos;&apos;&apos; bas = CreateScriptService(&apos;Basic&apos;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; This service proposes a collection of methods to be executed in a Python context
+&apos;&apos;&apos; to simulate the exact behaviour of the identical Basic builtin method.
+&apos;&apos;&apos; Typical example:
+&apos;&apos;&apos; bas.MsgBox(&apos;This has to be displayed in a message box&apos;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; The service includes also an agnostic &quot;Python Dispatcher&quot; function.
+&apos;&apos;&apos; It dispatches Python script requests to execute Basic services to the
+&apos;&apos;&apos; appropriate properties and methods via dynamic call techniques
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_PythonHelper Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_PythonHelper&quot;
+End Property &apos; ScriptForge.SF_PythonHelper.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.Basic&quot;
+End Property &apos; ScriptForge.SF_PythonHelper.ServiceName
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function PyCDate(ByVal DateArg As Variant) As Variant
+&apos;&apos;&apos; Convenient function to replicate CDate() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DateArg: a date as a string or as a double
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The converted date as a UNO DateTime structure
+&apos;&apos;&apos; If the input argument could not be recognized as a date, return the argument unchanged
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.CDate(&apos;2021-02-18&apos;)
+
+Dim vDate As Variant &apos; Return value
+Const cstThisSub = &quot;Basic.CDate&quot;
+Const cstSubArgs = &quot;datearg&quot;
+
+ On Local Error GoTo Catch
+ vDate = Null
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ vDate = CDate(DateArg)
+
+Finally:
+ If VarType(vDate) = V_DATE Then PyCDate = CDateToUnoDateTime(vDate) Else PyCDate = DateArg
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ On Local Error GoTo 0
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyCDate
+
+REM -----------------------------------------------------------------------------
+Public Function PyConvertFromUrl(ByVal FileName As Variant) As String
+&apos;&apos;&apos; Convenient function to replicate ConvertFromUrl() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file in URL format
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The same file name in native operating system notation
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.ConvertFromUrl(&apos;file:////boot.sys&apos;)
+
+Dim sFileName As String &apos; Return value
+Const cstThisSub = &quot;Basic.ConvertFromUrl&quot;
+Const cstSubArgs = &quot;filename&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFileName = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ sFileName = ConvertFromUrl(FileName)
+
+Finally:
+ PyConvertFromUrl = sFileName
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyConvertFromUrl
+
+REM -----------------------------------------------------------------------------
+Public Function PyConvertToUrl(ByVal FileName As Variant) As String
+&apos;&apos;&apos; Convenient function to replicate ConvertToUrl() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file in native operating system notation
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The same file name in URL format
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.ConvertToUrl(&apos;C:\boot.sys&apos;)
+
+Dim sFileName As String &apos; Return value
+Const cstThisSub = &quot;Basic.ConvertToUrl&quot;
+Const cstSubArgs = &quot;filename&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFileName = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ sFileName = ConvertToUrl(FileName)
+
+Finally:
+ PyConvertToUrl = sFileName
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyConvertToUrl
+
+REM -----------------------------------------------------------------------------
+Public Function PyCreateUnoService(ByVal UnoService As Variant) As Variant
+&apos;&apos;&apos; Convenient function to replicate CreateUnoService() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; UnoService: a string representing the service to create
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A UNO object
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.CreateUnoService(&apos;com.sun.star.i18n.CharacterClassification&apos;)
+
+Dim vUno As Variant &apos; Return value
+Const cstThisSub = &quot;Basic.CreateUnoService&quot;
+Const cstSubArgs = &quot;unoservice&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set vUno = Nothing
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ Set vUno = CreateUnoService(UnoService)
+
+Finally:
+ Set PyCreateUnoService = vUno
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyCreateUnoService
+
+REM -----------------------------------------------------------------------------
+Public Function PyDateAdd(ByVal Add As Variant _
+ , ByVal Count As Variant _
+ , ByVal DateArg As Variant _
+ ) As Variant
+&apos;&apos;&apos; Convenient function to replicate DateAdd() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Add: The unit to add
+&apos;&apos;&apos; Count: how many times to add (might be negative)
+&apos;&apos;&apos; DateArg: a date as a com.sun.star.util.DateTime UNO structure
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new date as a string in iso format
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.DateAdd(&apos;d&apos;, 1, bas.Now()) &apos; Tomorrow
+
+Dim vNewDate As Variant &apos; Return value
+Dim vDate As Date &apos; Alias of DateArg
+Const cstThisSub = &quot;Basic.DateAdd&quot;
+Const cstSubArgs = &quot;add, count, datearg&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vNewDate = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If VarType(DateArg) = V_OBJECT Then
+ vDate = CDateFromUnoDateTime(DateArg)
+ Else
+ vDate = SF_Utils._CStrToDate(DateArg)
+ End If
+ vNewDate = DateAdd(Add, Count, vDate)
+
+Finally:
+ If VarType(vNewDate) = V_DATE Then PyDateAdd = CDateToUnoDateTime(vNewDate) Else PyDateAdd = vNewDate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyDateAdd
+
+REM -----------------------------------------------------------------------------
+Public Function PyDateDiff(ByVal Add As Variant _
+ , ByVal Date1 As Variant _
+ , ByVal Date2 As Variant _
+ , ByVal WeekStart As Variant _
+ , ByVal YearStart As Variant _
+ ) As Long
+&apos;&apos;&apos; Convenient function to replicate DateDiff() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Add: The unit of the date interval
+&apos;&apos;&apos; Date1, Date2: the two dates to be compared
+&apos;&apos;&apos; WeekStart: the starting day of a week
+&apos;&apos;&apos; YearStart: the starting week of a year
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The number of intervals expressed in Adds
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.DateDiff(&apos;d&apos;, bas.DateAdd(&apos;d&apos;, 1, bas.Now()), bas.Now()) &apos; -1 day
+
+Dim lDiff As Long &apos; Return value
+Dim vDate1 As Date &apos; Alias of Date1
+Dim vDate2 As Date &apos; Alias of Date2
+Const cstThisSub = &quot;Basic.DateDiff&quot;
+Const cstSubArgs = &quot;add, date1, date2, [weekstart=1], [yearstart=1]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ lDiff = 0
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If VarType(Date1) = V_OBJECT Then
+ vDate1 = CDateFromUnoDateTime(Date1)
+ Else
+ vDate1 = SF_Utils._CStrToDate(Date1)
+ End If
+ If VarType(Date2) = V_OBJECT Then
+ vDate2 = CDateFromUnoDateTime(Date2)
+ Else
+ vDate2 = SF_Utils._CStrToDate(Date2)
+ End If
+ lDiff = DateDiff(Add, vDate1, vDate2, WeekStart, YearStart)
+
+
+Finally:
+ PyDateDiff = lDiff
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyDateDiff
+
+REM -----------------------------------------------------------------------------
+Public Function PyDatePart(ByVal Add As Variant _
+ , ByVal DateArg As Variant _
+ , ByVal WeekStart As Variant _
+ , ByVal YearStart As Variant _
+ ) As Long
+&apos;&apos;&apos; Convenient function to replicate DatePart() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Add: The unit of the date interval
+&apos;&apos;&apos; DateArg: The date from which to extract a part
+&apos;&apos;&apos; WeekStart: the starting day of a week
+&apos;&apos;&apos; YearStart: the starting week of a year
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The specified part of the date
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.DatePart(&apos;y&apos;, bas.Now()) &apos; day of year
+
+Dim lPart As Long &apos; Return value
+Dim vDate As Date &apos; Alias of DateArg
+Const cstThisSub = &quot;Basic.DatePart&quot;
+Const cstSubArgs = &quot;add, datearg, [weekstart=1], [yearstart=1]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ lPart = 0
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If VarType(DateArg) = V_OBJECT Then
+ vDate = CDateFromUnoDateTime(DateArg)
+ Else
+ vDate = SF_Utils._CStrToDate(DateArg)
+ End If
+ lPart = DatePart(Add, vDate, WeekStart, YearStart)
+
+
+Finally:
+ PyDatePart = lPart
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyDatePart
+
+REM -----------------------------------------------------------------------------
+Public Function PyDateValue(ByVal DateArg As Variant) As Variant
+&apos;&apos;&apos; Convenient function to replicate DateValue() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DateArg: a date as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The converted date as a UNO DateTime structure
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.DateValue(&apos;2021-02-18&apos;)
+
+Dim vDate As Variant &apos; Return value
+Const cstThisSub = &quot;Basic.DateValue&quot;
+Const cstSubArgs = &quot;datearg&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vDate = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ vDate = DateValue(DateArg)
+
+Finally:
+ If VarType(vDate) = V_DATE Then PyDateValue = CDateToUnoDateTime(vDate) Else PyDateValue = vDate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyDateValue
+
+REM -----------------------------------------------------------------------------
+Public Function PyFormat(ByVal Value As Variant _
+ , ByVal Pattern As Variant _
+ ) As String
+&apos;&apos;&apos; Convenient function to replicate Format() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Value: a date or a number
+&apos;&apos;&apos; Pattern: the format to apply
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The formatted value
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; MsgBox bas.Format(6328.2, &apos;##,##0.00&apos;)
+
+Dim sFormat As String &apos; Return value
+Dim vValue As Variant &apos; Alias of Value
+Const cstThisSub = &quot;Basic.Format&quot;
+Const cstSubArgs = &quot;value, pattern&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFormat = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If VarType(Value) = V_OBJECT Then vValue = CDateFromUnoDateTime(Value) ELse vValue = Value
+ If IsEmpty(Pattern) Or Len(Pattern) = 0 Then sFormat = Str(vValue) Else sFormat = Format(vValue, Pattern)
+
+
+Finally:
+ PyFormat = sFormat
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyFormat
+
+REM -----------------------------------------------------------------------------
+Public Function PyGetGuiType() As Integer
+&apos;&apos;&apos; Convenient function to replicate GetGuiType() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The GetGuiType value
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; MsgBox bas.GetGuiType()
+
+Const cstThisSub = &quot;Basic.GetGuiType&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ PyGetGuiType = GetGuiType()
+
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_PythonHelper.PyGetGuiType
+
+REM -----------------------------------------------------------------------------
+Public Function PyGetSystemTicks() As Long
+&apos;&apos;&apos; Convenient function to replicate GetSystemTicks() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The GetSystemTicks value
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; MsgBox bas.GetSystemTicks()
+
+Const cstThisSub = &quot;Basic.GetSystemTicks&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ PyGetSystemTicks = GetSystemTicks()
+
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_PythonHelper.PyGetSystemTicks
+
+REM -----------------------------------------------------------------------------
+Public Function PyGlobalScope(ByVal Library As Variant) As Object
+&apos;&apos;&apos; Convenient function to replicate GlobalScope() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Library: &quot;Basic&quot; or &quot;Dialog&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The GlobalScope value
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; MsgBox bas.GlobalScope.BasicLibraries()
+
+Const cstThisSub = &quot;Basic.GlobalScope.BasicLibraries&quot; &apos; or DialogLibraries
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ Select Case Library
+ Case &quot;Basic&quot;
+ PyGlobalScope = GlobalScope.BasicLibraries()
+ Case &quot;Dialog&quot;
+ PyGlobalScope = GlobalScope.DialogLibraries()
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_PythonHelper.PyGlobalScope
+
+REM -----------------------------------------------------------------------------
+Public Function PyInputBox(ByVal Msg As Variant _
+ , ByVal Title As Variant _
+ , ByVal Default As Variant _
+ , Optional ByVal XPosTwips As Variant _
+ , Optional ByVal YPosTwips As Variant _
+ ) As String
+&apos;&apos;&apos; Convenient function to replicate InputBox() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Msg: String expression displayed as the message in the dialog box
+&apos;&apos;&apos; Title: String expression displayed in the title bar of the dialog box
+&apos;&apos;&apos; Default: String expression displayed in the text box as default if no other input is given
+&apos;&apos;&apos; XPosTwips: Integer expression that specifies the horizontal position of the dialog
+&apos;&apos;&apos; YPosTwips: Integer expression that specifies the vertical position of the dialog
+&apos;&apos;&apos; If XPosTwips and YPosTwips are omitted, the dialog is centered on the screen
+&apos;&apos;&apos; The position is specified in twips.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The entered value or &quot;&quot; if the user pressed the Cancel button
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.InputBox (&apos;Please enter a phrase:&apos;, &apos;Dear User&apos;)
+
+Dim sInput As String &apos; Return value
+Const cstThisSub = &quot;Basic.InputBox&quot;
+Const cstSubArgs = &quot;msg, [title=&apos;&apos;], [default=&apos;&apos;], [xpostwips], [ypostwips]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sInput = &quot;&quot;
+
+Check:
+ If IsMissing(YPosTwips) Then YPosTwips = 1
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If IsMissing(XPosTwips) Then
+ sInput = InputBox(Msg, Title, Default)
+ Else
+ sInput = InputBox(Msg, Title, Default, XPosTwips, YPosTwips)
+ End If
+
+Finally:
+ PyInputBox = sInput
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyInputBox
+
+REM -----------------------------------------------------------------------------
+Public Function PyMsgBox(ByVal Text As Variant _
+ , ByVal DialogType As Variant _
+ , ByVal DialogTitle As Variant _
+ ) As Integer
+&apos;&apos;&apos; Convenient function to replicate MsgBox() in Python scripts
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Text: String expression displayed as a message in the dialog box
+&apos;&apos;&apos; DialogType: Any integer expression that defines the number and type of buttons or icons displayed
+&apos;&apos;&apos; DialogTitle: String expression displayed in the title bar of the dialog
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The pressed button
+&apos;&apos;&apos; Example: (Python code)
+&apos;&apos;&apos; a = bas.MsgBox (&apos;Please press a button:&apos;, bas.MB_EXCLAMATION, &apos;Dear User&apos;)
+
+Dim iMsg As Integer &apos; Return value
+Const cstThisSub = &quot;Basic.MsgBox&quot;
+Const cstSubArgs = &quot;text, [dialogtype=0], [dialogtitle]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iMsg = -1
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ iMsg = MsgBox(Text, DialogType, DialogTitle)
+
+Finally:
+ PyMsgBox = iMsg
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper.PyMsgBox
+
+REM ============================================================= PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function _PythonDispatcher(ByRef BasicObject As Variant _
+ , ByVal CallType As Variant _
+ , ByVal Script As Variant _
+ , ParamArray Args() As Variant _
+ ) As Variant
+&apos;&apos;&apos; Called from Python only
+&apos;&apos;&apos; The method calls the method Script associated with the BasicObject class or module
+&apos;&apos;&apos; with the given arguments
+&apos;&apos;&apos; The invocation of the method can be a Property Get, Property Let or a usual call
+&apos;&apos;&apos; NB: arguments and return values must not be 2D arrays
+&apos;&apos;&apos; The implementation intends to be as AGNOSTIC as possible in terms of objects nature and methods called
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; BasicObject: a module or a class instance - May also be the reserved string: &quot;SF_Services&quot;
+&apos;&apos;&apos; CallType: one of the constants applicable to a CallByName statement + optional protocol flags
+&apos;&apos;&apos; Script: the name of the method or property
+&apos;&apos;&apos; Args: the arguments to pass to the method. Input arguments can contain symbolic constants for Null, Missing, etc.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A 1D array:
+&apos;&apos;&apos; [0] The returned value - scalar, object or 1D array
+&apos;&apos;&apos; [1] The VarType() of the returned value
+&apos;&apos;&apos; Null, Empty and Nothing have different vartypes but return all None to Python
+&apos;&apos;&apos; Additionally, when array:
+&apos;&apos;&apos; [2] Number of dimensions in Basic
+&apos;&apos;&apos; Additionally, when Basic object:
+&apos;&apos;&apos; [2] Module (1), Class instance (2) or UNO (3)
+&apos;&apos;&apos; [3] The object&apos;s ObjectType
+&apos;&apos;&apos; [4] The object&apos;s service name
+&apos;&apos;&apos; [5] The object&apos;s name
+&apos;&apos;&apos; When an error occurs Python receives None as a scalar. This determines the occurrence of a failure
+
+Dim vReturn As Variant &apos; The value returned by the invoked property or method
+Dim vReturnArray As Variant &apos; Return value
+Dim vBasicObject As Variant &apos; Alias of BasicObject to avoid &quot;Object reference not set&quot; error
+Dim iNbArgs As Integer &apos; Number of valid input arguments
+Dim vArg As Variant &apos; Alias for a single argument
+Dim vArgs() As Variant &apos; Alias for Args()
+Dim sScript As String &apos; Argument of ExecuteBasicScript()
+Dim vParams As Variant &apos; Array of arguments to pass to a ParamArray
+Dim sObjectType As String &apos; Alias of object.ObjectType
+Dim sServiceName As String &apos; Alias of BasicObject.ServiceName
+Dim bBasicClass As Boolean &apos; True when BasicObject is a class
+Dim sLibrary As String &apos; Library where the object belongs to
+Dim bUno As Boolean &apos; Return value is a UNO object
+Dim oObjDesc As Object &apos; _ObjectDescriptor type
+Dim iDims As Integer &apos; # of dims of vReturn
+Dim sess As Object : Set sess = ScriptForge.SF_Session
+Dim i As Long, j As Long
+
+&apos; Conventional special input or output values
+Const cstNoArgs = &quot;+++NOARGS+++&quot;, cstSymEmpty = &quot;+++EMPTY+++&quot;, cstSymNull = &quot;+++NULL+++&quot;, cstSymMissing = &quot;+++MISSING+++&quot;
+
+&apos; https://support.office.com/en-us/article/CallByName-fonction-49ce9475-c315-4f13-8d35-e98cfe98729a
+&apos; Determines the CallType
+Const vbGet = 2, vbLet = 4, vbMethod = 1, vbSet = 8
+&apos; Protocol flags
+Const cstDateArg = 64 &apos; May contain a date argument
+Const cstDateRet = 128 &apos; Return value can be a date
+Const cstUno = 256 &apos; Return value can be a UNO object
+Const cstArgArray = 512 &apos; Any argument can be a 2D array
+Const cstRetArray = 1024 &apos; Return value can be an array
+Const cstObject = 2048 &apos; 1st argument is a Basic object when numeric
+Const cstHardCode = 4096 &apos; Method must not be executed with CallByName()
+&apos; Object nature in returned array
+Const objMODULE = 1, objCLASS = 2, objUNO = 3
+
+Check:
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ _PythonDispatcher = Null
+
+ &apos; Ignore Null basic objects (Null = Null or Nothing)
+ If IsNull(BasicObject) Or IsEmpty(BasicObject) Then GoTo Catch
+
+ &apos; Reinterpret arguments one by one into vArgs, convert UNO date/times and conventional NoArgs/Empty/Null/Missing values
+ iNbArgs = -1
+ vArgs = Array()
+
+ If UBound(Args) &gt;= 0 Then
+ For i = 0 To UBound(Args)
+ vArg = Args(i)
+ &apos; Are there arguments ?
+ If i = 0 And VarType(vArg) = V_STRING Then
+ If vArg = cstNoArgs Then Exit For
+ End If
+ &apos; Is 1st argument a reference to a Basic object ?
+ If i = 0 And (( CallType And cstObject ) = cstObject) And SF_Utils._VarTypeExt(vArg) = V_NUMERIC Then
+ If vArg &lt; 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
+ If vArg &gt; UBound(_SF_.PythonStorage) Then GoTo Catch
+ vArg = _SF_.PythonStorage(vArg)
+ &apos; Is argument a symbolic constant for Null, Empty, ... , or a date?
+ ElseIf VarType(vArg) = V_STRING Then
+ If Len(vArg) = 0 Then
+ ElseIf vArg = cstSymEmpty Then
+ vArg = Empty
+ ElseIf vArg = cstSymNull Then
+ vArg = Null
+ ElseIf vArg = cstSymMissing Then
+ Exit For &apos; Next arguments must be missing also
+ End If
+ ElseIf VarType(vArg) = V_OBJECT Then
+ If ( CallType And cstDateArg ) = cstDateArg Then vArg = CDateFromUnoDateTime(vArg)
+ End If
+ iNbArgs = iNbArgs + 1
+
+ ReDim Preserve vArgs(iNbArgs)
+ vArgs(iNbArgs) = vArg
+ Next i
+ End If
+
+Try:
+ &apos; Dispatching strategy: based on next constraints
+ &apos; (1) Bug https://bugs.documentfoundation.org/show_bug.cgi?id=138155
+ &apos; The CallByName function fails when returning an array
+ &apos; (2) Python has tuples and tuple of tuples, not 2D arrays
+ &apos; (3) Passing 2D arrays through a script provider always transform it into a sequence of sequences
+ &apos; (4) The CallByName function takes exclusive control on the targeted object up to its exit
+ &apos; 1. Methods in usual modules are called by ExecuteBasicScript() except if they use a ParamArray
+ &apos; 2. Properties in any service are got and set with obj.GetProperty/SetProperty(...)
+ &apos; 3. Methods in class modules are invoked with CallByName
+ &apos; 4. Methods in class modules using a 2D array or returning arrays, or methods using ParamArray,
+&apos;&apos;&apos; are hardcoded as exceptions or are not implemented
+ &apos; 5. Due to constraint (4), a predefined list of method calls must be hardcoded to avoid blocking use of CallByName
+ &apos; The concerned methods are flagged with cstHardCode
+
+ With _SF_
+ &apos; Initialize Python persistent storage at 1st call
+ If IsEmpty(.PythonStorage) Then ._InitPythonStorage()
+ &apos; Reset any error
+ ._Stackreset()
+ &apos; Set Python trigger to manage signatures in error messages
+ .TriggeredByPython = True
+ End With
+
+ Select case VarType(BasicObject)
+ Case V_STRING
+ &apos; Special entry for CreateScriptService()
+ vBasicObject = BasicObject
+ If vBasicObject = &quot;SF_Services&quot; Then
+ If UBound(vArgs) = 0 Then vParams = Array() Else vParams = SF_Array.Slice(vArgs, 1)
+ Select Case UBound(vParams)
+ Case -1 : vReturn = SF_Services.CreateScriptService(vArgs(0))
+ Case 0 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0))
+ Case 1 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1))
+ Case 2 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2))
+ Case 3 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2), vParams(3))
+ Case 4 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2), vParams(3), vParams(4))
+ End Select
+ End If
+ If VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
+ vBasicObject = vReturn
+ sObjectType = vBasicObject.ObjectType
+ bBasicClass = ( Left(sObjectType, 3) &lt;&gt; &quot;SF_&quot; )
+ End If
+
+ &apos; Implement dispatching strategy
+ Case V_INTEGER
+ If BasicObject &lt; 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
+ If BasicObject &gt; UBound(_SF_.PythonStorage) Then GoTo Catch
+ vBasicObject = _SF_.PythonStorage(BasicObject)
+ sObjectType = vBasicObject.ObjectType
+ sServiceName = vBasicObject.ServiceName
+
+ &apos; Basic modules have type = &quot;SF_*&quot;
+ bBasicClass = ( Left(sObjectType, 3) &lt;&gt; &quot;SF_&quot; )
+ sLibrary = Split(sServiceName, &quot;.&quot;)(0)
+
+ &apos; Methods in standard modules returning/passing a date are hardcoded as exceptions
+ If Not bBasicClass And ((CallType And vbMethod) = vbMethod) _
+ And (((CallType And cstDateRet) = cstDateRet) Or ((CallType And cstDateArg) = cstDateArg)) Then
+ Select Case sServiceName
+ Case &quot;ScriptForge.FileSystem&quot;
+ If Script = &quot;GetFileModified&quot; Then vReturn = SF_FileSystem.GetFileModified(vArgs(0))
+ Case &quot;ScriptForge.Region&quot;
+ Select Case Script
+ Case &quot;DSTOffset&quot; : vReturn = SF_Region.DSTOffset(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;LocalDateTime&quot; : vReturn = SF_Region.LocalDateTime(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;UTCDateTime&quot; : vReturn = SF_Region.UTCDateTime(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;UTCNow&quot; : vReturn = SF_Region.UTCNow(vArgs(0), vArgs(1))
+ Case Else
+ End Select
+ End Select
+
+ &apos; Methods in usual modules using a 2D array or returning arrays are hardcoded as exceptions
+ ElseIf Not bBasicClass And _
+ (((CallType And vbMethod) + (CallType And cstArgArray)) = vbMethod + cstArgArray Or _
+ ((CallType And vbMethod) + (CallType And cstRetArray)) = vbMethod + cstRetArray) Then
+ &apos; Not service related
+ If Script = &quot;Methods&quot; Then
+ vReturn = vBasicObject.Methods()
+ ElseIf Script = &quot;Properties&quot; Then
+ vReturn = vBasicObject.Properties()
+ Else
+ Select Case sServiceName
+ Case &quot;ScriptForge.Array&quot;
+ If Script = &quot;ImportFromCSVFile&quot; Then vReturn = SF_Array.ImportFromCSVFile(vArgs(0), vArgs(1), vArgs(2), True)
+ End Select
+ End If
+
+ &apos; Methods in usual modules are called by ExecuteBasicScript() except if they use a ParamArray
+ ElseIf Not bBasicClass And (CallType And vbMethod) = vbMethod Then
+ sScript = sLibrary &amp; &quot;.&quot; &amp; sObjectType &amp; &quot;.&quot; &amp; Script
+ &apos; Force validation in targeted function, not in ExecuteBasicScript()
+ _SF_.StackLevel = -1
+ Select Case UBound(vArgs)
+ Case -1 : vReturn = sess.ExecuteBasicScript(, sScript)
+ Case 0 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0))
+ Case 1 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1))
+ Case 2 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2))
+ Case 3 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case 4 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
+ Case 5 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
+ Case 6 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
+ Case 7 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
+ End Select
+ _SF_.StackLevel = 0
+
+ &apos; Properties in any service are got and set with obj.GetProperty/SetProperty(...)
+ ElseIf (CallType And vbGet) = vbGet Then &apos; In some cases (Calc ...) GetProperty may have an argument
+ If UBound(vArgs) &lt; 0 Then vReturn = vBasicObject.GetProperty(Script) Else vReturn = vBasicObject.GetProperty(Script, vArgs(0))
+ ElseIf (CallType And vbLet) = vbLet Then
+ vReturn = vBasicObject.SetProperty(Script, vArgs(0))
+
+ &apos; Methods in class modules using a 2D array or returning arrays are hardcoded as exceptions. Bug #138155
+ ElseIf ((CallType And vbMethod) + (CallType And cstArgArray)) = vbMethod + cstArgArray Or _
+ ((CallType And vbMethod) + (CallType And cstRetArray)) = vbMethod + cstRetArray Then
+ If Script = &quot;Methods&quot; Then
+ vReturn = vBasicObject.Methods()
+ ElseIf Script = &quot;Properties&quot; Then
+ vReturn = vBasicObject.Properties()
+ Else
+ Select Case sServiceName
+ Case &quot;SFDatabases.Database&quot;
+ If Script = &quot;GetRows&quot; Then vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;SFDialogs.Dialog&quot;
+ If Script = &quot;Controls&quot; Then vReturn = vBasicObject.Controls(vArgs(0))
+ Case &quot;SFDialogs.DialogControl&quot;
+ If Script = &quot;SetTableData&quot; Then vReturn = vBasicObject.SetTableData(vArgs(0), vArgs(1), vArgs(2))
+ Case &quot;SFDocuments.Document&quot;
+ If Script = &quot;Forms&quot; Then vReturn = vBasicObject.Forms(vArgs(0))
+ Case &quot;SFDocuments.Base&quot;
+ Select Case Script
+ Case &quot;FormDocuments&quot; : vReturn = vBasicObject.FormDocuments()
+ Case &quot;Forms&quot; : vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
+ End Select
+ Case &quot;SFDocuments.Calc&quot;
+ Select Case Script
+ Case &quot;Charts&quot; : vReturn = vBasicObject.Charts(vArgs(0), vArgs(1))
+ Case &quot;Forms&quot; : vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
+ Case &quot;GetFormula&quot; : vReturn = vBasicObject.GetFormula(vArgs(0))
+ Case &quot;GetValue&quot; : vReturn = vBasicObject.GetValue(vArgs(0))
+ Case &quot;SetArray&quot; : vReturn = vBasicObject.SetArray(vArgs(0), vArgs(1))
+ Case &quot;SetFormula&quot; : vReturn = vBasicObject.SetFormula(vArgs(0), vArgs(1))
+ Case &quot;SetValue&quot; : vReturn = vBasicObject.SetValue(vArgs(0), vArgs(1))
+ End Select
+ Case &quot;SFDocuments.Form&quot;
+ Select Case Script
+ Case &quot;Controls&quot; : vReturn = vBasicObject.Controls(vArgs(0))
+ Case &quot;Subforms&quot; : vReturn = vBasicObject.Subforms(vArgs(0))
+ End Select
+ Case &quot;SFDocuments.FormControl&quot;
+ If Script = &quot;Controls&quot; Then vReturn = vBasicObject.Controls(vArgs(0))
+ End Select
+ End If
+
+ &apos; Methods in class modules may better not be executed with CallByName()
+ ElseIf bBasicClass And ((CallType And vbMethod) + (CallType And cstHardCode)) = vbMethod + cstHardCode Then
+ Select Case sServiceName
+ Case &quot;SFDialogs.Dialog&quot;
+ Select Case Script
+ Case &quot;Activate&quot; : vReturn = vBasicObject.Activate()
+ Case &quot;Center&quot;
+ If UBound(vArgs) &lt; 0 Then vReturn = vBasicObject.Center() Else vReturn = vBasicObject.Center(vArgs(0))
+ Case &quot;EndExecute&quot; : vReturn = vBasicObject.EndExecute(vArgs(0))
+ Case &quot;Execute&quot; : vReturn = vBasicObject.Execute(vArgs(0))
+ Case &quot;Resize&quot; : vReturn = vBasicObject.Resize(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ End Select
+ End Select
+
+ &apos; Methods in class modules are invoked with CallByName
+ ElseIf bBasicClass And ((CallType And vbMethod) = vbMethod) Then
+ Select Case UBound(vArgs)
+ &apos; Dirty alternatives to process usual and ParamArray cases
+ &apos; But, up to ... how many ?
+ &apos; - The OFFSETADDRESSERROR has 12 arguments
+ &apos; - The &quot;.uno:DataSort&quot; command may have 14 property name-value pairs
+ Case -1 : vReturn = CallByName(vBasicObject, Script, vbMethod)
+ Case 0 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0))
+ Case 1 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1))
+ Case 2 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2))
+ Case 3 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case 4 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
+ Case 5 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
+ Case 6 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
+ Case 7 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
+ Case 8 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8))
+ Case 9 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9))
+ Case 10 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10))
+ Case 11 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11))
+ Case 12, 13 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12))
+ Case 14, 15 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14))
+ Case 16, 17 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16))
+ Case 18, 19 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18))
+ Case 20, 21 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
+ , vArgs(19), vArgs(20))
+ Case 22, 23 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
+ , vArgs(19), vArgs(20), vArgs(21), vArgs(22))
+ Case 24, 25 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
+ , vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24))
+ Case 26, 27 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
+ , vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24), vArgs(25), vArgs(26))
+ Case &gt;= 28 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
+ , vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
+ , vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24), vArgs(25), vArgs(26), vArgs(27), vArgs(28))
+ End Select
+ End If
+
+ &apos; Post processing
+ If Script = &quot;Dispose&quot; Then
+ &apos; Special case: Dispose() must update the cache for class objects created in Python scripts
+ Set _SF_.PythonStorage(BasicObject) = Nothing
+ End If
+ Case Else
+ End Select
+
+ &apos; Format the returned array
+ vReturnArray = Array()
+ &apos; Distinguish: Basic object
+ &apos; UNO object
+ &apos; Array
+ &apos; Scalar
+ If IsArray(vReturn) Then
+ ReDim vReturnArray(0 To 2)
+ iDims = SF_Array.CountDims(vReturn)
+ &apos; Replace dates by UNO format
+ If iDims = 1 Then
+ For i = LBound(vReturn) To UBound(vReturn)
+ If VarType(vReturn(i)) = V_DATE Then vReturn(i) = CDateToUnoDateTime(vReturn(i))
+ Next i
+ ElseIf iDims = 2 Then
+ For i = LBound(vReturn, 1) To UBound(vReturn, 1)
+ For j = LBound(vReturn, 2) To UBound(vReturn, 2)
+ If VarType(vReturn(i, j)) = V_DATE Then vReturn(i, j) = CDateToUnoDateTime(vReturn(i, j))
+ Next j
+ Next i
+ End If
+ vReturnArray(0) = vReturn &apos; 2D arrays are flattened by the script provider when returning to Python
+ vReturnArray(1) = VarType(vReturn)
+ vReturnArray(2) = iDims
+ ElseIf VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
+ &apos; Uno or not Uno ?
+ bUno = False
+ If (CallType And cstUno) = cstUno Then &apos; UNO considered only when pre-announced in CallType
+ Set oObjDesc = SF_Utils._VarTypeObj(vReturn)
+ bUno = ( oObjDesc.iVarType = V_UNOOBJECT )
+ End If
+ If bUno Then
+ ReDim vReturnArray(0 To 2)
+ Set vReturnArray(0) = vReturn
+ Else
+ ReDim vReturnArray(0 To 5)
+ vReturnArray(0) = _SF_._AddToPythonSTorage(vReturn)
+ End If
+ vReturnArray(1) = V_OBJECT
+ vReturnArray(2) = Iif(bUno, objUNO, Iif(bBasicClass, objCLASS, objMODULE))
+ If Not bUno Then
+ vReturnArray(3) = vReturn.ObjectType
+ vReturnArray(4) = vReturn.ServiceName
+ vReturnArray(5) = &quot;&quot;
+ If vReturn.ObjectType &lt;&gt; &quot;SF_CalcReference&quot; Then &apos; Calc references are implemented as a Type ... End Type data structure
+ If SF_Array.Contains(vReturn.Properties(), &quot;Name&quot;, SortOrder := &quot;ASC&quot;) Then vReturnArray(5) = vReturn.Name
+ End If
+ End If
+ Else &apos; Scalar or Nothing
+ ReDim vReturnArray(0 To 1)
+ If VarType(vReturn) = V_DATE Then vReturnArray(0) = CDateToUnoDateTime(vReturn) Else vReturnArray(0) = vReturn
+ vReturnArray(1) = VarType(vReturn)
+ End If
+
+ _PythonDispatcher = vReturnArray
+
+Finally:
+ _SF_.TriggeredByPython = False &apos; Reset normal state
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_PythonHelper._PythonDispatcher
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Basic instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[PythonHelper]&quot;
+
+ _Repr = &quot;[PythonHelper]&quot;
+
+End Function &apos; ScriptForge.SF_PythonHelper._Repr
+
+REM ================================================= END OF SCRIPTFORGE.SF_PythonHelper
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Region.xba b/wizards/source/scriptforge/SF_Region.xba
new file mode 100644
index 000000000..d3eacfae0
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Region.xba
@@ -0,0 +1,861 @@
+<?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_Region" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Region
+&apos;&apos;&apos; =========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Region&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos;
+&apos;&apos;&apos; A collection of functions about languages, countries and timezones
+&apos;&apos;&apos; - Locales
+&apos;&apos;&apos; - Currencies
+&apos;&apos;&apos; - Numbers and dates formatting
+&apos;&apos;&apos; - Calendars
+&apos;&apos;&apos; - Timezones conversions
+&apos;&apos;&apos; - Numbers transformed to text
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; Locale or Region
+&apos;&apos;&apos; A combination of a language (2 or 3 lower case characters) and a country (2 upper case characters)
+&apos;&apos;&apos; Most properties and methods require a locale as argument.
+&apos;&apos;&apos; Some of them accept either the complete locale or only the language or country parts.
+&apos;&apos;&apos; When absent, the considered locale is the locale used in the LibreOffice user interface.
+&apos;&apos;&apos; (see the SF_Platform.OfficeLocale property)
+&apos;&apos;&apos; Timezone
+&apos;&apos;&apos; Specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;.
+&apos;&apos;&apos; The time offset between the timezone and the Greenwich Meridian Time (GMT) is expressed in minutes.
+&apos;&apos;&apos; The Daylight Saving Time (DST) is an additional offset.
+&apos;&apos;&apos; Both offsets can be positive or negative.
+&apos;&apos;&apos; More info on
+&apos;&apos;&apos; https://timezonedb.com/time-zones
+&apos;&apos;&apos; https://en.wikipedia.org/wiki/Time_zone
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim regio As Object
+&apos;&apos;&apos; Set regio = CreateScriptService(&quot;Region&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_region.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private UserLocale As String &apos; platform.OfficeLocale
+
+&apos; Reference tables
+Private LocaleData As Variant &apos; com.sun.star.i18n.LocaleData
+Private LocaleNames As Variant &apos; Array of all available &quot;la-CO&quot; strings
+
+Private UserIndex As Integer &apos; Index of UserLocale in reference tables
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Region Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Country(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the english country name applicable in the given region.
+&apos;&apos;&apos; The region expressed either as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - country only (CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.Country(&quot;IT&quot;) &apos; Italy
+ Country = _PropertyGet(&quot;Country&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.Country (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Currency(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the currency applicable in the given region.
+&apos;&apos;&apos; The region is expressed either as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - country only (CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.Currency(&quot;IT&quot;) &apos; EUR
+ Currency = _PropertyGet(&quot;Currency&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.Currency (get)
+
+REM -----------------------------------------------------------------------------
+Public Function DatePatterns(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of date acceptance patterns for the given region.
+&apos;&apos;&apos; Patterns with input combinations that are accepted as incomplete date input, such as M/D or D.M
+&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; The list is zero-based.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.DatePatterns(&quot;it-IT&quot;), &quot;,&quot;) &apos; D/M/Y,D/M
+ DatePatterns = _PropertyGet(&quot;DatePatterns&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.DatePatterns (get)
+
+REM -----------------------------------------------------------------------------
+Property Get DateSeparator(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the separator used in dates applicable in the given region.
+&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.DateSeparator(&quot;it-IT&quot;) &apos; /
+ DateSeparator = _PropertyGet(&quot;DateSeparator&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.DateSeparator (get)
+
+REM -----------------------------------------------------------------------------
+Public Function DayAbbrevNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of abbreviated names of weekdays applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.DayAbbrevNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; lun,mar,mer,gio,ven,sab,dom
+ DayAbbrevNames = _PropertyGet(&quot;DayAbbrevNames&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.DayAbbrevNames (get)
+
+REM -----------------------------------------------------------------------------
+Public Function DayNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of names of weekdays applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.DayNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; lunedì,martedì,mercoledì,giovedì,venerdì,sabato,domenica
+ DayNames = _PropertyGet(&quot;DayNames&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.DayNames (get)
+
+REM -----------------------------------------------------------------------------
+Public Function DayNarrowNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of initials of weekdays applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.DayNarrowNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; l,m,m,g,v,s,d
+ DayNarrowNames = _PropertyGet(&quot;DayNarrowNames&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.DayNarrowNames (get)
+
+REM -----------------------------------------------------------------------------
+Property Get DecimalPoint(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the decimal separator used in numbers applicable in the given region.
+&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.DecimalPoint(&quot;it-IT&quot;) &apos; .
+ DecimalPoint = _PropertyGet(&quot;DecimalPoint&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.DecimalPoint (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Language(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the english Language name applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.Language(&quot;it-IT&quot;) &apos; Italian
+ Language = _PropertyGet(&quot;Language&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.Language (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ListSeparator(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the separator used in lists applicable in the given region.
+&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.ListSeparator(&quot;it-IT&quot;) &apos; ;
+ ListSeparator = _PropertyGet(&quot;ListSeparator&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.ListSeparator (get)
+
+REM -----------------------------------------------------------------------------
+Public Function MonthAbbrevNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of abbreviated names of months applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; The list is zero-based.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.MonthAbbrevNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic
+ MonthAbbrevNames = _PropertyGet(&quot;MonthAbbrevNames&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.MonthAbbrevNames (get)
+
+REM -----------------------------------------------------------------------------
+Public Function MonthNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of names of months applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; The list is zero-based.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.MonthNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre
+ MonthNames = _PropertyGet(&quot;MonthNames&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.MonthNames (get)
+
+REM -----------------------------------------------------------------------------
+Public Function MonthNarrowNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
+&apos;&apos;&apos; Returns list of initials of months applicable in the given region.
+&apos;&apos;&apos; The region expressed as a
+&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; - language only (la)
+&apos;&apos;&apos; The list is zero-based.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Join(Regio.MonthNarrowNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; g,f,m,a,m,g,l,a,s,o,n,d
+ MonthNarrowNames = _PropertyGet(&quot;MonthNarrowNames&quot;, Region)
+End Function &apos; ScriptForge.SF_Region.MonthNarrowNames (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_Region&quot;
+End Property &apos; ScriptForge.SF_Region.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.Region&quot;
+End Property &apos; ScriptForge.SF_Region.ServiceName
+
+REM -----------------------------------------------------------------------------
+Property Get ThousandSeparator(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the thousands separator used in numbers applicable in the given region.
+&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.ThousandSeparator(&quot;it-IT&quot;) &apos; .
+ ThousandSeparator = _PropertyGet(&quot;ThousandSeparator&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.ThousandSeparator (get)
+
+REM -----------------------------------------------------------------------------
+Property Get TimeSeparator(Optional ByVal Region As Variant) As String
+&apos;&apos;&apos; Returns the separator used to format times applicable in the given region.
+&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox Regio.TimeSeparator(&quot;it-IT&quot;) &apos; :
+ TimeSeparator = _PropertyGet(&quot;TimeSeparator&quot;, Region)
+End Property &apos; ScriptForge.SF_Region.TimeSeparator (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function DSTOffset(Optional ByVal LocalDateTime As Variant _
+ , Optional ByVal TimeZone As Variant _
+ , Optional ByVal Locale As Variant _
+ ) As Integer
+&apos;&apos;&apos; Computes the additional offset due to daylight saving (&quot;summer time&quot;)
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; LocalDateTime: local date and time as a Date. DST offset varies during the year.
+&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
+&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The offset in minutes
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; regio.DSTOffset(DateSerial(2022, 8, 20) + TimeSerial(16, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 60
+
+Dim iDSTOffset As Integer &apos; Return value
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Const cstThisSub = &quot;Region.DSTOffset&quot;
+Const cstSubArgs = &quot;LocalDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iDSTOffset = 0
+
+Check:
+ If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
+ If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendarTZ(oLocale, TimeZone)
+ .setLocalDateTime(LocaldateTime)
+ iDSTOffset = .getValue(com.sun.star.i18n.CalendarFieldIndex.DST_OFFSET)
+ End With
+
+Finally:
+ DSTOffset = iDSTOffset
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.DSTOffset
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant _
+ , Optional Region 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; Region: the language-COUNTRY combination (la-CO) or the country (CO- or the language (la)
+&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;Region.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+Check:
+ If IsMissing(Region) Or IsEmpty(Region) Then Region = &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(Region, &quot;Region&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ If Len(Region) = 0 Then
+ GetProperty = _PropertyGet(PropertyName)
+ Else
+ GetProperty = _PropertyGet(PropertyName, Region)
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function LocalDateTime(Optional ByVal UTCDateTime As Variant _
+ , Optional ByVal TimeZone As Variant _
+ , Optional ByVal Locale As Variant _
+ ) As Date
+&apos;&apos;&apos; Computes the local date and time from a UTC date and time
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; UTCDateTime: the universal date and time to be converted to local time
+&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
+&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The local time converted from the corresponding UTC date and time as a Date
+&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
+&apos;&apos;&apos; If the returned value matches the local time, it is likely that the timezone is not recognized
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; regio.LocalDateTime(DateSerial(2022, 3, 20) + TimeSerial(16, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;)
+&apos;&apos;&apos; &apos; 2022-03-20 17:58:17
+
+Dim dLocalDateTime As Double &apos; Return value
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Const cstThisSub = &quot;Region.LocalDateTime&quot;
+Const cstSubArgs = &quot;UTCDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ dLocalDateTime = -1
+
+Check:
+ If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
+ If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendarTZ(oLocale, TimeZone)
+ .setDateTime(UTCDateTime)
+ dLocalDateTime = .getLocalDateTime()
+ End With
+
+Finally:
+ LocalDateTime = CDate(dLocalDateTime)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.LocalDateTime
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Region class as an array
+
+ Methods = Array( _
+ &quot;DSTOffset&quot; _
+ , &quot;LocalDateTime&quot; _
+ , &quot;Number2Text&quot; _
+ , &quot;TimeZoneOffset&quot; _
+ , &quot;UTCDateTime&quot; _
+ , &quot;UTCNow&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Region.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Number2Text(Optional ByVal Number As Variant _
+ , Optional ByVal Locale As Variant _
+ ) As String
+&apos;&apos;&apos; Convert numbers and money amounts in many languages into words
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; Number: the number to spell out
+&apos;&apos;&apos; Accepted types: strings or numeric values (integer or real numbers)
+&apos;&apos;&apos; When a string, a variety of prefixes is supported
+&apos;&apos;&apos; The string &quot;help&quot; provides helpful tips about allowed prefixes by language
+&apos;&apos;&apos; Example for french
+&apos;&apos;&apos; un, deux, trois
+&apos;&apos;&apos; feminine: une, deux, trois
+&apos;&apos;&apos; masculine: un, deux, trois
+&apos;&apos;&apos; ordinal: premier, deuxième, troisième
+&apos;&apos;&apos; ordinal-feminine: première, deuxième, troisième
+&apos;&apos;&apos; ordinal-masculine: premier, deuxième, troisième
+&apos;&apos;&apos; informal: onze-cents, douze-cents, treize-cents
+&apos;&apos;&apos; Numbers may be prefixed by ISO currency codes (EUR, USD, ...)
+&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or language alone (la)
+&apos;&apos;&apos; The list of supported languages can be found on
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1linguistic2_1_1XNumberText.html
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The number or amount transformed in words
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; regio.Number2Text(&quot;help&quot;, &quot;fr&quot;) &apos; See above
+&apos;&apos;&apos; regio.Number2Text(&quot;79,93&quot;, &quot;fr-BE&quot;) &apos; septante-neuf virgule nonante-trois
+&apos;&apos;&apos; regio.Number2Text(Pi(), &quot;pt-BR&quot;) &apos; três vírgula um quatro um cinco nove dois seis cinco três cinco oito nove sete nove
+&apos;&apos;&apos; regio.Number2Text(&quot;EUR 1234.56&quot;, &quot;it&quot;) &apos; milleduecentotrentaquattro euro cinquantasei centesimi
+
+Dim sNumber2Text As String &apos; Return value
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oNumber2Text As Object &apos; com.sun.star.linguistic2.NumberText
+Const cstThisSub = &quot;Region.Number2Text&quot;
+Const cstSubArgs = &quot;Number, [Locale=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sNumber2Text = &quot;&quot;
+
+Check:
+ If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Number, &quot;Number&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
+ If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ Set oLocale = SF_Region._GetLocale(Locale, pbLanguage := True)
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Set oNumber2Text = SF_Utils._GetUNOService(&quot;Number2Text&quot;)
+ sNumber2Text = oNumber2Text.getNumberText(Number, oLocale)
+
+Finally:
+ Number2Text = sNumber2Text
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.Number2Text
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Region class as an array
+
+ Properties = Array( _
+ &quot;Country&quot; _
+ , &quot;Currency&quot; _
+ , &quot;DatePatterns&quot; _
+ , &quot;DateSeparator&quot; _
+ , &quot;DayAbbrevNames&quot; _
+ , &quot;DayNames&quot; _
+ , &quot;DayNarrowNames&quot; _
+ , &quot;DecimalPoint&quot; _
+ , &quot;Language&quot; _
+ , &quot;ListSeparator&quot; _
+ , &quot;MonthAbbrevNames&quot; _
+ , &quot;MonthNames&quot; _
+ , &quot;MonthNarrowNames&quot; _
+ , &quot;ThousandSeparator&quot; _
+ , &quot;TimeSeparator&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Region.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function TimeZoneOffset(Optional ByVal TimeZone As Variant _
+ , Optional ByVal Locale As Variant _
+ ) As Integer
+&apos;&apos;&apos; Computes the offset between GMT and the given timezone and locale
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
+&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The offset in minutes
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; regio.TimeZoneOffset(&quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 60
+
+Dim iTimeZoneOffset As Integer &apos; Return value
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Const cstThisSub = &quot;Region.TimeZoneOffset&quot;
+Const cstSubArgs = &quot;TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iTimeZoneOffset = 0
+
+Check:
+ If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendarTZ(oLocale, TimeZone)
+ iTimeZoneOffset = .getValue(com.sun.star.i18n.CalendarFieldIndex.ZONE_OFFSET)
+ End With
+
+Finally:
+ TimeZoneOffset = iTimeZoneOffset
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.TimeZoneOffset
+
+REM -----------------------------------------------------------------------------
+Public Function UTCDateTime(Optional ByVal LocalDateTime As Variant _
+ , Optional ByVal TimeZone As Variant _
+ , Optional ByVal Locale As Variant _
+ ) As Date
+&apos;&apos;&apos; Computes the UTC date and time of a given local date and time
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; LocalDateTime: the date and time measured in a given timezone
+&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
+&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The local time converted to the corresponding UTC date and time as a Date
+&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
+&apos;&apos;&apos; If the returned value matches the local time, it is likely that the the timezone is not recognized
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; regio.UTCDateTime(DateSerial(2022, 3, 20) + TimeSerial(17, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;)
+&apos;&apos;&apos; &apos; 2022-03-20 16:58:17
+
+Dim dUTCDateTime As Double &apos; Return value
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Const cstThisSub = &quot;Region.UTCDateTime&quot;
+Const cstSubArgs = &quot;LocalDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ dUTCDateTime = -1
+
+Check:
+ If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
+ If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendarTZ(oLocale, TimeZone)
+ .setLocalDateTime(LocalDateTime)
+ dUTCDateTime = .getDateTime()
+ End With
+
+Finally:
+ UTCDateTime = CDate(dUTCDateTime)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.UTCDateTime
+
+REM -----------------------------------------------------------------------------
+Public Function UTCNow(Optional ByVal TimeZone As Variant _
+ , Optional ByVal Locale As Variant _
+ ) As Date
+&apos;&apos;&apos; Computes the actual UTC date and time
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
+&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The actual UTC date and time as a Date
+&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
+&apos;&apos;&apos; If the returned value matches the local time, it is likely that the the timezone is not recognized
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; regio.UTCNow(&quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 2022-03-20 16:58:17
+
+Dim dUTCNow As Double &apos; Return value
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Const cstThisSub = &quot;Region.UTCNow&quot;
+Const cstSubArgs = &quot;TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ dUTCNow = -1
+
+Check:
+ If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendarTZ(oLocale, TimeZone)
+ .setLocalDateTime(Now())
+ dUTCNow = .getDateTime()
+ End With
+
+Finally:
+ UTCNow = CDate(dUTCNow)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Region.UTCNow
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _GetLocale(ByVal psLocale As String _
+ , Optional ByVal pbCountry As Variant _
+ , Optional ByVal pbLanguage As Variant _
+ ) As Object
+&apos;&apos;&apos; Convert a locale given as a string to a com.sun.star.lang.Locale object
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLocale: the input string, as &quot;la-CO&quot;, &quot;la&quot; or &quot;CO&quot;
+&apos;&apos;&apos; pbCountry: True when &quot;CO&quot; only is admitted
+&apos;&apos;&apos; pbLanguage: True when &quot;la&quot; only is admitted
+&apos;&apos;&apos; At most one out of pbLanguage or pbCountry may be True
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; com.sun.star.lang.Locale
+
+Dim sLocale As String &apos; &quot;la-CO&quot;
+Dim iLocale As Integer &apos; Index in reference tables
+Dim oLocale As Object &apos; Return value com.sun.star.lang.Locale
+Dim i As Integer
+
+ If IsMissing(pbCountry) Or IsEmpty(pbCountry) Then pbCountry = False
+ If IsMissing(pbLanguage) Or IsEmpty(pbLanguage) Then pbLanguage = False
+
+ _LoadAllLocales() &apos; Initialize locale reference tables
+
+Check:
+ &apos; The argument may be a language &quot;la&quot;, a country &quot;CO&quot; or a Locale &quot;la-CO&quot;
+ &apos; Scan the reference tables to find a valid locale as a com.sun.star.lang.Locale
+ Set oLocale = Nothing : sLocale = &quot;&quot; : iLocale = -1
+ If Len(psLocale) = 0 Then &apos; Default value is the office com.sun.star.i18n.Locale
+ sLocale = UserLocale
+ iLocale = UserIndex
+ ElseIf InStr(psLocale, &quot;-&quot;) = 0 Then &apos; Language only or country only
+ Select Case True
+ Case pbLanguage
+ &apos; Find any locale having the argument as language
+ For i = 0 To UBound(LocaleNames)
+ &apos; A language is presumed 2 or 3 characters long
+ If Split(LocaleNames(i), &quot;-&quot;)(0) = LCase(psLocale) Then
+ sLocale = LocaleNames(i)
+ iLocale = i
+ Exit For
+ End If
+ Next i
+ Case pbCountry
+ &apos; Find any locale having the argument as country
+ For i = 0 To UBound(LocaleNames)
+ &apos; A country is presumed exactly 2 characters long
+ If Right(LocaleNames(i), 2) = UCase(psLocale) Then
+ sLocale = LocaleNames(i)
+ iLocale = i
+ Exit For
+ End If
+ Next i
+ Case Else
+ End Select
+ Else &apos; A full locale is given
+ iLocale = SF_Array.IndexOf(LocaleNames, psLocale, CaseSensitive := False)
+ If iLocale &gt;= 0 Then sLocale = LocaleNames(iLocale)
+ End If
+
+Try:
+ &apos; Build error message when relevant
+ If iLocale &lt; 0 Then
+ If Not SF_Utils._Validate(psLocale, &quot;Locale&quot;, V_STRING, LocaleNames) Then GoTo Finally
+ Else
+ Set oLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
+ oLocale.Language = Split(sLocale, &quot;-&quot;)(0) &apos; A language is 2 or 3 characters long
+ oLocale.Country = Right(sLocale, 2)
+ End If
+
+Finally:
+ Set _GetLocale = oLocale
+ Exit Function
+End Function &apos; ScriptForge.SF_Region._GetLocale
+
+REM -----------------------------------------------------------------------------
+Private Sub _LoadAllLocales()
+&apos;&apos;&apos; Initialize the LocaleNames array = the list of all available locales in the LibreOffice installation
+
+Dim oOffice As Object &apos; com.sun.star.lang.Locale
+Dim vLocales As Variant &apos; Array of com.sun.star.lang.Locale
+Dim iTop As Integer &apos; Upper bound of LocaleNames
+Dim i As Integer
+
+Try:
+ &apos; Office locale
+ If Len(UserLocale) = 0 Then
+ Set oOffice = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
+ UserLocale = oOffice.Language &amp; &quot;-&quot; &amp; oOffice.Country
+ End If
+
+ &apos; LocaleData, localeNames and UserIndex
+ If IsEmpty(LocaleData) Or IsNull(LocaleData) Or Not IsArray(LocaleNames) Then
+ LocaleData = SF_Utils._GetUNOService(&quot;LocaleData&quot;)
+ vLocales = LocaleData.getAllInstalledLocaleNames()
+ LocaleNames = Array()
+ iTop = UBound(vLocales)
+ ReDim LocaleNames(0 To iTop)
+ For i = 0 To iTop
+ LocaleNames(i) = vLocales(i).Language &amp; &quot;-&quot; &amp; vLocales(i).Country
+ If LocaleNames(i) = UserLocale Then UserIndex = i
+ Next i
+ End If
+
+End Sub &apos; ScriptForge.SF_Region._LoadAllLocales
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String _
+ , Optional ByVal pvLocale 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
+&apos;&apos;&apos; pvLocale: a locale in the form language-COUNTRY (la-CO) or language only, or country only
+&apos;&apos;&apos; When language or country only, any locale matching either the language or the country is selected
+
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim vCurrencies As Variant &apos; Array of com.sun.star.i18n.Currency
+Dim oCurrency As Object &apos; com.sun.star.i18n.Currency
+Dim oLanguageCountryInfo As Object &apos; com.sun.star.i18n.LanguageCountryInfo
+Dim oLocaleDataItem2 As Object &apos; com.sun.star.i18n.LocaleDataItem2
+Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Dim oCalItem As Object &apos; com.sun.star.i18n.CalendarItem2
+Dim vCalItems() As Variant &apos; Array of days/months
+Dim i As Integer, j As Integer
+
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;Region.Get&quot; &amp; psProperty
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Check:
+ If IsMissing(pvLocale) Or IsEmpty(pvLocale) Then pvLocale = &quot;&quot;
+ If Not SF_Utils._Validate(pvLocale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
+
+ Select Case psProperty
+ Case &quot;Currency&quot;, &quot;Country&quot;
+ Set oLocale = SF_Region._GetLocale(pvLocale, pbCountry := True) &apos; Country only is admitted
+ Case &quot;Language&quot;, &quot;DayNames&quot;, &quot;DayAbbrevNames&quot;, &quot;DayNarrowNames&quot; _
+ , &quot;MonthNames&quot;, &quot;MonthAbbrevNames&quot;, &quot;MonthNarrowNames&quot;
+ Set oLocale = SF_Region._GetLocale(pvLocale, pbLanguage := True) &apos; Language only is admitted
+ Case Else
+ Set oLocale = SF_Region._GetLocale(pvLocale)
+ End Select
+ If IsNull(oLocale) Then GoTo Finally
+
+Try:
+ Select Case psProperty
+ Case &quot;Country&quot;, &quot;Language&quot;
+ Set oLanguageCountryInfo = LocaleData.getLanguageCountryInfo(oLocale)
+ With oLanguageCountryInfo
+ If psProperty = &quot;Country&quot; Then _PropertyGet = .CountryDefaultName Else _PropertyGet = .LanguageDefaultName
+ End With
+ Case &quot;Currency&quot;
+ vCurrencies = LocaleData.getAllCurrencies(oLocale)
+ _PropertyGet = &quot;&quot;
+ For Each oCurrency In vCurrencies
+ If oCurrency.Default Then
+ _PropertyGet = oCurrency.BankSymbol
+ Exit For
+ End If
+ Next oCurrency
+ Case &quot;DatePatterns&quot;
+ _PropertyGet = LocaleData.getDateAcceptancePatterns(oLocale)
+ Case &quot;DateSeparator&quot;, &quot;DecimalPoint&quot;, &quot;ListSeparator&quot;, &quot;ThousandSeparator&quot;, &quot;TimeSeparator&quot;
+ Set oLocaleDataItem2 = LocaleData.getLocaleItem2(oLocale)
+ With oLocaleDataItem2
+ Select Case psProperty
+ Case &quot;DateSeparator&quot; : _PropertyGet = .dateSeparator
+ Case &quot;DecimalPoint&quot; : _PropertyGet = .decimalSeparator
+ Case &quot;ListSeparator&quot; : _PropertyGet = .listSeparator
+ Case &quot;ThousandSeparator&quot; : _PropertyGet = .thousandSeparator
+ Case &quot;TimeSeparator&quot; : _PropertyGet = .timeSeparator
+ End Select
+ End With
+ Case &quot;DayAbbrevNames&quot;, &quot;DayNames&quot;, &quot;DayNarrowNames&quot;
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendar(oLocale)
+ vCalItems = Array() : ReDim vCalItems(0 To 6)
+ For i = 0 To UBound(.Days2)
+ Set oCalItem = .Days2(i)
+ j = Iif(i = 0, 6, i - 1)
+ Select Case psProperty
+ Case &quot;DayNames&quot; : vCalItems(j) = oCalItem.FullName
+ Case &quot;DayAbbrevNames&quot; : vCalItems(j) = oCalItem.AbbrevName
+ Case &quot;DayNarrowNames&quot; : vCalItems(j) = oCalItem.NarrowName
+ End Select
+ Next i
+ _PropertyGet = vCalItems
+ End With
+ Case &quot;MonthAbbrevNames&quot;, &quot;MonthNames&quot;, &quot;MonthNarrowNames&quot;
+ Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
+ With oCalendarImpl
+ .loadDefaultCalendar(oLocale)
+ vCalItems = Array() : ReDim vCalItems(0 To 11)
+ For i = 0 To UBound(.Months2)
+ Set oCalItem = .Months2(i)
+ Select Case psProperty
+ Case &quot;MonthNames&quot; : vCalItems(i) = oCalItem.FullName
+ Case &quot;MonthAbbrevNames&quot; : vCalItems(i) = oCalItem.AbbrevName
+ Case &quot;MonthNarrowNames&quot; : vCalItems(i) = oCalItem.NarrowName
+ End Select
+ Next i
+ _PropertyGet = vCalItems
+ End With
+ Case Else
+ _PropertyGet = &quot;&quot;
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Region._PropertyGet
+
+REM ================================================ END OF SCRIPTFORGE.SF_REGION
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Root.xba b/wizards/source/scriptforge/SF_Root.xba
new file mode 100644
index 000000000..4db0efb42
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Root.xba
@@ -0,0 +1,1070 @@
+<?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_Root" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+Option Private Module
+
+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_Root
+&apos;&apos;&apos; =======
+&apos;&apos;&apos; FOR INTERNAL USE ONLY
+&apos;&apos;&apos; Singleton class holding all persistent variables shared
+&apos;&apos;&apos; by all the modules of the ScriptForge 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 ============================================================= PRIVATE MEMBERS
+
+&apos; Internals
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be &quot;ROOT&quot;
+Private MainFunction As String &apos; Name of method or property called by user script
+Private MainFunctionArgs As String &apos; Syntax of method called by user script
+Private StackLevel As Integer &apos; Depth of calls between internal methods
+
+&apos; Error management
+Private ErrorHandler As Boolean &apos; True = error handling active, False = internal debugging
+Private ConsoleLines() As Variant &apos; Array of messages displayable in console
+Private ConsoleDialog As Object &apos; SFDialogs.Dialog object
+Private ConsoleControl As Object &apos; SFDialogs.DialogControl object
+Private DisplayEnabled As Boolean &apos; When True, display of console or error messages is allowed
+Private StopWhenError As Boolean &apos; When True, process stops after error &gt; &quot;WARNING&quot;
+Private TriggeredByPython As Boolean &apos; When True, the actual user script is a Python script
+Private DebugMode As Boolean &apos; When True, log enter/exit each official Sub
+
+&apos; Progress and status bars
+Private ProgressBarDialog As Object &apos; SFDialogs.Dialog object
+Private ProgressBarText As Object &apos; SFDialogs.DialogControl object
+Private ProgressBarBar As Object &apos; SFDialogs.DialogControl object
+Private Statusbar As Object
+
+&apos; Services management
+Private ServicesList As Variant &apos; Dictionary of provided services
+
+&apos; Usual UNO services
+Private FunctionAccess As Object &apos; com.sun.star.sheet.FunctionAccess
+Private PathSettings As Object &apos; com.sun.star.util.PathSettings
+Private PathSubstitution As Object &apos; com.sun.star.util.PathSubstitution
+Private ScriptProvider As Object &apos; com.sun.star.script.provider.MasterScriptProviderFactory
+Private SystemShellExecute As Object &apos; com.sun.star.system.SystemShellExecute
+Private CoreReflection As Object &apos; com.sun.star.reflection.CoreReflection
+Private DispatchHelper As Object &apos; com.sun.star.frame.DispatchHelper
+Private TextSearch As Object &apos; com.sun.star.util.TextSearch
+Private SearchOptions As Object &apos; com.sun.star.util.SearchOptions
+Private SystemLocale As Object &apos; com.sun.star.lang.Locale
+Private OfficeLocale As Object &apos; com.sun.star.lang.Locale
+Private FormatLocale As Object &apos; com.sun.star.lang.Locale
+Private LocaleData As Object &apos; com.sun.star.i18n.LocaleData
+Private CalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
+Private Number2Text As Object &apos; com.sun.star.linguistic2.NumberText
+Private PrinterServer As Object &apos; com.sun.star.awt.PrinterServer
+Private CharacterClass As Object &apos; com.sun.star.i18n.CharacterClassification
+Private FileAccess As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Private FilterFactory As Object &apos; com.sun.star.document.FilterFactory
+Private FolderPicker As Object &apos; com.sun.star.ui.dialogs.FolderPicker
+Private FilePicker As Object &apos; com.sun.star.ui.dialogs.FilePicker
+Private URLTransformer As Object &apos; com.sun.star.util.URLTransformer
+Private Introspection As Object &apos; com.sun.star.beans.Introspection
+Private BrowseNodeFactory As Object &apos; com.sun.star.script.browse.BrowseNodeFactory
+Private DatabaseContext As Object &apos; com.sun.star.sdb.DatabaseContext
+Private ConfigurationProvider _
+ As Object &apos; com.sun.star.configuration.ConfigurationProvider
+Private PackageProvider As Object &apos; com.sun.star.comp.deployment.PackageInformationProvider
+Private MailService As Object &apos; com.sun.star.system.SimpleCommandMail or com.sun.star.system.SimpleSystemMail
+Private GraphicExportFilter As Object &apos; com.sun.star.drawing.GraphicExportFilter
+Private Toolkit As Object &apos; com.sun.star.awt.Toolkit
+
+&apos; Specific persistent services objects or properties
+Private FileSystemNaming As String &apos; If &quot;SYS&quot;, file and folder naming is based on operating system notation
+Private PythonHelper As String &apos; File name of Python helper functions (stored in $(inst)/share/Scripts/python)
+Private PythonHelper2 As String &apos; Alternate Python helper file name for test purposes
+Private LocalizedInterface As Object &apos; ScriptForge own L10N service
+Private OSName As String &apos; WIN, LINUX, MACOS
+Private SFDialogs As Variant &apos; Persistent storage for the SFDialogs library
+Private SFForms As Variant &apos; Persistent storage for the SF_Form class in the SFDocuments library
+Private PythonStorage As Variant &apos; Persistent storage for the objects created and processed in Python
+Private PythonPermanent As Long &apos; Number of permanent entries in PythonStorage containing standard module objects
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;ROOT&quot;
+ MainFunction = &quot;&quot;
+ MainFunctionArgs = &quot;&quot;
+ StackLevel = 0
+ ErrorHandler = True
+ ConsoleLines = Array()
+ Set ConsoleDialog = Nothing
+ Set ConsoleControl = Nothing
+ DisplayEnabled = True
+ StopWhenError = True
+ TriggeredByPython = False
+ DebugMode = False
+ Set ProgressBarDialog = Nothing
+ Set ProgressBarText = Nothing
+ Set progressBarBar = Nothing
+ Set Statusbar = Nothing
+ ServicesList = Empty
+ Set FunctionAccess = Nothing
+ Set PathSettings = Nothing
+ Set PathSubstitution = Nothing
+ Set ScriptProvider = Nothing
+ Set SystemShellExecute = Nothing
+ Set CoreReflection = Nothing
+ Set DispatchHelper = Nothing
+ Set TextSearch = Nothing
+ Set SearchOptions = Nothing
+ Set SystemLocale = Nothing
+ Set OfficeLocale = Nothing
+ Set FormatLocale = Nothing
+ Set LocaleData = Nothing
+ Set CalendarImpl = Nothing
+ Set Number2Text = Nothing
+ Set PrinterServer = Nothing
+ Set CharacterClass = Nothing
+ Set FileAccess = Nothing
+ Set FilterFactory = Nothing
+ Set FolderPicker = Nothing
+ Set FilePicker = Nothing
+ Set URLTransformer = Nothing
+ Set Introspection = Nothing
+ FileSystemNaming = &quot;ANY&quot;
+ PythonHelper = &quot;ScriptForgeHelper.py&quot;
+ PythonHelper2 = &quot;&quot;
+ Set LocalizedInterface = Nothing
+ Set BrowseNodeFactory = Nothing
+ Set DatabaseContext = Nothing
+ Set ConfigurationProvider = Nothing
+ Set PackageProvider = Nothing
+ Set MailService = Nothing
+ Set GraphicExportFilter = Nothing
+ Set Toolkit = Nothing
+ OSName = &quot;&quot;
+ SFDialogs = Empty
+ SFForms = Empty
+ PythonStorage = Empty
+ PythonPermanent = -1
+End Sub &apos; ScriptForge.SF_Root Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; ScriptForge.SF_Root Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Root Explicit destructor
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Sub _AddToConsole(ByVal psLine As String)
+&apos;&apos;&apos; Add a new line to the console
+&apos;&apos;&apos; TAB characters are expanded before the insertion of the line
+&apos;&apos;&apos; NB: Array redimensioning of a member of an object must be done in the class module
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLine: the line to add
+
+Dim lConsole As Long &apos; UBound of ConsoleLines
+Dim sLine As String &apos; Alias of psLine
+
+ &apos; Resize ConsoleLines
+ lConsole = UBound(ConsoleLines)
+ If lConsole &lt; 0 Then
+ ReDim ConsoleLines(0)
+ Else
+ ReDim Preserve ConsoleLines(0 To lConsole + 1)
+ End If
+
+ &apos; Add a timestamp to the line and insert it (without date)
+ sLine = Mid(SF_Utils._Repr(Now()), 12) &amp; &quot; -&gt; &quot; &amp; psLine
+ ConsoleLines(lConsole + 1) = sLine
+
+ &apos; Add the new line to the actual (probably non-modal) console, if active
+ If Not IsNull(ConsoleDialog) Then
+ If ConsoleDialog._IsStillAlive(False) Then &apos; False to not raise an error
+ If IsNull(ConsoleControl) Then Set ConsoleControl = ConsoleDialog.Controls(SF_Exception.CONSOLENAME) &apos; Should not happen ...
+ ConsoleControl.WriteLine(sLine)
+ End If
+ End If
+
+End Sub &apos; ScriptForge.SF_Root._AddToConsole
+
+REM -----------------------------------------------------------------------------
+Public Function _AddToPythonStorage(ByRef poObject As Object) As Long
+&apos;&apos;&apos; Insert a newly created object in the Python persistent storage
+&apos;&apos;&apos; and return the index of the used entry
+&apos;&apos;&apos; The persistent storage is a simple array of objects
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poObject: the object to insert
+
+Dim lIndex As Long &apos; Return value
+Dim lSize As Long &apos; UBound of the persistent storage
+Dim i As Long
+
+Check:
+ lIndex = -1
+ If IsNull(poObject) Then Exit Function
+ On Local Error GoTo Finally
+ lSize = UBound(PythonStorage)
+
+Try:
+ &apos; Can an empty entry be reused ?
+ For i = PythonPermanent + 1 To lSize
+ If IsNull(PythonStorage(i)) Then
+ lIndex = i
+ Exit For
+ End If
+ Next i
+
+ &apos; Resize Python storage if no empty space
+ If lIndex &lt; 0 Then
+ lSize = lSize + 1
+ ReDim Preserve PythonStorage(0 To lSize)
+ lIndex = lSize
+ End If
+
+ &apos; Insert new object
+ Set PythonStorage(lIndex) = poObject
+
+Finally:
+ _AddToPythonStorage = lIndex
+ Exit Function
+End Function &apos; ScriptForge.SF_Root._AddToPythonStorage
+
+REM ------------------------------------------------------------------------------
+Public Function _GetLocalizedInterface() As Object
+&apos;&apos;&apos; Returns the LN object instance related to the ScriptForge internal localization
+&apos;&apos;&apos; If not yet done, load it from the shipped po files
+&apos;&apos;&apos; Makes that the localized user interface is loaded only when needed
+
+Try:
+ If IsNull(LocalizedInterface) Then _LoadLocalizedInterface()
+
+Finally:
+ Set _GetLocalizedInterface = LocalizedInterface
+ Exit Function
+End Function &apos; ScriptForge.SF_Root._GetLocalizedInterface
+
+REM -----------------------------------------------------------------------------
+Public Sub _InitPythonStorage()
+&apos;&apos;&apos; Make PythonStorage an array
+&apos;&apos;&apos; In prevision to an abundant use of those objects in Python, hardcode to optimize the performance and memory :
+&apos;&apos;&apos; Initialize the first entries with the standard module objects located in the ScriptForge library
+
+Try:
+ If Not IsArray(PythonStorage) Then
+ PythonPermanent = 8
+ PythonStorage = Array()
+ ReDim PythonStorage(0 To PythonPermanent)
+ &apos; Initialize each entry
+ PythonStorage(0) = ScriptForge.SF_Array
+ PythonStorage(1) = ScriptForge.SF_Exception
+ PythonStorage(2) = ScriptForge.SF_FileSystem
+ PythonStorage(3) = ScriptForge.SF_Platform
+ PythonStorage(4) = ScriptForge.SF_Region
+ PythonStorage(5) = ScriptForge.SF_Services
+ PythonStorage(6) = ScriptForge.SF_Session
+ PythonStorage(7) = ScriptForge.SF_String
+ PythonStorage(8) = ScriptForge.SF_UI
+ End If
+
+Finally:
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Root._InitPythonStorage
+
+REM -----------------------------------------------------------------------------
+Public Sub _LoadLocalizedInterface(Optional ByVal psMode As String)
+&apos;&apos;&apos; Build the user interface in a persistent L10N object
+&apos;&apos;&apos; Executed - only once - at first request of a label inside the LocalizedInterface dictionary
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMode: ADDTEXT =&gt; the (english) labels are loaded from code below
+&apos;&apos;&apos; POFILE =&gt; the localized labels are loaded from a PO file
+&apos;&apos;&apos; the name of the file is &quot;la.po&quot; where la = language part of locale
+&apos;&apos;&apos; (fallback to ADDTEXT mode if file does not exist)
+
+Dim sInstallFolder As String &apos; ScriptForge installation directory
+Dim sPOFolder As String &apos; Folder containing the PO files
+Dim sPOFile As String &apos; PO File to load
+Dim sLocale As String &apos; Locale
+
+ If ErrorHandler Then On Local Error GoTo Catch
+
+Try:
+ &apos;TODO: Modify default value
+ If IsMissing(psMode) Then psMode = &quot;POFILE&quot;
+
+ If psMode = &quot;POFILE&quot; Then &apos; Use this mode in production
+ &apos; Build the po file name
+ With SF_FileSystem
+ sInstallFolder = ._SFInstallFolder() &apos; ScriptForge installation folder
+ sLocale = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;).Language
+ sPOFolder = .BuildPath(sInstallFolder, &quot;po&quot;)
+ sPOFile = .BuildPath(sPOFolder, sLocale &amp; &quot;.po&quot;)
+ If sLocale = &quot;en&quot; Then &apos; LocalizedInterface loaded by code i.o. read from po file
+ psMode = &quot;ADDTEXT&quot;
+ ElseIf Not .FileExists(sPOFile) Then &apos; File not found =&gt; load texts from code below
+ psMode = &quot;ADDTEXT&quot;
+ Else
+ Set LocalizedInterface = CreateScriptService(&quot;L10N&quot;, sPOFolder, sLocale)
+ End If
+ End With
+ End If
+
+ If psMode = &quot;ADDTEXT&quot; Then &apos; Use this mode in development to prepare a new POT file
+ Set LocalizedInterface = CreateScriptService(&quot;L10N&quot;)
+ With LocalizedInterface
+ &apos; SF_Exception.Raise
+ .AddText( Context := &quot;ERRORNUMBER&quot; _
+ , MsgId := &quot;Error %1&quot; _
+ , Comment := &quot;Title in error message box\n&quot; _
+ &amp; &quot;%1: an error number&quot; _
+ )
+ .AddText( Context := &quot;ERRORLOCATION&quot; _
+ , MsgId := &quot;Location : %1&quot; _
+ , Comment := &quot;Error message box\n&quot; _
+ &amp; &quot;%1: a line number&quot; _
+ )
+ .AddText( Context := &quot;LONGERRORDESC&quot; _
+ , MsgId := &quot;Error %1 - Location = %2 - Description = %3&quot; _
+ , Comment := &quot;Logfile record&quot; _
+ )
+ .AddText( Context := &quot;STOPEXECUTION&quot; _
+ , MsgId := &quot;THE EXECUTION IS CANCELLED.&quot; _
+ , Comment := &quot;Any blocking error message&quot; _
+ )
+ .AddText( Context := &quot;NEEDMOREHELP&quot; _
+ , MsgId := &quot;Do you want to receive more information about the &apos;%1&apos; method ?&quot; _
+ , Comment := &quot;Any blocking error message\n&quot; _
+ &amp; &quot;%1: a method name&quot; _
+ )
+ &apos; SF_Exception.RaiseAbort
+ .AddText( Context := &quot;INTERNALERROR&quot; _
+ , MsgId := &quot;The ScriptForge library has crashed. The reason is unknown.\n&quot; _
+ &amp; &quot;Maybe a bug that could be reported on\n&quot; _
+ &amp; &quot;\thttps://bugs.documentfoundation.org/\n\n&quot; _
+ &amp; &quot;More details : \n\n&quot; _
+ , Comment := &quot;SF_Exception.RaiseAbort error message&quot; _
+ )
+ &apos; SF_Utils._Validate
+ .AddText( Context := &quot;VALIDATESOURCE&quot; _
+ , MsgId := &quot;Library : \t%1\nService : \t%2\nMethod : \t%3&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: probably ScriptForge\n&quot; _
+ &amp; &quot;%2: service or module name\n&quot; _
+ &amp; &quot;%3: property or method name where the error occurred&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEARGS&quot; _
+ , MsgId := &quot;Arguments: %1&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: list of arguments of the method&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEERROR&quot; _
+ , MsgId := &quot;A serious error has been detected in your code on argument : « %1 ».&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name&quot; _
+ )
+ .AddText( Context := &quot;VALIDATIONRULES&quot; _
+ , MsgId := &quot;\tValidation rules :&quot;, Comment := &quot;SF_Utils.Validate error message&quot; _
+ )
+ .AddText( Context := &quot;VALIDATETYPES&quot; _
+ , MsgId := &quot;\t\t« %1 » must have next type (or one of next types) : %2&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: Comma separated list of allowed types&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEVALUES&quot; _
+ , MsgId := &quot;\t\t« %1 » must contain one of next values : %2&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: Comma separated list of allowed values&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEREGEX&quot; _
+ , MsgId := &quot;\t\t« %1 » must match next regular expression : %2&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: A regular expression&quot; _
+ )
+ .AddText( Context := &quot;VALIDATECLASS&quot; _
+ , MsgId := &quot;\t\t« %1 » must be a Basic object of class : %2&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: The name of a Basic class&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEACTUAL&quot; _
+ , MsgId := &quot;The actual value of « %1 » is : &apos;%2&apos;&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: The value of the argument as a string&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEMISSING&quot; _
+ , MsgId := &quot;The « %1 » argument is mandatory, yet it is missing.&quot; _
+ , Comment := &quot;SF_Utils._Validate error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name&quot; _
+ )
+ &apos; SF_Utils._ValidateArray
+ .AddText( Context := &quot;VALIDATEARRAY&quot; _
+ , MsgId := &quot;\t\t« %1 » must be an array.&quot; _
+ , Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEDIMS&quot; _
+ , MsgId := &quot;\t\t« %1 » must have exactly %2 dimension(s).&quot; _
+ , Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: Number of dimensions of the array&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEALLTYPES&quot; _
+ , MsgId := &quot;\t\t« %1 » must have all elements of the same type : %2&quot; _
+ , Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;%2: Either one single type or &apos;String, Date, Numeric&apos;&quot; _
+ )
+ .AddText( Context := &quot;VALIDATENOTNULL&quot; _
+ , MsgId := &quot;\t\t« %1 » must not contain any NULL or EMPTY elements.&quot; _
+ , Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;NULL and EMPTY should not be translated&quot; _
+ )
+ &apos; SF_Utils._ValidateFile
+ .AddText( Context := &quot;VALIDATEFILE&quot; _
+ , MsgId := &quot;\t\t« %1 » must be of type String.&quot; _
+ , Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;&apos;String&apos; should not be translated&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEFILESYS&quot; _
+ , MsgId := &quot;\t\t« %1 » must be a valid file or folder name expressed in the operating system native notation.&quot; _
+ , Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEFILEURL&quot; _
+ , MsgId := &quot;\t\t« %1 » must be a valid file or folder name expressed in the portable URL notation.&quot; _
+ , Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;&apos;URL&apos; should not be translated&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEFILEANY&quot; _
+ , MsgId := &quot;\t\t« %1 » must be a valid file or folder name.&quot; _
+ , Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name&quot; _
+ )
+ .AddText( Context := &quot;VALIDATEWILDCARD&quot; _
+ , MsgId := &quot;\t\t« %1 » may contain one or more wildcard characters (?, *) in its last path component only.&quot; _
+ , Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
+ &amp; &quot;%1: Wrong argument name\n&quot; _
+ &amp; &quot;&apos;(?, *)&apos; is to be left as is&quot; _
+ )
+ &apos; SF_Array.RangeInit
+ .AddText( Context := &quot;ARRAYSEQUENCE&quot; _
+ , MsgId := &quot;The respective values of &apos;From&apos;, &apos;UpTo&apos; and &apos;ByStep&apos; are incoherent.\n\n&quot; _
+ &amp; &quot;\t« From » = %1\n&quot; _
+ &amp; &quot;\t« UpTo » = %2\n&quot; _
+ &amp; &quot;\t« ByStep » = %3&quot; _
+ , Comment := &quot;SF_Array.RangeInit error message\n&quot; _
+ &amp; &quot;%1, %2, %3: Numeric values\n&quot; _
+ &amp; &quot;&apos;From&apos;, &apos;UpTo&apos;, &apos;ByStep&apos; should not be translated&quot; _
+ )
+ &apos; SF_Array.AppendColumn, AppendRow, PrependColumn, PrependRow
+ .AddText( Context := &quot;ARRAYINSERT&quot; _
+ , MsgId := &quot;The array and the vector to insert have incompatible sizes.\n\n&quot; _
+ &amp; &quot;\t« Array_2D » = %2\n&quot; _
+ &amp; &quot;\t« %1 » = %3&quot; _
+ , Comment := &quot;SF_Array.AppendColumn (...) error message\n&quot; _
+ &amp; &quot;%1: &apos;Column&apos; or &apos;Row&apos; of a matrix\n&quot; _
+ &amp; &quot;%2, %3: array contents\n&quot; _
+ &amp; &quot;&apos;Array_2D&apos; should not be translated&quot; _
+ )
+ &apos; SF_Array.ExtractColumn, ExtractRow
+ .AddText( Context := &quot;ARRAYINDEX1&quot; _
+ , MsgId := &quot;The given index does not fit within the bounds of the array.\n\n&quot; _
+ &amp; &quot;\t« Array_2D » = %2\n&quot; _
+ &amp; &quot;\t« %1 » = %3&quot; _
+ , Comment := &quot;SF_Array.ExtractColumn (...) error message\n&quot; _
+ &amp; &quot;%1: &apos;Column&apos; or &apos;Row&apos; of a matrix\n&quot; _
+ &amp; &quot;%2, %3: array contents\n&quot; _
+ &amp; &quot;&apos;Array_2D&apos; should not be translated&quot; _
+ )
+ &apos; SF_Array.ExtractColumn, ExtractRow
+ .AddText( Context := &quot;ARRAYINDEX2&quot; _
+ , MsgId := &quot;The given slice limits do not fit within the bounds of the array.\n\n&quot; _
+ &amp; &quot;\t« Array_1D » = %1\n&quot; _
+ &amp; &quot;\t« From » = %2\n&quot; _
+ &amp; &quot;\t« UpTo » = %3&quot; _
+ , Comment := &quot;SF_Array.ExtractColumn (...) error message\n&quot; _
+ &amp; &quot;%1: &apos;Column&apos; or &apos;Row&apos; of a matrix\n&quot; _
+ &amp; &quot;%2, %3: array contents\n&quot; _
+ &amp; &quot;&apos;Array_1D&apos;, &apos;From&apos; and &apos;UpTo&apos; should not be translated&quot; _
+ )
+ &apos; SF_Array.ImportFromCSVFile
+ .AddText( Context := &quot;CSVPARSING&quot; _
+ , MsgId := &quot;The given file could not be parsed as a valid CSV file.\n\n&quot; _
+ &amp; &quot;\t« File name » = %1\n&quot; _
+ &amp; &quot;\tLine number = %2\n&quot; _
+ &amp; &quot;\tContent = %3&quot; _
+ , Comment := &quot;SF_Array.ImportFromCSVFile error message\n&quot; _
+ &amp; &quot;%1: a file name\n&quot; _
+ &amp; &quot;%2: numeric\n&quot; _
+ &amp; &quot;%3: a long string&quot; _
+ )
+ &apos; SF_Dictionary.Add/ReplaceKey
+ .AddText( Context := &quot;DUPLICATEKEY&quot; _
+ , MsgId := &quot;The insertion of a new key &quot; _
+ &amp; &quot;into a dictionary failed because the key already exists.\n&quot; _
+ &amp; &quot;Note that the comparison between keys is NOT case-sensitive.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_Dictionary Add/ReplaceKey error message\n&quot; _
+ &amp; &quot;%1: An identifier&quot; _
+ &amp; &quot;%2: a (potentially long) string&quot; _
+ )
+ &apos; SF_Dictionary.Remove/ReplaceKey/ReplaceItem
+ .AddText( Context := &quot;UNKNOWNKEY&quot; _
+ , MsgId := &quot;The requested key does not exist in the dictionary.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_Dictionary Remove/ReplaceKey/ReplaceItem error message\n&quot; _
+ &amp; &quot;%1: An identifier&quot; _
+ &amp; &quot;%2: a (potentially long) string&quot; _
+ )
+ &apos; SF_Dictionary.Add/ReplaceKey
+ .AddText( Context := &quot;INVALIDKEY&quot; _
+ , MsgId := &quot;The insertion or the update of an entry &quot; _
+ &amp; &quot;into a dictionary failed because the given key contains only spaces.&quot; _
+ , Comment := &quot;SF_Dictionary Add/ReplaceKey error message\n&quot; _
+ )
+ &apos; SF_FileSystem.CopyFile/MoveFile/DeleteFile/CreateScriptService(&quot;L10N&quot;)
+ .AddText( Context := &quot;UNKNOWNFILE&quot; _
+ , MsgId := &quot;The given file could not be found on your system.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders
+ .AddText( Context := &quot;UNKNOWNFOLDER&quot; _
+ , MsgId := &quot;The given folder could not be found on your system.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A folder name&quot; _
+ )
+ &apos; SF_FileSystem.CopyFile/MoveFolder/DeleteFile
+ .AddText( Context := &quot;NOTAFILE&quot; _
+ , MsgId := &quot;« %1 » contains the name of an existing folder, not that of a file.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders
+ .AddText( Context := &quot;NOTAFOLDER&quot; _
+ , MsgId := &quot;« %1 » contains the name of an existing file, not that of a folder.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A folder name&quot; _
+ )
+ &apos; SF_FileSystem.Copy+Move/File+Folder/CreateTextFile/OpenTextFile
+ .AddText( Context := &quot;OVERWRITE&quot; _
+ , MsgId := &quot;You tried to create a new file which already exists. Overwriting it has been rejected.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/... error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_FileSystem.Copy+Move+Delete/File+Folder
+ .AddText( Context := &quot;READONLY&quot; _
+ , MsgId := &quot;Copying or moving a file to a destination which has its read-only attribute set, or deleting such a file or folder is forbidden.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_FileSystem.Copy+Move+Delete/File+Folder
+ .AddText( Context := &quot;NOFILEMATCH&quot; _
+ , MsgId := &quot;When « %1 » contains wildcards. at least one file or folder must match the given filter. Otherwise the operation is rejected.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file or folder name with wildcards&quot; _
+ )
+ &apos; SF_FileSystem.CreateFolder
+ .AddText( Context := &quot;FOLDERCREATION&quot; _
+ , MsgId := &quot;« %1 » contains the name of an existing file or an existing folder. The operation is rejected.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_FileSystem CreateFolder error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file or folder name&quot; _
+ )
+ &apos; SF_Services.CreateScriptService
+ .AddText( Context := &quot;UNKNOWNSERVICE&quot; _
+ , MsgId := &quot;No service named &apos;%4&apos; has been registered for the library &apos;%3&apos;.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_Services.CreateScriptService error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: A Basic library name\n&quot; _
+ &amp; &quot;%4: A service (1 word) name&quot; _
+ )
+ &apos; SF_Services.CreateScriptService
+ .AddText( Context := &quot;SERVICESNOTLOADED&quot; _
+ , MsgId := &quot;The library &apos;%3&apos; and its services could not been loaded.\n&quot; _
+ &amp; &quot;The reason is unknown.\n&quot; _
+ &amp; &quot;However, checking the &apos;%3.SF_Services.RegisterScriptServices()&apos; function and its return value can be a good starting point.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_Services.CreateScriptService error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: A Basic library name&quot; _
+ )
+ &apos; SF_Session.ExecuteCalcFunction
+ .AddText( Context := &quot;CALCFUNC&quot; _
+ , MsgId := &quot;The Calc &apos;%1&apos; function encountered an error. Either the given function does not exist or its arguments are invalid.&quot; _
+ , Comment := &quot;SF_Session.ExecuteCalcFunction error message\n&quot; _
+ &amp; &quot;&apos;Calc&apos; should not be translated&quot; _
+ )
+ &apos; SF_Session._GetScript
+ .AddText( Context := &quot;NOSCRIPT&quot; _
+ , MsgId := &quot;The requested %1 script could not be located in the given libraries and modules.\n&quot; _
+ &amp; &quot;« %2 » = %3\n&quot; _
+ &amp; &quot;« %4 » = %5&quot; _
+ , Comment := &quot;SF_Session._GetScript error message\n&quot; _
+ &amp; &quot;%1: &apos;Basic&apos; or &apos;Python&apos;\n&quot; _
+ &amp; &quot;%2: An identifier\n&quot; _
+ &amp; &quot;%3: A string\n&quot; _
+ &amp; &quot;%4: An identifier\n&quot; _
+ &amp; &quot;%5: A string&quot; _
+ )
+ &apos; SF_Session.ExecuteBasicScript
+ .AddText( Context := &quot;SCRIPTEXEC&quot; _
+ , MsgId := &quot;An exception occurred during the execution of the Basic script.\n&quot; _
+ &amp; &quot;Cause: %3\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_Session.ExecuteBasicScript error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: A (long) string&quot; _
+ )
+ &apos; SF_Session.SendMail
+ .AddText( Context := &quot;WRONGEMAIL&quot; _
+ , MsgId := &quot;One of the email addresses has been found invalid.\n&quot; _
+ &amp; &quot;Invalid mail = « %1 »&quot; _
+ , Comment := &quot;SF_Session.SendMail error message\n&quot; _
+ &amp; &quot;%1 = a mail address&quot; _
+ )
+ &apos; SF_Session.SendMail
+ .AddText( Context := &quot;SENDMAIL&quot; _
+ , MsgId := &quot;The message could not be sent due to a system error.\n&quot; _
+ &amp; &quot;A possible cause is that LibreOffice could not find any mail client.&quot; _
+ , Comment := &quot;SF_Session.SendMail error message&quot; _
+ )
+ &apos; SF_TextStream._IsFileOpen
+ .AddText( Context := &quot;FILENOTOPEN&quot; _
+ , MsgId := &quot;The requested file operation could not be executed because the file was closed previously.\n\n&quot; _
+ &amp; &quot;File name = &apos;%1&apos;&quot; _
+ , Comment := &quot;SF_TextStream._IsFileOpen error message\n&quot; _
+ &amp; &quot;%1: A file name&quot; _
+ )
+ &apos; SF_TextStream._IsFileOpen
+ .AddText( Context := &quot;FILEOPENMODE&quot; _
+ , MsgId := &quot;The requested file operation could not be executed because it is incompatible with the mode in which the file was opened.\n\n&quot; _
+ &amp; &quot;File name = &apos;%1&apos;\n&quot; _
+ &amp; &quot;Open mode = %2&quot; _
+ , Comment := &quot;SF_TextStream._IsFileOpen error message\n&quot; _
+ &amp; &quot;%1: A file name\n&quot; _
+ &amp; &quot;%2: READ, WRITE or APPEND&quot; _
+ )
+ &apos; SF_TextStream.ReadLine, ReadAll, SkipLine
+ .AddText( Context := &quot;ENDOFFILE&quot; _
+ , MsgId := &quot;The requested file read operation could not be completed because an unexpected end-of-file was encountered.\n\n&quot; _
+ &amp; &quot;File name = &apos;%1&apos;&quot; _
+ , Comment := &quot;SF_TextStream.ReadLine/ReadAll/SkipLine error message\n&quot; _
+ &amp; &quot;%1: A file name&quot; _
+ )
+ &apos; SF_UI.Document
+ .AddText( Context := &quot;DOCUMENT&quot; _
+ , MsgId := &quot;The requested document could not be found.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;&quot; _
+ , Comment := &quot;SF_UI.GetDocument error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string&quot; _
+ )
+ &apos; SF_UI.Create
+ .AddText( Context := &quot;DOCUMENTCREATION&quot; _
+ , MsgId := &quot;The creation of a new document failed.\n&quot; _
+ &amp; &quot;Something must be wrong with some arguments.\n\n&quot; _
+ &amp; &quot;Either the document type is unknown, or no template file was given,\n&quot; _
+ &amp; &quot;or the given template file was not found on your system.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = &apos;%4&apos;&quot; _
+ , Comment := &quot;SF_UI.GetDocument error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A string&quot; _
+ )
+ &apos; SF_UI.OpenDocument
+ .AddText( Context := &quot;DOCUMENTOPEN&quot; _
+ , MsgId := &quot;The opening of the document failed.\n&quot; _
+ &amp; &quot;Something must be wrong with some arguments.\n\n&quot; _
+ &amp; &quot;Either the file does not exist, or the password is wrong, or the given filter is invalid.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = &apos;%4&apos;\n&quot; _
+ &amp; &quot;%5 = &apos;%6&apos;&quot; _
+ , Comment := &quot;SF_UI.OpenDocument error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A string\n&quot; _
+ &amp; &quot;%5: An identifier\n&quot; _
+ &amp; &quot;%6: A string&quot; _
+ )
+ &apos; SF_UI.OpenBaseDocument
+ .AddText( Context := &quot;BASEDOCUMENTOPEN&quot; _
+ , MsgId := &quot;The opening of the Base document failed.\n&quot; _
+ &amp; &quot;Something must be wrong with some arguments.\n\n&quot; _
+ &amp; &quot;Either the file does not exist, or the file is not registered under the given name.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = &apos;%4&apos;&quot; _
+ , Comment := &quot;SF_UI.OpenDocument error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A string&quot; _
+ )
+ &apos; SF_Document._IsStillAlive
+ .AddText( Context := &quot;DOCUMENTDEAD&quot; _
+ , MsgId := &quot;The requested action could not be executed because the document was closed inadvertently.\n\n&quot; _
+ &amp; &quot;The concerned document is &apos;%1&apos;&quot; _
+ , Comment := &quot;SF_Document._IsStillAlive error message\n&quot; _
+ &amp; &quot;%1: A file name&quot; _
+ )
+ &apos; SF_Document.Save
+ .AddText( Context := &quot;DOCUMENTSAVE&quot; _
+ , MsgId := &quot;The document could not be saved.\n&quot; _
+ &amp; &quot;Either the document has been opened read-only, or the destination file has a read-only attribute set, &quot; _
+ &amp; &quot;or the file where to save to is undefined.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;&quot; _
+ , Comment := &quot;SF_Document.SaveAs error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name\n&quot; _
+ )
+ &apos; SF_Document.SaveAs
+ .AddText( Context := &quot;DOCUMENTSAVEAS&quot; _
+ , MsgId := &quot;The document could not be saved.\n&quot; _
+ &amp; &quot;Either the document must not be overwritten, or the destination file has a read-only attribute set, &quot; _
+ &amp; &quot;or the given filter is invalid.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = %4\n&quot; _
+ &amp; &quot;%5 = &apos;%6&apos;&quot; _
+ , Comment := &quot;SF_Document.SaveAs error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: True or False\n&quot; _
+ &amp; &quot;%5: An identifier\n&quot; _
+ &amp; &quot;%6: A string&quot; _
+ )
+ &apos; SF_Document.any update
+ .AddText( Context := &quot;DOCUMENTREADONLY&quot; _
+ , MsgId := &quot;You tried to edit a document which is not modifiable. The document has not been changed.\n\n&quot; _
+ &amp; &quot;« %1 » = %2&quot; _
+ , Comment := &quot;SF_Document any update\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_Base.GetDatabase
+ .AddText( Context := &quot;DBCONNECT&quot; _
+ , MsgId := &quot;The database related to the actual Base document could not be retrieved.\n&quot; _
+ &amp; &quot;Check the connection/login parameters.\n\n&quot; _
+ &amp; &quot;« %1 » = &apos;%2&apos;\n&quot; _
+ &amp; &quot;« %3 » = &apos;%4&apos;\n&quot; _
+ &amp; &quot;« Document » = %5&quot; _
+ , Comment := &quot;SF_Base GetDatabase\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A user name\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A password\n&quot; _
+ &amp; &quot;%5: A file name&quot; _
+ )
+ &apos; SF_Calc._ParseAddress (sheet)
+ .AddText( Context := &quot;CALCADDRESS1&quot; _
+ , MsgId := &quot;The given address does not correspond with a valid sheet name.\n\n&quot; _
+ &amp; &quot;« %1 » = %2\n&quot; _
+ &amp; &quot;« %3 » = %4&quot; _
+ , Comment := &quot;SF_Calc _ParseAddress (sheet)\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A file name&quot; _
+ )
+ &apos; SF_Calc._ParseAddress (range)
+ .AddText( Context := &quot;CALCADDRESS2&quot; _
+ , MsgId := &quot;The given address does not correspond with a valid range of cells.\n\n&quot; _
+ &amp; &quot;« %1 » = %2\n&quot; _
+ &amp; &quot;« %3 » = %4&quot; _
+ , Comment := &quot;SF_Calc _ParseAddress (range)\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A file name&quot; _
+ )
+ &apos; SF_Calc.InsertSheet
+ .AddText( Context := &quot;DUPLICATESHEET&quot; _
+ , MsgId := &quot;There exists already in the document a sheet with the same name.\n\n&quot; _
+ &amp; &quot;« %1 » = %2\n&quot; _
+ &amp; &quot;« %3 » = %4&quot; _
+ , Comment := &quot;SF_Calc InsertSheet\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A file name&quot; _
+ )
+ &apos; SF_Calc.Offset
+ .AddText( Context := &quot;OFFSETADDRESS&quot; _
+ , MsgId := &quot;The computed range falls beyond the sheet boundaries or is meaningless.\n\n&quot; _
+ &amp; &quot;« %1 » = %2\n&quot; _
+ &amp; &quot;« %3 » = %4\n&quot; _
+ &amp; &quot;« %5 » = %6\n&quot; _
+ &amp; &quot;« %7 » = %8\n&quot; _
+ &amp; &quot;« %9 » = %10\n&quot; _
+ &amp; &quot;« %11 » = %12&quot; _
+ , Comment := &quot;SF_Calc Offset\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A Calc reference\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A number\n&quot; _
+ &amp; &quot;%5: An identifier\n&quot; _
+ &amp; &quot;%6: A number\n&quot; _
+ &amp; &quot;%7: An identifier\n&quot; _
+ &amp; &quot;%8: A number\n&quot; _
+ &amp; &quot;%9: An identifier\n&quot; _
+ &amp; &quot;%10: A number\n&quot; _
+ &amp; &quot;%11: An identifier\n&quot; _
+ &amp; &quot;%12: A file name&quot; _
+ )
+ &apos; SF_Calc.CreateChart
+ .AddText( Context := &quot;DUPLICATECHART&quot; _
+ , MsgId := &quot;A chart with the same name exists already in the sheet.\n\n&quot; _
+ &amp; &quot;« %1 » = %2\n&quot; _
+ &amp; &quot;« %3 » = %4\n&quot; _
+ &amp; &quot;« %5 » = %6\n&quot; _
+ , Comment := &quot;SF_Calc CreateChart\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A string\n&quot; _
+ &amp; &quot;%5: An identifier\n&quot; _
+ &amp; &quot;%6: A file name&quot; _
+ )
+ &apos; SF_Calc.ExportRangeToFile
+ .AddText( Context := &quot;RANGEEXPORT&quot; _
+ , MsgId := &quot;The given range could not be exported.\n&quot; _
+ &amp; &quot;Either the destination file must not be overwritten, or it has a read-only attribute set.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = %4&quot; _
+ , Comment := &quot;SF_Calc.ExportRangeToFile error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: True or False\n&quot; _
+ )
+ &apos; SF_Chart.ExportToFile
+ .AddText( Context := &quot;CHARTEXPORT&quot; _
+ , MsgId := &quot;The chart could not be exported.\n&quot; _
+ &amp; &quot;Either the destination file must not be overwritten, or it has a read-only attribute set.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = %4&quot; _
+ , Comment := &quot;SF_Chart.ExportToFile error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: True or False\n&quot; _
+ )
+ &apos; SF_Form._IsStillAlive
+ .AddText( Context := &quot;FORMDEAD&quot; _
+ , MsgId := &quot;The requested action could not be executed because the form is not open or the document was closed inadvertently.\n\n&quot; _
+ &amp; &quot;The concerned form is &apos;%1&apos; in document &apos;%2&apos;.&quot; _
+ , Comment := &quot;SF_Dialog._IsStillAlive error message\n&quot; _
+ &amp; &quot;%1: An identifier&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_Calc.Forms
+ .AddText( Context := &quot;CALCFORMNOTFOUND&quot; _
+ , MsgId := &quot;The requested form could not be found in the Calc sheet. The given index is off-limits.\n\n&quot; _
+ &amp; &quot;The concerned Calc document is &apos;%3&apos;.\n\n&quot; _
+ &amp; &quot;The name of the sheet = &apos;%2&apos;\n&quot; _
+ &amp; &quot;The index = %1.&quot; _
+ , Comment := &quot;SF_Form determination\n&quot; _
+ &amp; &quot;%1: A number\n&quot; _
+ &amp; &quot;%2: A sheet name\n&quot; _
+ &amp; &quot;%3: A file name&quot; _
+ )
+ &apos; SF_Document.Forms
+ .AddText( Context := &quot;WRITERFORMNOTFOUND&quot; _
+ , MsgId := &quot;The requested form could not be found in the Writer document. The given index is off-limits.\n\n&quot; _
+ &amp; &quot;The concerned Writer document is &apos;%2&apos;.\n\n&quot; _
+ &amp; &quot;The index = %1.&quot; _
+ , Comment := &quot;SF_Form determination\n&quot; _
+ &amp; &quot;%1: A number\n&quot; _
+ &amp; &quot;%2: A file name&quot; _
+ )
+ &apos; SF_Base.Forms
+ .AddText( Context := &quot;BASEFORMNOTFOUND&quot; _
+ , MsgId := &quot;The requested form could not be found in the form document &apos;%2&apos;. The given index is off-limits.\n\n&quot; _
+ &amp; &quot;The concerned Base document is &apos;%3&apos;.\n\n&quot; _
+ &amp; &quot;The index = %1.&quot; _
+ , Comment := &quot;SF_Form determination\n&quot; _
+ &amp; &quot;%1: A number\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: A file name&quot; _
+ )
+ &apos; SF_Form.Subforms
+ .AddText( Context := &quot;SUBFORMNOTFOUND&quot; _
+ , MsgId := &quot;The requested subform could not be found below the given main form.\n\n&quot; _
+ &amp; &quot;The main form = &apos;%2&apos;.\n&quot; _
+ &amp; &quot;The subform = &apos;%1&apos;.&quot; _
+ , Comment := &quot;SF_Form determination\n&quot; _
+ &amp; &quot;%1: A form name\n&quot; _
+ &amp; &quot;%2: A form name&quot; _
+ )
+ &apos; SF_FormControl._SetProperty
+ .AddText( Context := &quot;FORMCONTROLTYPE&quot; _
+ , MsgId := &quot;The control &apos;%1&apos; in form &apos;%2&apos; is of type &apos;%3&apos;.\n&quot; _
+ &amp; &quot;The property or method &apos;%4&apos; is not applicable on that type of form controls.&quot; _
+ , Comment := &quot;SF_FormControl property setting\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: An identifier\n&quot; _
+ &amp; &quot;%3: A string\n&quot; _
+ &amp; &quot;%4: An identifier&quot; _
+ )
+ &apos; SF_Dialog._NewDialog
+ .AddText( Context := &quot;DIALOGNOTFOUND&quot; _
+ , MsgId := &quot;The requested dialog could not be located in the given container or library.\n&quot; _
+ &amp; &quot;« %1 » = %2\n&quot; _
+ &amp; &quot;« %3 » = %4\n&quot; _
+ &amp; &quot;« %5 » = %6\n&quot; _
+ &amp; &quot;« %7 » = %8&quot; _
+ , Comment := &quot;SF_Dialog creation\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A string\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: A file name\n&quot; _
+ &amp; &quot;%5: An identifier\n&quot; _
+ &amp; &quot;%6: A string\n&quot; _
+ &amp; &quot;%7: An identifier\n&quot; _
+ &amp; &quot;%8: A string&quot; _
+ )
+ &apos; SF_Dialog._IsStillAlive
+ .AddText( Context := &quot;DIALOGDEAD&quot; _
+ , MsgId := &quot;The requested action could not be executed because the dialog was closed inadvertently.\n\n&quot; _
+ &amp; &quot;The concerned dialog is &apos;%1&apos;.&quot; _
+ , Comment := &quot;SF_Dialog._IsStillAlive error message\n&quot; _
+ &amp; &quot;%1: An identifier&quot; _
+ )
+ &apos; SF_DialogControl._SetProperty
+ .AddText( Context := &quot;CONTROLTYPE&quot; _
+ , MsgId := &quot;The control &apos;%1&apos; in dialog &apos;%2&apos; is of type &apos;%3&apos;.\n&quot; _
+ &amp; &quot;The property or method &apos;%4&apos; is not applicable on that type of dialog controls.&quot; _
+ , Comment := &quot;SF_DialogControl property setting\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: An identifier\n&quot; _
+ &amp; &quot;%3: A string\n&quot; _
+ &amp; &quot;%4: An identifier&quot; _
+ )
+ &apos; SF_DialogControl.WriteLine
+ .AddText( Context := &quot;TEXTFIELD&quot; _
+ , MsgId := &quot;The control &apos;%1&apos; in dialog &apos;%2&apos; is not a multiline text field.\n&quot; _
+ &amp; &quot;The requested method could not be executed.&quot; _
+ , Comment := &quot;SF_DialogControl add line in textbox\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: An identifier&quot; _
+ )
+ &apos; SF_Database.RunSql
+ .AddText( Context := &quot;DBREADONLY&quot; _
+ , MsgId := &quot;The database has been opened in read-only mode.\n&quot; _
+ &amp; &quot;The &apos;%1&apos; method must not be executed in this context.&quot; _
+ , Comment := &quot;SF_Database when running update SQL statement\n&quot; _
+ &amp; &quot;%1: The concerned method&quot; _
+ )
+ &apos; SF_Database._ExecuteSql
+ .AddText( Context := &quot;SQLSYNTAX&quot; _
+ , MsgId := &quot;An SQL statement could not be interpreted or executed by the database system.\n&quot; _
+ &amp; &quot;Check its syntax, table and/or field names, ...\n\n&quot; _
+ &amp; &quot;SQL Statement : « %1 »&quot; _
+ , Comment := &quot;SF_Database can&apos;t interpret SQL statement\n&quot; _
+ &amp; &quot;%1: The statement&quot; _
+ )
+ &apos; SF_Exception.PythonShell (Python only)
+ .AddText( Context := &quot;PYTHONSHELL&quot; _
+ , MsgId := &quot;The APSO extension could not be located in your LibreOffice installation.&quot; _
+ , Comment := &quot;SF_Exception.PythonShell error message&quot; _
+ &amp; &quot;APSO: to leave unchanged&quot; _
+ )
+ &apos; SFUnitTests._NewUnitTest
+ .AddText( Context := &quot;UNITTESTLIBRARY&quot; _
+ , MsgId := &quot;The requested library could not be located.\n&quot; _
+ &amp; &quot;The UnitTest service has not been initialized.\n\n&quot; _
+ &amp; &quot;Library name : « %1 »&quot; _
+ , Comment := &quot;SFUnitTest could not locate the library gven as argument\n&quot; _
+ &amp; &quot;%1: The name of the library&quot; _
+ )
+ &apos; SFUnitTests.SF_UnitTest
+ .AddText( Context := &quot;UNITTESTMETHOD&quot; _
+ , MsgId := &quot;The method &apos;%1&apos; is unexpected in the current context.\n&quot; _
+ &amp; &quot;The UnitTest service cannot proceed further with the on-going test.&quot; _
+ , Comment := &quot;SFUnitTest finds a RunTest() call in a inappropriate location\n&quot; _
+ &amp; &quot;%1: The name of a method&quot; _
+ )
+ End With
+ End If
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Root._LoadLocalizedInterface
+
+REM -----------------------------------------------------------------------------
+Public Function _Repr() As String
+&apos;&apos;&apos; Convert the unique SF_Root instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Root] (MainFunction: xxx, Console: yyy lines, ServicesList)&quot;
+
+Dim sRoot As String &apos; Return value
+Const cstRoot = &quot;[Root] (&quot;
+
+ sRoot = cstRoot &amp; &quot;MainFunction: &quot; &amp; MainFunction &amp; &quot;, Console: &quot; &amp; UBound(ConsoleLines) + 1 &amp; &quot; lines&quot; _
+ &amp; &quot;, Libraries:&quot; &amp; SF_Utils._Repr(ServicesList.Keys) _
+ &amp; &quot;)&quot;
+
+ _Repr = sRoot
+
+End Function &apos; ScriptForge.SF_Root._Repr
+
+REM -----------------------------------------------------------------------------
+Public Sub _StackReset()
+&apos;&apos;&apos; Reset private members after a fatal/abort error to leave
+&apos;&apos;&apos; a stable persistent storage after an unwanted interrupt
+
+ MainFunction = &quot;&quot;
+ MainFunctionArgs = &quot;&quot;
+ StackLevel = 0
+ TriggeredByPython = False
+
+End Sub &apos; ScriptForge.SF_Root._StackReset
+
+REM ================================================== END OF SCRIPTFORGE.SF_ROOT
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Services.xba b/wizards/source/scriptforge/SF_Services.xba
new file mode 100644
index 000000000..627dc4d2e
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -0,0 +1,639 @@
+<?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_Services" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Services
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Services&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos; The ScriptForge framework includes
+&apos;&apos;&apos; the current ScriptForge library
+&apos;&apos;&apos; a number of &quot;associated&quot; libraries
+&apos;&apos;&apos; any user/contributor extension wanting to fit into the framework
+&apos;&apos;&apos; The methods in this module constitute the kernel of the ScriptForge framework
+&apos;&apos;&apos; - RegisterScriptServices
+&apos;&apos;&apos; Register for a library the list of services it implements
+&apos;&apos;&apos; Each library in the framework must implement its own RegisterScriptServices method
+&apos;&apos;&apos; This method consists in a series of invocations of next 2 methods
+&apos;&apos;&apos; - RegisterService
+&apos;&apos;&apos; Register a single service
+&apos;&apos;&apos; - RegisterEventManager
+&apos;&apos;&apos; Register a single event manager
+&apos;&apos;&apos; - CreateScriptService
+&apos;&apos;&apos; Called by user scripts to get an object giving access to a service or to the event manager
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_services.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const UNKNOWNSERVICEERROR = &quot;UNKNOWNSERVICEERROR&quot; &apos; Service not found within the registered services of the given library
+Const SERVICESNOTLOADEDERROR = &quot;SERVICESNOTLOADEDERROR&quot; &apos; Failure during the registering of the services of the given library
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
+
+REM ============================================================== PUBLIC MEMBERS
+
+&apos; Defines an entry in in the services dictionary
+Type _Service
+ ServiceName As String
+ ServiceType As Integer
+ &apos; 0 Undefined
+ &apos; 1 Basic module
+ &apos; 2 Method reference as a string
+ ServiceReference As Object
+ ServiceMethod As String
+ EventManager As Boolean &apos; True if registered item is an event manager
+End Type
+
+Private vServicesArray As Variant &apos; List of services registered by a library
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function CreateScriptService(Optional ByRef Service As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As Variant
+&apos;&apos;&apos; Create access to the services of a library for the benefit of a user script
+&apos;&apos;&apos; A service is to understand either:
+&apos;&apos;&apos; as a set of methods gathered in a Basic standard module
+&apos;&apos;&apos; or a set of methods and properties gathered in a Basic class module
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Service: the name of the service in 2 parts &quot;library.service&quot;
+&apos;&apos;&apos; The library is a Basic library that must exist in the GlobalScope
+&apos;&apos;&apos; (default = &quot;ScriptForge&quot;)
+&apos;&apos;&apos; The service is one of the services registered by the library
+&apos;&apos;&apos; thru the RegisterScriptServices() routine
+&apos;&apos;&apos; pvArgs: a set of arguments passed to the constructor of the service
+&apos;&apos;&apos; This is only possible if the service refers to a Basic class module
+&apos;&apos;&apos; Returns
+&apos;&apos;&apos; The object containing either the reference of the Basic module
+&apos;&apos;&apos; or of the Basic class instance
+&apos;&apos;&apos; Both are Basic objects
+&apos;&apos;&apos; Returns Nothing if an error occurred.
+&apos;&apos;&apos; ==&gt;&gt; NOTE: The error can be within the user script creating the new class instance
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; SERVICESNOTLOADEDERROR RegisterScriptService probable failure
+&apos;&apos;&apos; UNKNOWNSERVICEERROR Service not found
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; CreateScriptService(&quot;Array&quot;)
+&apos;&apos;&apos; =&gt; Refers to ScriptForge.Array or SF_Array
+&apos;&apos;&apos; CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
+&apos;&apos;&apos; =&gt; Returns a new empty dictionary; &quot;ScriptForge.&quot; is optional
+&apos;&apos;&apos; CreateScriptService(&quot;SFDocuments.Calc&quot;)
+&apos;&apos;&apos; =&gt; Refers to the Calc service, implemented in the SFDocuments library
+&apos;&apos;&apos; CreateScriptService(&quot;Dialog&quot;, dlgName)
+&apos;&apos;&apos; =&gt; Returns a Dialog instance referring to the dlgName dialog
+&apos;&apos;&apos; CreateScriptService(&quot;SFDocuments.Event&quot;, oEvent)
+&apos;&apos;&apos; =&gt; Refers to the Document service instance, implemented in the SFDocuments library, having triggered the event
+
+Dim vScriptService As Variant &apos; Return value
+Dim vServiceItem As Variant &apos; A single service (see _Service type definition)
+Dim vServicesList As Variant &apos; Output of RegisterScriptServices
+Dim vSplit As Variant &apos; Array to split argument in
+Dim sLibrary As String &apos; Library part of the argument
+Dim sService As String &apos; Service part of the argument
+Dim vLibrary As Variant &apos; Dictionary of libraries
+Dim vService As Variant &apos; An individual service object
+Const cstThisSub = &quot;SF_Services.CreateScriptService&quot;
+Const cstSubArgs = &quot;Service, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set vScriptService = Nothing
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Service, &quot;Service&quot;, V_STRING) Then GoTo Catch
+ If Len(Service) = 0 Then GoTo CatchNotFound
+ End If
+
+Try:
+ &apos; Initialize the list of services when CreateScriptService called for the very 1st time
+ If IsEmpty(_SF_.ServicesList) Then _SF_.ServicesList = SF_Services._NewDictionary()
+
+ &apos; Simple parsing of argument
+ vSplit = Split(Service, &quot;.&quot;)
+ If UBound(vSplit) &gt; 1 Then GoTo CatchNotFound
+ If UBound(vSplit) = 0 Then
+ sLibrary = &quot;ScriptForge&quot; &apos; Yes, the default value !
+ sService = vSplit(0)
+ &apos; Accept other default values for associated libraries
+ Select Case LCase(sService)
+ Case &quot;document&quot;, &quot;calc&quot;, &quot;writer&quot;, &quot;base&quot;, &quot;documentevent&quot;, &quot;formevent&quot;
+ sLibrary = &quot;SFDocuments&quot;
+ Case &quot;dialog&quot;, &quot;dialogevent&quot; : sLibrary = &quot;SFDialogs&quot;
+ Case &quot;database&quot; : sLibrary = &quot;SFDatabases&quot;
+ Case &quot;unittest&quot; : sLibrary = &quot;SFUnitTests&quot;
+ Case &quot;menu&quot;, &quot;popupmenu&quot; : sLibrary = &quot;SFWidgets&quot;
+ Case Else
+ End Select
+ Else
+ sLibrary = vSplit(0)
+ sService = vSplit(1)
+ End If
+
+ With _SF_.ServicesList
+
+ &apos; Load the set of services from the library, if not yet done
+ If Not .Exists(sLibrary) Then
+ If Not SF_Services._LoadLibraryServices(sLibrary) Then GoTo CatchNotLoaded
+ End If
+
+ &apos; Find and return the requested service
+ vServicesList = .Item(sLibrary)
+ If Not vServicesList.Exists(sService) Then GoTo CatchNotFound
+ vServiceItem = vServicesList.Item(sService)
+ Select Case vServiceItem.ServiceType
+ Case 1 &apos; Basic module
+ vScriptService = vServiceItem.ServiceReference
+ Case 2 &apos; Method to call
+ If sLibrary = &quot;ScriptForge&quot; Then &apos; Direct call
+ Select Case UCase(sService)
+ Case &quot;DICTIONARY&quot; : vScriptService = SF_Services._NewDictionary()
+ Case &quot;L10N&quot; : vScriptService = SF_Services._NewL10N(pvArgs)
+ Case &quot;TIMER&quot; : vScriptService = SF_Services._NewTimer(pvArgs)
+ Case Else
+ End Select
+ Else &apos; Call via script provider
+ Set vService = SF_Session._GetScript(&quot;Basic&quot;, SF_Session.SCRIPTISAPPLICATION, vServiceItem.ServiceMethod)
+ vScriptService = vService.Invoke(Array(pvArgs()), Array(), Array())
+ End If
+ Case Else
+ End Select
+
+ End With
+
+Finally:
+ CreateScriptService = vScriptService
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ SF_Exception.RaiseFatal(UNKNOWNSERVICEERROR, &quot;Service&quot;, Service, sLibrary, sService)
+ GoTo Finally
+CatchNotLoaded:
+ SF_Exception.RaiseFatal(SERVICESNOTLOADEDERROR, &quot;Service&quot;, Service, sLibrary)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services.CreateScriptService
+
+REM -----------------------------------------------------------------------------
+Public Function RegisterEventManager(Optional ByVal ServiceName As Variant _
+ , Optional ByRef ServiceReference As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Register into ScriptForge a new event entry for the library
+&apos;&apos;&apos; from which this method is called
+&apos;&apos;&apos; MUST BE CALLED ONLY from a specific RegisterScriptServices() method
+&apos;&apos;&apos; Usually the method should be called only once by library
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ServiceName: the name of the service as a string. It the service exists
+&apos;&apos;&apos; already for the library the method overwrites the existing entry
+&apos;&apos;&apos; ServiceReference: the function which will identify the source of the triggered event
+&apos;&apos;&apos; something like: &quot;libraryname.modulename.function&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; &apos; Code snippet stored in a module contained in the SFDocuments library
+&apos;&apos;&apos; Sub RegisterScriptServices()
+&apos;&apos;&apos; &apos; Register the events manager of the library
+&apos;&apos;&apos; RegisterEventManager(&quot;DocumentEvent&quot;, &quot;SFDocuments.SF_Register._EventManager&quot;)
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos; &apos; Code snippet stored in a user script
+&apos;&apos;&apos; Sub Trigger(poEvent As Object) &apos; Triggered by a DOCUMENTEVENT event
+&apos;&apos;&apos; Dim myDoc As Object
+&apos;&apos;&apos; &apos; To get the document concerned by the event:
+&apos;&apos;&apos; Set myDoc = CreateScriptService(&quot;SFDocuments.DocumentEvent&quot;, poEvent)
+&apos;&apos;&apos; End Sub
+
+Dim bRegister As Boolean &apos; Return value
+Const cstThisSub = &quot;SF_Services.RegisterEventManager&quot;
+Const cstSubArgs = &quot;ServiceName, ServiceReference&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRegister = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(ServiceName, &quot;ServiceName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(ServiceReference, &quot;ServiceReference&quot;,V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ bRegister = _AddToServicesArray(ServiceName, ServiceReference, True)
+
+Finally:
+ RegisterEventManager = bRegister
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services.RegisterEventManager
+
+REM -----------------------------------------------------------------------------
+Public Function RegisterService(Optional ByVal ServiceName As Variant _
+ , Optional ByRef ServiceReference As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Register into ScriptForge a new service entry for the library
+&apos;&apos;&apos; from which this method is called
+&apos;&apos;&apos; MUST BE CALLED ONLY from a specific RegisterScriptServices() method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ServiceName: the name of the service as a string. It the service exists
+&apos;&apos;&apos; already for the library the method overwrites the existing entry
+&apos;&apos;&apos; ServiceReference: either
+&apos;&apos;&apos; - the Basic module that implements the methods of the service
+&apos;&apos;&apos; something like: GlobalScope.Library.Module
+&apos;&apos;&apos; - an instance of the class implementing the methods and properties of the service
+&apos;&apos;&apos; something like: &quot;libraryname.modulename.function&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+
+Dim bRegister As Boolean &apos; Return value
+Const cstThisSub = &quot;SF_Services.RegisterService&quot;
+Const cstSubArgs = &quot;ServiceName, ServiceReference&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRegister = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(ServiceName, &quot;ServiceName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(ServiceReference, &quot;ServiceReference&quot;, Array(V_STRING, V_OBJECT)) Then GoTo Finally
+ End If
+
+Try:
+ bRegister = _AddToServicesArray(ServiceName, ServiceReference, False)
+
+Finally:
+ RegisterService = bRegister
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services.RegisterService
+
+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; This method may be stored in any standard (i.e. not class-) module
+&apos;&apos;&apos;
+&apos;&apos;&apos; Each individual service is registered by calling the RegisterService() method
+&apos;&apos;&apos;
+&apos;&apos;&apos; The current version is given as an example
+&apos;&apos;&apos;
+ With GlobalScope.ScriptForge.SF_Services
+ .RegisterService(&quot;Array&quot;, GlobalScope.ScriptForge.SF_Array) &apos; Reference to the Basic module
+ .RegisterService(&quot;Dictionary&quot;, &quot;ScriptForge.SF_Services._NewDictionary&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;Exception&quot;, GlobalScope.ScriptForge.SF_Exception)
+ .RegisterService(&quot;FileSystem&quot;, GlobalScope.ScriptForge.SF_FileSystem)
+ .RegisterService(&quot;L10N&quot;, &quot;ScriptForge.SF_Services._NewL10N&quot;)
+ .RegisterService(&quot;Platform&quot;, GlobalScope.ScriptForge.SF_Platform)
+ .RegisterService(&quot;Region&quot;, GlobalScope.ScriptForge.SF_Region)
+ .RegisterService(&quot;Session&quot;, GlobalScope.ScriptForge.SF_Session)
+ .RegisterService(&quot;String&quot;, GlobalScope.ScriptForge.SF_String)
+ .RegisterService(&quot;Timer&quot;, &quot;ScriptForge.SF_Services._NewTimer&quot;)
+ .RegisterService(&quot;UI&quot;, GlobalScope.ScriptForge.SF_UI)
+ &apos;TODO
+ End With
+
+End Sub &apos; ScriptForge.SF_Services.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _AddToServicesArray(ByVal psServiceName As String _
+ , ByRef pvServiceReference As Variant _
+ , ByVal pbEvent As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Add the arguments as an additional row in vServicesArray (Public variable)
+&apos;&apos;&apos; Called from RegisterService and RegisterEvent methods
+
+Dim bRegister As Boolean &apos; Return value
+Dim lMax As Long &apos; Number of rows in vServicesArray
+
+ bRegister = False
+
+Check:
+ &apos; Ignore when method is not called from RegisterScriptServices()
+ If IsEmpty(vServicesArray) Or IsNull(vServicesArray) Or Not IsArray(vServicesArray) Then GoTo Finally
+
+Try:
+ lMax = UBound(vServicesArray, 1) + 1
+ If lMax &lt;= 0 Then
+ ReDim vServicesArray(0 To 0, 0 To 2)
+ Else
+ ReDim Preserve vServicesArray(0 To lMax, 0 To 2)
+ End If
+ vServicesArray(lMax, 0) = psServiceName
+ vServicesArray(lMax, 1) = pvServiceReference
+ vServicesArray(lMax, 2) = pbEvent
+ bRegister = True
+
+Finally:
+ _AddToServicesArray = bRegister
+ Exit Function
+End Function &apos; ScriptForge.SF_Services._AddToServicesArray
+
+REM -----------------------------------------------------------------------------
+Private Function _FindModuleFromMethod(ByVal psLibrary As String _
+ , ByVal psMethod As String _
+ ) As String
+&apos;&apos;&apos; Find in the given library the name of the module containing
+&apos;&apos;&apos; the method given as 2nd argument (usually RegisterScriptServices)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLibrary: the name of the Basic library
+&apos;&apos;&apos; psMethod: the method to locate
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The name of the module or a zero-length string if not found
+
+Dim vCategories As Variant &apos; &quot;user&quot; or &quot;share&quot; library categories
+Dim sCategory As String
+Dim vLanguages As Variant &apos; &quot;Basic&quot;, &quot;Python&quot;, ... programming languages
+Dim sLanguage As String
+Dim vLibraries As Variant &apos; Library names
+Dim sLibrary As String
+Dim vModules As Variant &apos; Module names
+Dim sModule As String &apos; Return value
+Dim vMethods As Variant &apos; Method/properties/subs/functions
+Dim sMethod As String
+Dim oRoot As Object &apos; com.sun.star.script.browse.BrowseNodeFactory
+Dim i As Integer, j As Integer, k As Integer, l As Integer, m As Integer
+
+ _FindModuleFromMethod = &quot;&quot;
+ Set oRoot = SF_Utils._GetUNOService(&quot;BrowseNodeFactory&quot;).createView(com.sun.star.script.browse.BrowseNodeFactoryViewTypes.MACROORGANIZER)
+
+ &apos; Exploration is done via tree nodes
+ If Not IsNull(oRoot) Then
+ If oRoot.hasChildNodes() Then
+ vCategories = oRoot.getChildNodes()
+ For i = 0 To UBound(vCategories)
+ sCategory = vCategories(i).getName()
+ &apos; Consider &quot;My macros &amp; Dialogs&quot; and &quot;LibreOffice Macros &amp; Dialogs&quot; only
+ If sCategory = &quot;user&quot; Or sCategory = &quot;share&quot; Then
+ If vCategories(i).hasChildNodes() Then
+ vLanguages = vCategories(i).getChildNodes()
+ For j = 0 To UBound(vLanguages)
+ sLanguage = vLanguages(j).getName()
+ &apos; Consider Basic libraries only
+ If sLanguage = &quot;Basic&quot; Then
+ If vLanguages(j).hasChildNodes() Then
+ vLibraries = vLanguages(j).getChildNodes()
+ For k = 0 To UBound(vLibraries)
+ sLibrary = vLibraries(k).getName()
+ &apos; Consider the given library only
+ If sLibrary = psLibrary Then
+ If vLibraries(k).hasChildNodes() Then
+ vModules = vLibraries(k).getChildNodes()
+ For l = 0 To UBound(vModules)
+ sModule = vModules(l).getName()
+ &apos; Check if the module contains the targeted method
+ If vModules(l).hasChildNodes() Then
+ vMethods = vModules(l).getChildNodes()
+ For m = 0 To UBound(vMethods)
+ sMethod = vMethods(m).getName()
+ If sMethod = psMethod Then
+ _FindModuleFromMethod = sModule
+ Exit Function
+ End If
+ Next m
+ End If
+ Next l
+ End If
+ End If
+ Next k
+ End If
+ End If
+ Next j
+ End If
+ End If
+ Next i
+ End If
+ End If
+
+End Function &apos; ScriptForge.SF_Services._FindModuleFromMethod
+
+REM -----------------------------------------------------------------------------
+Private Function _LoadLibraryServices(ByVal psLibrary As String) As Boolean
+&apos;&apos;&apos; Execute psLibrary.RegisterScriptServices() and load its services into the persistent storage
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLibrary: the name of the Basic library
+&apos;&apos;&apos; Library will be loaded if not yet done
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if success
+&apos;&apos;&apos; The list of services is loaded directly into the persistent storage
+
+
+Dim vServicesList As Variant &apos; Dictionary of services
+Dim vService As Variant &apos; Single service entry in dictionary
+Dim vServiceItem As Variant &apos; Single service in vServicesArray
+Dim sModule As String &apos; Name of module containing the RegisterScriptServices method
+Dim i As Long
+Const cstRegister = &quot;RegisterScriptServices&quot;
+
+Try:
+ _LoadLibraryServices = False
+
+ vServicesArray = Array()
+
+ If psLibrary = &quot;ScriptForge&quot; Then
+ &apos; Direct call
+ ScriptForge.SF_Services.RegisterScriptServices()
+ Else
+ &apos; Register services via script provider
+ If GlobalScope.BasicLibraries.hasByName(psLibrary) Then
+ If Not GlobalScope.BasicLibraries.isLibraryLoaded(psLibrary) Then
+ GlobalScope.BasicLibraries.LoadLibrary(psLibrary)
+ End If
+ Else
+ GoTo Finally
+ End If
+ sModule = SF_Services._FindModuleFromMethod(psLibrary, cstRegister)
+ If Len(sModule) = 0 Then GoTo Finally
+ SF_Session.ExecuteBasicScript(, psLibrary &amp; &quot;.&quot; &amp; sModule &amp; &quot;.&quot; &amp; cstRegister)
+ End If
+
+ &apos; Store in persistent storage
+ &apos; - Create list of services for the current library
+ Set vServicesList = SF_Services._NewDictionary()
+ For i = 0 To UBound(vServicesArray, 1)
+ Set vService = New _Service
+ With vService
+ .ServiceName = vServicesArray(i, 0)
+ vServiceItem = vServicesArray(i, 1)
+ If VarType(vServiceItem) = V_STRING Then
+ .ServiceType = 2
+ .ServiceMethod = vServiceItem
+ Set .ServiceReference = Nothing
+ Else &apos; OBJECT
+ .ServiceType = 1
+ .ServiceMethod = &quot;&quot;
+ Set .ServiceReference = vServiceItem
+ End If
+ .EventManager = vServicesArray(i, 2)
+ End With
+ vServicesList.Add(vServicesArray(i, 0), vService)
+ Next i
+ &apos; - Add the new dictionary to the persistent dictionary
+ _SF_.ServicesList.Add(psLibrary, vServicesList)
+ _LoadLibraryServices = True
+ vServicesArray = Empty
+
+Finally:
+ Exit Function
+End Function &apos; ScriptForge.SF_Services._LoadLibraryServices
+
+REM -----------------------------------------------------------------------------
+Public Function _NewDictionary() As Variant
+&apos;&apos;&apos; Create a new instance of the SF_Dictionary class
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oDict As Variant
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+
+Try:
+ Set oDict = New SF_Dictionary
+ Set oDict.[Me] = oDict
+
+Finally:
+ Set _NewDictionary = oDict
+ Exit Function
+Catch:
+ Set oDict = Nothing
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services._NewDictionary
+
+REM -----------------------------------------------------------------------------
+Public Function _NewL10N(Optional ByVal pvArgs As Variant) As Variant
+&apos;&apos;&apos; Create a new instance of the SF_L10N class
+&apos; Args:
+&apos;&apos;&apos; FolderName: the folder containing the PO files in SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; Locale: locale of user session (default) or any other valid la{nguage]-CO[UNTRY] combination
+&apos;&apos;&apos; The country part is optional. Valid are f.i. &quot;fr&quot;, &quot;fr-CH&quot;, &quot;en-US&quot;
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice probably does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Locale2: fallback Locale to select if Locale po file does not exist (typically &quot;en-US&quot;)
+&apos;&apos;&apos; Encoding2: Encoding of the 2nd Locale file
+&apos;&apos;&apos; Returns: the instance or Nothing
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The PO file does not exist
+
+Dim oL10N As Variant &apos; Return value
+Dim sFolderName As String &apos; Folder containing the PO files
+Dim sLocale As String &apos; Passed argument or that of the user session
+Dim sLocale2 As String &apos; Alias for Locale2
+Dim oLocale As Variant &apos; com.sun.star.lang.Locale
+Dim sPOFile As String &apos; PO file must exist
+Dim sEncoding As String &apos; Alias for Encoding
+Dim sEncoding2 As String &apos; Alias for Encoding2
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Then pvArgs = Array()
+ sPOFile = &quot;&quot;
+ sEncoding = &quot;&quot;
+ If UBound(pvArgs) &gt;= 0 Then
+ If Not SF_Utils._ValidateFile(pvArgs(0), &quot;Folder (Arg0)&quot;, , True) Then GoTo Catch
+ sFolderName = pvArgs(0)
+ sLocale = &quot;&quot;
+ If UBound(pvArgs) &gt;= 1 Then
+ If Not SF_Utils._Validate(pvArgs(1), &quot;Locale (Arg1)&quot;, V_STRING) Then GoTo Catch
+ sLocale = pvArgs(1)
+ End If
+ If Len(sLocale) = 0 Then &apos; Called from Python, the Locale argument may be the zero-length string
+ Set oLocale = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
+ sLocale = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
+ End If
+ If UBound(pvArgs) &gt;= 2 Then
+ If IsMissing(pvArgs(2)) Or IsEmpty(pvArgs(2)) Then pvArgs(2) = &quot;UTF-8&quot;
+ If Not SF_Utils._Validate(pvArgs(2), &quot;Encoding (Arg2)&quot;, V_STRING) Then GoTo Catch
+ sEncoding = pvArgs(2)
+ Else
+ sEncoding = &quot;UTF-8&quot;
+ End If
+ sLocale2 = &quot;&quot;
+ If UBound(pvArgs) &gt;= 3 Then
+ If Not SF_Utils._Validate(pvArgs(3), &quot;Locale2 (Arg3)&quot;, V_STRING) Then GoTo Catch
+ sLocale2 = pvArgs(3)
+ End If
+ If UBound(pvArgs) &gt;= 4 Then
+ If Not SF_Utils._Validate(pvArgs(4), &quot;Encoding2 (Arg4)&quot;, V_STRING) Then GoTo Catch
+ sEncoding2 = pvArgs(4)
+ Else
+ sEncoding2 = &quot;UTF-8&quot;
+ End If
+ If Len(sFolderName) &gt; 0 Then
+ sPOFile = SF_FileSystem.BuildPath(sFolderName, sLocale &amp; &quot;.po&quot;)
+ If Not SF_FileSystem.FileExists(sPOFile) Then
+ If Len(sLocale2) = 0 Then GoTo CatchNotExists &apos; No fallback =&gt; error
+ &apos; Try the fallback
+ sPOFile = SF_FileSystem.BuildPath(sFolderName, sLocale2 &amp; &quot;.po&quot;)
+ If Not SF_FileSystem.FileExists(sPOFile) Then GoTo CatchNotExists
+ sEncoding = sEncoding2
+ End If
+ End If
+ End If
+
+Try:
+ Set oL10N = New SF_L10N
+ Set oL10N.[Me] = oL10N
+ oL10N._Initialize(sPOFile, sEncoding)
+
+Finally:
+ Set _NewL10N = oL10N
+ Exit Function
+Catch:
+ Set oL10N = Nothing
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, sPOFile)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services._NewL10N
+
+REM -----------------------------------------------------------------------------
+Public Function _NewTimer(Optional ByVal pvArgs As Variant) As Variant
+&apos;&apos;&apos; Create a new instance of the SF_Timer class
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; [0] : If True, start the timer immediately
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oTimer As Variant &apos; Return value
+Dim bStart As Boolean &apos; Automatic start ?
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Then pvArgs = Array()
+ If UBound(pvArgs) &lt; 0 Then
+ bStart = False
+ Else
+ If Not SF_Utils._Validate(pvArgs(0), &quot;Start (Arg0)&quot;, V_BOOLEAN) Then GoTo Catch
+ bStart = pvArgs(0)
+ End If
+Try:
+ Set oTimer = New SF_Timer
+ Set oTimer.[Me] = oTimer
+ If bStart Then oTimer.Start()
+
+Finally:
+ Set _NewTimer = oTimer
+ Exit Function
+Catch:
+ Set oTimer = Nothing
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services._NewTimer
+
+REM ============================================== END OF SCRIPTFORGE.SF_SERVICES
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Session.xba b/wizards/source/scriptforge/SF_Session.xba
new file mode 100644
index 000000000..b4292f36e
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Session.xba
@@ -0,0 +1,1076 @@
+<?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_Session" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Session
+&apos;&apos;&apos; ==========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Session&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos;
+&apos;&apos;&apos; Gathers diverse general-purpose properties and methods about :
+&apos;&apos;&apos; - installation/execution environment
+&apos;&apos;&apos; - UNO introspection utilities
+&apos;&apos;&apos; - clipboard management
+&apos;&apos;&apos; - invocation of external scripts or programs
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim session As Variant
+&apos;&apos;&apos; session = CreateScriptService(&quot;Session&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_session.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const CALCFUNCERROR = &quot;CALCFUNCERROR&quot; &apos; Calc function execution failed
+Const NOSCRIPTERROR = &quot;NOSCRIPTERROR&quot; &apos; Script could not be located
+Const SCRIPTEXECERROR = &quot;SCRIPTEXECERROR&quot; &apos; Exception during script execution
+Const WRONGEMAILERROR = &quot;WRONGEMAILERROR&quot; &apos; Wrong email address
+Const SENDMAILERROR = &quot;SENDMAILERROR&quot; &apos; Mail could not be sent
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos;&apos;&apos; Script locations
+&apos;&apos;&apos; ================
+&apos;&apos;&apos; Use next constants as Scope argument when invoking next methods:
+&apos;&apos;&apos; ExecuteBasicScript()
+&apos;&apos;&apos; ExecutePythonScript()
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; session.ExecuteBasicScript(session.SCRIPTISEMBEDDED, &quot;Standard.myModule.myFunc&quot;, etc)
+
+Const cstSCRIPTISEMBEDDED = &quot;document&quot; &apos; a library of the document (BASIC + PYTHON)
+Const cstSCRIPTISAPPLICATION = &quot;application&quot; &apos; a shared library (BASIC)
+Const cstSCRIPTISPERSONAL = &quot;user&quot; &apos; a library of My Macros (PYTHON)
+Const cstSCRIPTISPERSOXT = &quot;user:uno_packages&quot; &apos; an extension for the current user (PYTHON)
+Const cstSCRIPTISSHARED = &quot;share&quot; &apos; a library of LibreOffice Macros (PYTHON)
+Const cstSCRIPTISSHAROXT = &quot;share:uno_packages&quot; &apos; an extension for all users (PYTHON)
+Const cstSCRIPTISOXT = &quot;uno_packages&quot; &apos; an extension but install params are unknown (PYTHON)
+
+&apos;&apos;&apos; To build or to parse scripting framework URI&apos;s
+Const cstScript1 = &quot;vnd.sun.star.script:&quot;
+Const cstScript2 = &quot;?language=&quot;
+Const cstScript3 = &quot;&amp;location=&quot;
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Array Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_Session&quot;
+End Property &apos; ScriptForge.SF_Session.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.Session&quot;
+End Property &apos; ScriptForge.SF_Array.ServiceName
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISAPPLICATION As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISAPPLICATION = cstSCRIPTISAPPLICATION
+End Property &apos; ScriptForge.SF_Session.SCRIPTISAPPLICATION
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISEMBEDDED As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISEMBEDDED = cstSCRIPTISEMBEDDED
+End Property &apos; ScriptForge.SF_Session.SCRIPTISEMBEDDED
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISOXT As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISOXT = cstSCRIPTISOXT
+End Property &apos; ScriptForge.SF_Session.SCRIPTISOXT
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISPERSONAL As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISPERSONAL = cstSCRIPTISPERSONAL
+End Property &apos; ScriptForge.SF_Session.SCRIPTISPERSONAL
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISPERSOXT As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISPERSOXT = cstSCRIPTISPERSOXT
+End Property &apos; ScriptForge.SF_Session.SCRIPTISPERSOXT
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISSHARED As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISSHARED = cstSCRIPTISSHARED
+End Property &apos; ScriptForge.SF_Session.SCRIPTISSHARED
+
+REM -----------------------------------------------------------------------------
+Property Get SCRIPTISSHAROXT As String
+&apos;&apos;&apos; Convenient constants
+ SCRIPTISSHAROXT = cstSCRIPTISSHAROXT
+End Property &apos; ScriptForge.SF_Session.SCRIPTISSHAROXT
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function ExecuteBasicScript(Optional ByVal Scope As Variant _
+ , Optional ByVal Script As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As Variant
+&apos;&apos;&apos; Execute the Basic script given as a string and return the value returned by the script
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Scope: &quot;Application&quot; (default) or &quot;Document&quot; (NOT case-sensitive)
+&apos;&apos;&apos; (or use one of the SCRIPTIS... public constants above)
+&apos;&apos;&apos; Script: library.module.method (Case sensitive)
+&apos;&apos;&apos; library =&gt; The library may be not loaded yet
+&apos;&apos;&apos; module =&gt; Must not be a class module
+&apos;&apos;&apos; method =&gt; Sub or Function
+&apos;&apos;&apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; pvArgs: the arguments of the called script
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The value returned by the call to the script
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; NOSCRIPTERROR The script could not be found
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; session.ExecuteBasicScript(, &quot;XrayTool._Main.Xray&quot;, someuno) &apos; Sub: no return expected
+
+Dim oScript As Object &apos; Script to be invoked
+Dim vReturn As Variant &apos; Returned value
+
+Const cstThisSub = &quot;Session.ExecuteBasicScript&quot;
+Const cstSubArgs = &quot;[Scope], Script, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ vReturn = Empty
+
+Check:
+ If IsMissing(Scope) Or IsEmpty(Scope) Then Scope = SCRIPTISAPPLICATION
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Scope, &quot;Scope&quot;, V_STRING _
+ , Array(SCRIPTISAPPLICATION, SCRIPTISEMBEDDED)) Then GoTo Finally
+ If Not SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Execute script
+ Set oScript = SF_Session._GetScript(&quot;Basic&quot;, Scope, Script)
+ On Local Error GoTo CatchExec
+ If Not IsNull(oScript) Then vReturn = oScript.Invoke(pvArgs, Array(), Array())
+
+Finally:
+ ExecuteBasicScript = vReturn
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchExec:
+ SF_Exception.RaiseFatal(SCRIPTEXECERROR, &quot;Script&quot;, Script, Error$)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.ExecuteBasicScript
+
+REM -----------------------------------------------------------------------------
+Public Function ExecuteCalcFunction(Optional ByVal CalcFunction As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As Variant
+&apos;&apos;&apos; Execute a Calc function by its (english) name and based on the given arguments
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; CalcFunction: the english name of the function to execute
+&apos;&apos;&apos; pvArgs: the arguments of the called function
+&apos;&apos;&apos; Each argument must be either a string, a numeric value
+&apos;&apos;&apos; or an array of arrays combining those types
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The (string or numeric) value or the array of arrays returned by the call to the function
+&apos;&apos;&apos; When the arguments contain arrays, the function is executed as an array function
+&apos;&apos;&apos; Wrong arguments generate an error
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; CALCFUNCERROR &apos; Execution error in calc function
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; session.ExecuteCalcFunction(&quot;AVERAGE&quot;, 1, 5, 3, 7) returns 4
+&apos;&apos;&apos; session.ExecuteCalcFunction(&quot;ABS&quot;, Array(Array(-1,2,3),Array(4,-5,6),Array(7,8,-9)))(2)(2) returns 9
+&apos;&apos;&apos; session.ExecuteCalcFunction(&quot;LN&quot;, -3) generates an error
+
+Dim oCalc As Object &apos; Give access to the com.sun.star.sheet.FunctionAccess service
+Dim vReturn As Variant &apos; Returned value
+Const cstThisSub = &quot;Session.ExecuteCalcFunction&quot;
+Const cstSubArgs = &quot;CalcFunction, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vReturn = Empty
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(CalcFunction, &quot;CalcFunction&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Execute function
+ Set oCalc = SF_Utils._GetUNOService(&quot;FunctionAccess&quot;)
+ &apos; Intercept calls from Python when no arguments. Example NOW()
+ If UBound(pvArgs) = 0 Then
+ If IsEmpty(pvArgs(0)) Then pvArgs = Array()
+ End If
+ On Local Error GoTo CatchCall
+ vReturn = oCalc.callFunction(UCase(CalcFunction), pvArgs())
+
+Finally:
+ ExecuteCalcFunction = vReturn
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchCall:
+ SF_Exception.RaiseFatal(CALCFUNCERROR, CalcFunction)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.ExecuteCalcFunction
+
+REM -----------------------------------------------------------------------------
+Public Function ExecutePythonScript(Optional ByVal Scope As Variant _
+ , Optional ByVal Script As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As Variant
+&apos;&apos;&apos; Execute the Python script given as a string and return the value returned by the script
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Scope: one of the SCRIPTIS... public constants above (default = &quot;share&quot;)
+&apos;&apos;&apos; Script: (Case sensitive)
+&apos;&apos;&apos; &quot;library/module.py$method&quot;
+&apos;&apos;&apos; or &quot;module.py$method&quot;
+&apos;&apos;&apos; or &quot;myExtension.oxt|myScript|module.py$method&quot;
+&apos;&apos;&apos; library =&gt; The library may be not loaded yet
+&apos;&apos;&apos; myScript =&gt; The directory containing the python module
+&apos;&apos;&apos; module.py =&gt; The python module
+&apos;&apos;&apos; method =&gt; The python function
+&apos;&apos;&apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; pvArgs: the arguments of the called script
+&apos;&apos;&apos; Date arguments are converted to iso format. However dates in arrays are not converted
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The value(s) returned by the call to the script. If &gt;1 values, enclosed in an array
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; NOSCRIPTERROR The script could not be found
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; session.ExecutePythonScript(session.SCRIPTISSHARED, &quot;Capitalise.py$getNewString&quot;, &quot;Abc&quot;) returns &quot;abc&quot;
+
+Dim oScript As Object &apos; Script to be invoked
+Dim vArg As Variant &apos; Individual argument
+Dim vReturn As Variant &apos; Returned value
+Dim i As Long
+
+Const cstThisSub = &quot;Session.ExecutePythonScript&quot;
+Const cstSubArgs = &quot;[Scope], Script, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ vReturn = Empty
+
+Check:
+ If IsError(Scope) Or IsMissing(Scope) Then Scope = SCRIPTISSHARED
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Scope, &quot;Scope&quot;, V_STRING _
+ , Array(SCRIPTISSHARED, SCRIPTISEMBEDDED, SCRIPTISPERSONAL, SCRIPTISSHAROXT, SCRIPTISPERSOXT, SCRIPTISOXT) _
+ ) Then GoTo Finally
+ If Not SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Filter date arguments - NB: dates in arrays are not filtered
+ For i = 0 To UBound(pvArgs) &apos; pvArgs always zero-based
+ vArg = pvArgs(i)
+ If VarType(vArg) = V_DATE Then pvArgs(i) = SF_Utils._CDateToIso(vArg)
+ Next i
+
+ &apos; Intercept alternate Python helpers file when relevant
+ With _SF_
+ If SF_String.StartsWith(Script, .PythonHelper) And Len(.PythonHelper2) &gt; 0 Then
+ Scope = SCRIPTISPERSONAL
+ Script = .PythonHelper2 &amp; Mid(Script, Len(.PythonHelper) + 1)
+ End If
+ End With
+ &apos; Find script
+ Set oScript = SF_Session._GetScript(&quot;Python&quot;, Scope, Script)
+
+ &apos; Execute script
+ If Not IsNull(oScript) Then
+ vReturn = oScript.Invoke(pvArgs(), Array(), Array())
+ &apos; Remove surrounding array when single returned value
+ If IsArray(vReturn) Then
+ If UBound(vReturn) = 0 Then vReturn = vReturn(0)
+ End If
+ End If
+
+Finally:
+ ExecutePythonScript = vReturn
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.ExecutePythonScript
+
+REM -----------------------------------------------------------------------------
+Public Function GetPDFExportOptions() As Variant
+&apos;&apos;&apos; Return the actual values of the PDF export options
+&apos;&apos;&apos; The PDF options are described on https://wiki.openoffice.org/wiki/API/Tutorials/PDF_export
+&apos;&apos;&apos; PDF options are set at each use of the Export as ... PDF command by the user and kept
+&apos;&apos;&apos; permanently until their reset by script or by a new export
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A ScriptForge dictionary instance listing the 40+ properties and their value
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim dict As Object
+&apos;&apos;&apos; Set dict = session.GetPDFExportOptions()
+&apos;&apos;&apos; MsgBox dict.Item(&quot;Quality&quot;)
+
+Dim vDict As Variant &apos; Returned value
+Dim oConfig As Object &apos; com.sun.star.configuration.ConfigurationProvider
+Dim oNodePath As Object &apos; com.sun.star.beans.PropertyValue
+Dim oOptions As Object &apos; configmgr.RootAccess
+Dim vOptionNames As Variant &apos; Array of PDF options names
+Dim vOptionValues As Variant &apos; Array of PDF options values
+Dim i As Long
+
+Const cstThisSub = &quot;Session.GetPDFExportOptions&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set vDict = Nothing
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ &apos; Get the (read-only) internal PDF options
+ Set oConfig = SF_Utils._GetUNOService(&quot;ConfigurationProvider&quot;)
+ Set oNodePath = SF_Utils._MakePropertyValue(&quot;nodepath&quot;, &quot;/org.openoffice.Office.Common/Filter/PDF/Export/&quot;)
+ Set oOptions = oConfig.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationAccess&quot;, Array(oNodePath))
+
+ &apos; Copy the options into a ScriptForge dictionary
+ Set vDict = CreateScriptService(&quot;dictionary&quot;)
+ vOptionNames = oOptions.getElementNames()
+ vOptionValues = oOptions.getPropertyValues(vOptionNames)
+ &apos;
+ For i = 0 To UBound(vOptionNames)
+ vDict.Add(vOptionNames(i), vOptionValues(i))
+ Next i
+
+
+Finally:
+ GetPDFExportOptions = vDict
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.GetPDFExportOptions
+
+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;Session.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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; ScriptForge.SF_Session.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function HasUnoMethod(Optional ByRef UnoObject As Variant _
+ , Optional ByVal MethodName As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if a UNO object contains the given method
+&apos;&apos;&apos; Code-snippet derived from XRAY
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; UnoObject: the object to identify
+&apos;&apos;&apos; MethodName: the name of the method as a string. The search is case-sensitive
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when the method is not found or when an argument is invalid
+
+Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
+Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
+Dim bMethod As Boolean &apos; Return value
+Const cstThisSub = &quot;Session.HasUnoMethod&quot;
+Const cstSubArgs = &quot;UnoObject, MethodName&quot;
+
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Check:
+ bMethod = False
+ If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
+ If IsNull(UnoObject) Then GoTo Finally
+ If VarType(MethodName) &lt;&gt; V_STRING Then GoTo Finally
+ If MethodName = Space(Len(MethodName)) Then GoTo Finally
+
+Try:
+ On Local Error GoTo Catch
+ Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
+ Set oInspect = oIntrospect.inspect(UnoObject)
+ bMethod = oInspect.hasMethod(MethodName, com.sun.star.beans.MethodConcept.ALL)
+
+Finally:
+ HasUnoMethod = bMethod
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ On Local Error GoTo 0
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.HasUnoMethod
+
+REM -----------------------------------------------------------------------------
+Public Function HasUnoProperty(Optional ByRef UnoObject As Variant _
+ , Optional ByVal PropertyName As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if a UNO object contains the given property
+&apos;&apos;&apos; Code-snippet derived from XRAY
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; UnoObject: the object to identify
+&apos;&apos;&apos; PropertyName: the name of the property as a string. The search is case-sensitive
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when the property is not found or when an argument is invalid
+
+Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
+Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
+Dim bProperty As Boolean &apos; Return value
+Const cstThisSub = &quot;Session.HasUnoProperty&quot;
+Const cstSubArgs = &quot;UnoObject, PropertyName&quot;
+
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Check:
+ bProperty = False
+ If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
+ If IsNull(UnoObject) Then GoTo Finally
+ If VarType(PropertyName) &lt;&gt; V_STRING Then GoTo Finally
+ If PropertyName = Space(Len(PropertyName)) Then GoTo Finally
+
+Try:
+ On Local Error GoTo Catch
+ Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
+ Set oInspect = oIntrospect.inspect(UnoObject)
+ bProperty = oInspect.hasProperty(PropertyName, com.sun.star.beans.PropertyConcept.ALL)
+
+Finally:
+ HasUnoProperty = bProperty
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ On Local Error GoTo 0
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.HasUnoProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Session service as an array
+
+ Methods = Array( _
+ &quot;ExecuteBasicScript&quot; _
+ , &quot;ExecuteCalcFunction&quot; _
+ , &quot;ExecutePythonScript&quot; _
+ , &quot;HasUnoMethod&quot; _
+ , &quot;HasUnoProperty&quot; _
+ , &quot;OpenURLInBrowser&quot; _
+ , &quot;RunApplication&quot; _
+ , &quot;SendMail&quot; _
+ , &quot;UnoMethods&quot; _
+ , &quot;UnoObjectType&quot; _
+ , &quot;UnoProperties&quot; _
+ , &quot;WebService&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Session.Methods
+
+REM -----------------------------------------------------------------------------
+Public Sub OpenURLInBrowser(Optional ByVal URL As Variant)
+&apos;&apos;&apos; Opens a URL in the default browser
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; URL: The URL to open in the browser
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; session.OpenURLInBrowser(&quot;https://docs.python.org/3/library/webbrowser.html&quot;)
+
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Session__OpenURLInBrowser&quot;
+
+Const cstThisSub = &quot;Session.OpenURLInBrowser&quot;
+Const cstSubArgs = &quot;URL&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(URL, &quot;URL&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ ExecutePythonScript(SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, URL)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Session.OpenURLInBrowser
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties as an array
+
+ Properties = Array( _
+ )
+
+End Function &apos; ScriptForge.SF_Session.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function RunApplication(Optional ByVal Command As Variant _
+ , Optional ByVal Parameters As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Executes an arbitrary system command
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Command: The command to execute
+&apos;&apos;&apos; This may be an executable file or a document which is registered with an application
+&apos;&apos;&apos; so that the system knows what application to launch for that document
+&apos;&apos;&apos; Parameters: a list of space separated parameters as a single string
+&apos;&apos;&apos; The method does not validate the given parameters, but only passes them to the specified command
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if success
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; session.RunApplication(&quot;Notepad.exe&quot;)
+&apos;&apos;&apos; session.RunApplication(&quot;C:\myFolder\myDocument.odt&quot;)
+&apos;&apos;&apos; session.RunApplication(&quot;kate&quot;, &quot;/home/me/install.txt&quot;) &apos; (Linux)
+
+Dim bReturn As Boolean &apos; Returned value
+Dim oShell As Object &apos; com.sun.star.system.SystemShellExecute
+Dim sCommand As String &apos; Command as an URL
+Const cstThisSub = &quot;Session.RunApplication&quot;
+Const cstSubArgs = &quot;Command, [Parameters]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bReturn = False
+
+Check:
+ If IsMissing(Parameters) Then Parameters = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Command, &quot;Command&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Parameters, &quot;Parameters&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oShell = SF_Utils._GetUNOService(&quot;SystemShellExecute&quot;)
+ sCommand = SF_FileSystem._ConvertToUrl(Command)
+ oShell.execute(sCommand, Parameters, com.sun.star.system.SystemShellExecuteFlags.URIS_ONLY)
+ bReturn = True
+
+Finally:
+ RunApplication = bReturn
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.RunApplication
+
+REM -----------------------------------------------------------------------------
+Public Sub SendMail(Optional ByVal Recipient As Variant _
+ , Optional ByRef Cc As Variant _
+ , Optional ByRef Bcc As Variant _
+ , Optional ByVal Subject As Variant _
+ , Optional ByRef Body As Variant _
+ , Optional ByVal FileNames As Variant _
+ , Optional ByVal EditMessage As Variant _
+ )
+&apos;&apos;&apos; Send a message (with or without attachments) to recipients from the user&apos;s mail client
+&apos;&apos;&apos; The message may be edited by the user before sending or, alternatively, be sent immediately
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Recipient: an email addresses (To recipient)
+&apos;&apos;&apos; Cc: a comma-delimited list of email addresses (carbon copy)
+&apos;&apos;&apos; Bcc: a comma-delimited list of email addresses (blind carbon copy)
+&apos;&apos;&apos; Subject: the header of the message
+&apos;&apos;&apos; FileNames: a comma-separated list of filenames to attach to the mail. SF_FileSystem naming conventions apply
+&apos;&apos;&apos; Body: the unformatted text of the message
+&apos;&apos;&apos; EditMessage: when True (default) the message is editable before being sent
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR File does not exist
+&apos;&apos;&apos; WRONGEMAILERROR String not recognized as an email address
+&apos;&apos;&apos; SENDMAILERROR System error, probably no mail client
+
+Dim sEmail As String &apos; An single email address
+Dim sFile As String &apos; A single file name
+Dim sArg As String &apos; Argument name
+Dim vCc As Variant &apos; Array alias of Cc
+Dim vBcc As Variant &apos; Array alias of Bcc
+Dim vFileNames As Variant &apos; Array alias of FileNames
+Dim oMailService As Object &apos; com.sun.star.system.SimpleCommandMail or com.sun.star.system.SimpleSystemMail
+Dim oMail As Object &apos; com.sun.star.system.XSimpleMailClient
+Dim oMessage As Object &apos; com.sun.star.system.XSimpleMailMessage
+Dim lFlag As Long &apos; com.sun.star.system.SimpleMailClientFlags.XXX
+Dim ARR As Object : ARR = ScriptForge.SF_Array
+Dim i As Long
+Const cstComma = &quot;,&quot;, cstSemiColon = &quot;;&quot;
+Const cstThisSub = &quot;Session.SendMail&quot;
+Const cstSubArgs = &quot;Recipient, [Cc=&quot;&quot;&quot;&quot;], [Bcc=&quot;&quot;&quot;&quot;], [Subject=&quot;&quot;&quot;&quot;], [FileNames=&quot;&quot;&quot;&quot;], [Body=&quot;&quot;&quot;&quot;], [EditMessage=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Cc) Or IsEmpty(Cc) Then Cc = &quot;&quot;
+ If IsMissing(Bcc) Or IsEmpty(Bcc) Then Bcc = &quot;&quot;
+ If IsMissing(Subject) Or IsEmpty(Subject) Then Subject = &quot;&quot;
+ If IsMissing(FileNames) Or IsEmpty(FileNames) Then FileNames = &quot;&quot;
+ If IsMissing(Body) Or IsEmpty(Body) Then Body = &quot;&quot;
+ If IsMissing(EditMessage) Or IsEmpty(EditMessage) Then EditMessage = True
+
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Cc, &quot;Recipient&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Cc, &quot;Cc&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Bcc, &quot;Bcc&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Subject, &quot;Subject&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(FileNames, &quot;FileNames&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Body, &quot;Body&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(EditMessage, &quot;EditMessage&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+ &apos; Check email addresses
+ sArg = &quot;Recipient&quot; : sEmail = Recipient
+ If Not SF_String.IsEmail(sEmail) Then GoTo CatchEmail
+ sArg = &quot;Cc&quot; : vCc = ARR.TrimArray(Split(Cc, cstComma))
+ For Each sEmail In vCc
+ If Not SF_String.IsEmail(sEmail) Then GoTo CatchEmail
+ Next sEmail
+ sArg = &quot;Bcc&quot; : vBcc = ARR.TrimArray(Split(Bcc, cstComma))
+ For Each sEmail In vBcc
+ If Not SF_String.IsEmail(sEmail) Then GoTo CatchEmail
+ Next sEmail
+
+ &apos; Check file existence
+ If Len(FileNames) &gt; 0 Then
+ vFileNames = ARR.TrimArray(Split(FileNames, cstComma))
+ For i = 0 To UBound(vFileNames)
+ sFile = vFileNames(i)
+ If Not SF_Utils._ValidateFile(sFile, &quot;FileNames&quot;) Then GoTo Finally
+ If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
+ vFileNames(i) = ConvertToUrl(sFile)
+ Next i
+ End If
+
+Try:
+ &apos; Initialize the mail service
+ Set oMailService = SF_Utils._GetUNOService(&quot;MailService&quot;)
+ If IsNull(oMailService) Then GoTo CatchMail
+ Set oMail = oMailService.querySimpleMailClient()
+ If IsNull(oMail) Then GoTo CatchMail
+ Set oMessage = oMail.createSimpleMailMessage()
+ If IsNull(oMessage) Then GoTo CatchMail
+
+ &apos; Feed the new mail message
+ With oMessage
+ .setRecipient(Recipient)
+ If Subject &lt;&gt; &quot;&quot; Then .setSubject(Subject)
+ If UBound(vCc) &gt;= 0 Then .setCcRecipient(vCc)
+ If UBound(vBcc) &gt;= 0 Then .setBccRecipient(vBcc)
+ .Body = Iif(Len(Body) = 0, &quot; &quot;, Body) &apos; Body must not be the empty string ??
+ .setAttachement(vFileNames)
+ End With
+ lFlag = Iif(EditMessage, com.sun.star.system.SimpleMailClientFlags.DEFAULTS, com.sun.star.system.SimpleMailClientFlags.NO_USER_INTERFACE)
+
+ &apos; Send using the mail service
+ oMail.sendSimpleMailMessage(oMessage, lFlag)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+CatchEmail:
+ SF_Exception.RaiseFatal(WRONGEMAILERROR, sArg, sEmail)
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileNames&quot;, sFile)
+ GoTo Finally
+CatchMail:
+ SF_Exception.RaiseFatal(SENDMAILERROR)
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_Session.SendMail
+
+REM -----------------------------------------------------------------------------
+Public Function SetPDFExportOptions(Optional ByRef PDFOptions As Variant) As Boolean
+&apos;&apos;&apos; Modify the actual values of the PDF export options from an options dictionary
+&apos;&apos;&apos; The PDF options are described on https://wiki.openoffice.org/wiki/API/Tutorials/PDF_export
+&apos;&apos;&apos; PDF options are set at each use of the Export as ... PDF command by the user and kept
+&apos;&apos;&apos; permanently until their reset by script (like this one) or by a new export
+&apos;&apos;&apos; The changed options are applicable on any subsequent ExportToPDF user command or to any SaveAsPDF script execution
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PDFOptions: a ScriptForge dictionary object
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim dict As Object
+&apos;&apos;&apos; Set dict = session.GetPDFExportOptions()
+&apos;&apos;&apos; dict.ReplaceItem(&quot;Quality&quot;, 50)
+&apos;&apos;&apos; session.SetPDFExportOptions(dict)
+
+Dim bSetPDF As Boolean &apos; Returned value
+Dim oConfig As Object &apos; com.sun.star.configuration.ConfigurationProvider
+Dim oNodePath As Object &apos; com.sun.star.beans.PropertyValue
+Dim oOptions As Object &apos; configmgr.RootAccess
+Dim vOptionNames As Variant &apos; Array of PDF options names
+Dim vOptionValues As Variant &apos; Array of PDF options values
+Dim oDict As Object &apos; Alias of PDFOptions
+Dim i As Long
+
+Const cstThisSub = &quot;Session.SetPDFExportOptions&quot;
+Const cstSubArgs = &quot;PDFOptions&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSetPDF = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(PDFOptions, &quot;PDFOptions&quot;, V_OBJECT, , , &quot;DICTIONARY&quot;) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Get the (updatable) internal PDF options
+ Set oConfig = SF_Utils._GetUNOService(&quot;ConfigurationProvider&quot;)
+ Set oNodePath = SF_Utils._MakePropertyValue(&quot;nodepath&quot;, &quot;/org.openoffice.Office.Common/Filter/PDF/Export/&quot;)
+ Set oOptions = oConfig.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationUpdateAccess&quot;, Array(oNodePath))
+
+ &apos; Copy the options from the ScriptForge dictionary in argument to property values
+ Set oDict = PDFOptions
+ oOptions.setPropertyValues(oDict.Keys, oDict.Items)
+ oOptions.commitChanges()
+
+ bSetPDF = True
+
+Finally:
+ SetPDFExportOptions = bSetPDF
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.SetPDFExportOptions
+
+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;Session.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; ScriptForge.SF_Session.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function UnoMethods(Optional ByRef UnoObject As Variant) As Variant
+&apos;&apos;&apos; Returns a list of the methods callable from an UNO object
+&apos;&apos;&apos; Code-snippet derived from XRAY
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; UnoObject: the object to identify
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based sorted array. May be empty
+
+Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
+Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
+Dim vMethods As Variant &apos; Array of com.sun.star.reflection.XIdlMethod
+Dim vMethod As Object &apos; com.sun.star.reflection.XIdlMethod
+Dim lMax As Long &apos; UBounf of vMethods
+Dim vMethodsList As Variant &apos; Return value
+Dim i As Long
+Const cstThisSub = &quot;Session.UnoMethods&quot;
+Const cstSubArgs = &quot;UnoObject&quot;
+
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Check:
+ vMethodsList = Array()
+ If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
+ If IsNull(UnoObject) Then GoTo Finally
+
+Try:
+ On Local Error GoTo Catch
+ Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
+ Set oInspect = oIntrospect.inspect(UnoObject)
+ vMethods = oInspect.getMethods(com.sun.star.beans.MethodConcept.ALL)
+
+ &apos; The names must be extracted from com.sun.star.reflection.XIdlMethod structures
+ lMax = UBound(vMethods)
+ If lMax &gt;= 0 Then
+ ReDim vMethodsList(0 To lMax)
+ For i = 0 To lMax
+ vMethodsList(i) = vMethods(i).Name
+ Next i
+ vMethodsList = SF_Array.Sort(vMethodsList, CaseSensitive := True)
+ End If
+
+Finally:
+ UnoMethods = vMethodsList
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ On Local Error GoTo 0
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.UnoMethods
+
+REM -----------------------------------------------------------------------------
+Public Function UnoObjectType(Optional ByRef UnoObject As Variant) As String
+&apos;&apos;&apos; Identify the UNO type of an UNO object
+&apos;&apos;&apos; Code-snippet derived from XRAY
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; UnoObject: the object to identify
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; com.sun.star. ... as a string
+&apos;&apos;&apos; a zero-length string if identification was not successful
+
+Dim oObjDesc As Object &apos; _ObjectDescriptor type
+Dim sObjectType As String &apos; Return value
+Const cstThisSub = &quot;Session.UnoObjectType&quot;
+Const cstSubArgs = &quot;UnoObject&quot;
+
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Check:
+ sObjectType = &quot;&quot;
+ If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
+ If IsNull(UnoObject) Then GoTo Finally
+
+Try:
+ Set oObjDesc = SF_Utils._VarTypeObj(UnoObject)
+ If oObjDesc.iVarType = V_UNOOBJECT Then sObjectType = oObjDesc.sObjectType
+
+Finally:
+ UnoObjectType = sObjectType
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Session.UnoObjectType
+
+REM -----------------------------------------------------------------------------
+Public Function UnoProperties(Optional ByRef UnoObject As Variant) As Variant
+&apos;&apos;&apos; Returns a list of the properties of an UNO object
+&apos;&apos;&apos; Code-snippet derived from XRAY
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; UnoObject: the object to identify
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based sorted array. May be empty
+
+Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
+Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.Property
+Dim vProperty As Object &apos; com.sun.star.beans.Property
+Dim lMax As Long &apos; UBounf of vProperties
+Dim vPropertiesList As Variant &apos; Return value
+Dim i As Long
+Const cstThisSub = &quot;Session.UnoProperties&quot;
+Const cstSubArgs = &quot;UnoObject&quot;
+
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Check:
+ vPropertiesList = Array()
+ If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
+ If IsNull(UnoObject) Then GoTo Finally
+
+Try:
+ On Local Error GoTo Catch
+ Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
+ Set oInspect = oIntrospect.inspect(UnoObject)
+ vProperties = oInspect.getProperties(com.sun.star.beans.PropertyConcept.ALL)
+
+ &apos; The names must be extracted from com.sun.star.beans.Property structures
+ lMax = UBound(vProperties)
+ If lMax &gt;= 0 Then
+ ReDim vPropertiesList(0 To lMax)
+ For i = 0 To lMax
+ vPropertiesList(i) = vProperties(i).Name
+ Next i
+ vPropertiesList = SF_Array.Sort(vPropertiesList, CaseSensitive := True)
+ End If
+
+Finally:
+ UnoProperties = vPropertiesList
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ On Local Error GoTo 0
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.UnoProperties
+
+REM -----------------------------------------------------------------------------
+Public Function WebService(Optional ByVal URI As Variant) As String
+&apos;&apos;&apos; Get some web content from a URI
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; URI: URI text of the web service
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The web page content of the URI
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; CALCFUNCERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; session.WebService(&quot;wiki.documentfoundation.org/api.php?&quot; _
+&apos;&apos;&apos; &amp; &quot;hidebots=1&amp;days=7&amp;limit=50&amp;action=feedrecentchanges&amp;feedformat=rss&quot;)
+
+Dim sReturn As String &apos; Returned value
+Const cstThisSub = &quot;Session.WebService&quot;
+Const cstSubArgs = &quot;URI&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sReturn = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(URI, &quot;URI&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ sReturn = SF_Session.ExecuteCalcFunction(&quot;WEBSERVICE&quot;, URI)
+
+Finally:
+ WebService = sReturn
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session.WebService
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _ExecuteScript(ByVal psScript As String _
+ , Optional ByRef pvArg As Variant _
+ ) As Variant
+&apos;&apos;&apos; Execute the script expressed in the scripting framework_URI notation
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psScript: read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; pvArg: the unique argument to pass to the called script.
+&apos;&apos;&apos; It is often an event object that triggered the execution of the script.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The return value after the script execution. May be ignored for events
+
+Dim sScope As String &apos; The scope part of the script URI
+Dim sLanguage As String &apos; The language part of the script URI
+Dim sScript As String &apos; The script part of the script URI
+Dim vStrings As Variant &apos; Array of strings: (script, language, scope)
+Const cstComma = &quot;,&quot;
+
+Try:
+ If ScriptForge.SF_String.StartsWith(psScript, cstScript1) Then
+ &apos; Parse script
+ vStrings = Split( _
+ Replace( _
+ Replace(Mid(psScript, Len(cstScript1) + 1), cstScript2, cstComma) _
+ , cstScript3, cstComma) _
+ , cstComma)
+ sScript = vStrings(0) : sLanguage = vStrings(1) : sScope = vStrings(2)
+ &apos; Execute script
+ If UCase(sLanguage) = &quot;BASIC&quot; Then
+ _ExecuteScript = ExecuteBasicScript(sScope, sScript, pvArg)
+ Else &apos; Python
+ _ExecuteScript = ExecutePythonScript(sScope, sScript, pvArg)
+ End If
+ End If
+
+End Function &apos; ScriptForge.SF_Session._ExecuteScript
+
+REM -----------------------------------------------------------------------------
+Private Function _GetScript(ByVal psLanguage As String _
+ , ByVal psScope As String _
+ , ByVal psScript As String _
+ ) As Object
+&apos;&apos;&apos; Get the adequate script provider and from there the requested script
+&apos;&apos;&apos; Called by ExecuteBasicScript() and ExecutePythonScript()
+&apos;&apos;&apos; The execution of the script is done by the caller
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLanguage: Basic or Python
+&apos;&apos;&apos; psScope: one of the SCRIPTISxxx constants
+&apos;&apos;&apos; The SCRIPTISOXT constant is an alias for 2 cases, extension either
+&apos;&apos;&apos; installed for one user only, or for all users
+&apos;&apos;&apos; Managed here by trial and error
+&apos;&apos;&apos; psScript: Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A com.sun.star.script.provider.XScript object
+
+Dim sScript As String &apos; The complete script string
+Dim oScriptProvider As Object &apos; Script provider singleton
+Dim oScript As Object &apos; Return value
+
+Try:
+ &apos; Build script string
+ sScript = cstScript1 &amp; psScript &amp; cstScript2 &amp; psLanguage &amp; cstScript3 &amp; LCase(psScope)
+
+ &apos; Find script
+ Set oScript = Nothing
+ &apos; Python only: installation of extension is determined by user =&gt; unknown to script author
+ If psScope = SCRIPTISOXT Then &apos; =&gt; Trial and error
+ On Local Error GoTo ForAllUsers
+ sScript = cstScript1 &amp; psScript &amp; cstScript2 &amp; psLanguage &amp; cstScript3 &amp; SCRIPTISPERSOXT
+ Set oScriptProvider = SF_Utils._GetUNOService(&quot;ScriptProvider&quot;, SCRIPTISPERSOXT)
+ Set oScript = oScriptProvider.getScript(sScript)
+ End If
+ ForAllUsers:
+ On Local Error GoTo CatchNotFound
+ If IsNull(oScript) Then
+ If psScope = SCRIPTISOXT Then psScope = SCRIPTISSHAROXT
+ Set oScriptProvider = SF_Utils._GetUNOService(&quot;ScriptProvider&quot;, psScope)
+ Set oScript = oScriptProvider.getScript(sScript)
+ End If
+
+Finally:
+ _GetScript = oScript
+ Exit Function
+CatchNotFound:
+ SF_Exception.RaiseFatal(NOSCRIPTERROR, psLanguage, &quot;Scope&quot;, psScope, &quot;Script&quot;, psScript)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Session._GetScript
+
+REM =============================================== END OF SCRIPTFORGE.SF_SESSION
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_String.xba b/wizards/source/scriptforge/SF_String.xba
new file mode 100644
index 000000000..888cf672c
--- /dev/null
+++ b/wizards/source/scriptforge/SF_String.xba
@@ -0,0 +1,2734 @@
+<?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_String" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_String
+&apos;&apos;&apos; =========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.String&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos; Focus on string manipulation, regular expressions, encodings and hashing algorithms
+&apos;&apos;&apos; The first argument of almost every method is the string to consider
+&apos;&apos;&apos; It is always passed by reference and left unchanged
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions
+&apos;&apos;&apos; Line breaks: symbolic name(Ascii number)
+&apos;&apos;&apos; LF(10), VT(12), CR(13), LF+CR, File separator(28), Group separator(29), Record separator(30),
+&apos;&apos;&apos; Next Line(133), Line separator(8232), Paragraph separator(8233)
+&apos;&apos;&apos; Whitespaces: symbolic name(Ascii number)
+&apos;&apos;&apos; Space(32), HT(9), LF(10), VT(11), FF(12), CR(13), Next Line(133), No-break space(160),
+&apos;&apos;&apos; Line separator(8232), Paragraph separator(8233)
+&apos;&apos;&apos; A quoted string:
+&apos;&apos;&apos; The quoting character must be the double quote (&quot;)
+&apos;&apos;&apos; To preserve a quoting character inside the quoted substring, use (\) or (&quot;) as escape character
+&apos;&apos;&apos; =&gt; [str\&quot;i&quot;&quot;ng] means [str&quot;i&quot;ng]
+&apos;&apos;&apos; Escape sequences: symbolic name(Ascii number) = escape sequence
+&apos;&apos;&apos; Line feed(10) = &quot;\n&quot;
+&apos;&apos;&apos; Carriage return(13) = &quot;\r&quot;
+&apos;&apos;&apos; Horizontal tab(9) = &quot;\t&quot;
+&apos;&apos;&apos; Double the backslash to ignore the sequence, e.g. &quot;\\n&quot; means &quot;\n&quot; (not &quot;\&quot; &amp; Chr(10)).
+&apos;&apos;&apos; Not printable characters:
+&apos;&apos;&apos; Defined in the Unicode character database as “Other” or “Separator”
+&apos;&apos;&apos; In particular, &quot;control&quot; characters (ascii code &lt;= 0x1F) are not printable
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_string.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos; Some references:
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1i18n_1_1KCharacterType.html
+&apos;&apos;&apos; com.sun.star.i18n.KCharacterType.###
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1i18n_1_1XCharacterClassification.html
+&apos;&apos;&apos; com.sun.star.i18n.XCharacterClassification
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos;&apos;&apos; Most expressions below are derived from https://www.regular-expressions.info/
+
+Const REGEXALPHA = &quot;^[A-Za-z]+$&quot; &apos; Not used
+Const REGEXALPHANUM = &quot;^[\w]+$&quot;
+Const REGEXDATEDAY = &quot;(0[1-9]|[12][0-9]|3[01])&quot;
+Const REGEXDATEMONTH = &quot;(0[1-9]|1[012])&quot;
+Const REGEXDATEYEAR = &quot;(19|20)\d\d&quot;
+Const REGEXTIMEHOUR = &quot;(0[1-9]|1[0-9]|2[0123])&quot;
+Const REGEXTIMEMIN = &quot;([0-5][0-9])&quot;
+Const REGEXTIMESEC = REGEXTIMEMIN
+Const REGEXDIGITS = &quot;^[0-9]+$&quot;
+Const REGEXEMAIL = &quot;^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$&quot;
+Const REGEXFILELINUX = &quot;^[^&lt;&gt;:;,?&quot;&quot;*|\\]+$&quot;
+Const REGEXFILEWIN = &quot;^([A-Z]|[a-z]:)?[^&lt;&gt;:;,?&quot;&quot;*|]+$&quot;
+Const REGEXHEXA = &quot;^(0X|&amp;H)?[0-9A-F]+$&quot; &apos; Includes 0xFF and &amp;HFF
+Const REGEXIPV4 = &quot;^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$&quot;
+Const REGEXNUMBER = &quot;^[-+]?(([0-9]+)?\.)?[0-9]+([eE][-+]?[0-9]+)?$&quot;
+Const REGEXURL = &quot;^(https?|ftp)://[^\s/$.?#].[^\s]*$&quot;
+Const REGEXWHITESPACES = &quot;^[\s]+$&quot;
+Const REGEXLTRIM = &quot;^[\s]+&quot;
+Const REGEXRTRIM = &quot;[\s]+$&quot;
+Const REGEXSPACES = &quot;[\s]+&quot;
+
+&apos;&apos;&apos; Accented characters substitution: https://docs.google.com/spreadsheets/d/1pJKSueZK8RkAcJFQIiKpYUamWSC1u1xVQchK7Z7BIwc/edit#gid=0
+&apos;&apos;&apos; (Many of them are in the list, but do not consider the list as closed vs. the Unicode database)
+
+Const cstCHARSWITHACCENT = &quot;ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿŠšŸŽž&quot; _
+ &amp; &quot;ĂăĐđĨĩŨũƠơƯưẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹ₫&quot;
+Const cstCHARSWITHOUTACCENT = &quot;AAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyySsYZz&quot; _
+ &amp; &quot;AaDdIiUuOoUuAaAaAaAaAaAaAaAaAaAaAaAaEeEeEeEeEeEeEeEeIiIiOoOoOoOoOoOoOoOoOoOoOoOoUuUuUuUuUuUuUuYyYyYyYyd&quot;
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_String Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get CHARSWITHACCENT() As String
+&apos;&apos;&apos; Latin accents
+ CHARSWITHACCENT = cstCHARSWITHACCENT
+End Property &apos; ScriptForge.SF_String.CHARSWITHACCENT
+
+REM -----------------------------------------------------------------------------
+Property Get CHARSWITHOUTACCENT() As String
+&apos;&apos;&apos; Latin accents
+ CHARSWITHOUTACCENT = cstCHARSWITHOUTACCENT
+End Property &apos; ScriptForge.SF_String.CHARSWITHOUTACCENT
+
+&apos;&apos;&apos; Symbolic constants for linebreaks
+REM -----------------------------------------------------------------------------
+Property Get sfCR() As Variant
+&apos;&apos;&apos; Carriage return
+ sfCR = Chr(13)
+End Property &apos; ScriptForge.SF_String.sfCR
+
+REM -----------------------------------------------------------------------------
+Property Get sfCRLF() As Variant
+&apos;&apos;&apos; Carriage return
+ sfCRLF = Chr(13) &amp; Chr(10)
+End Property &apos; ScriptForge.SF_String.sfCRLF
+
+REM -----------------------------------------------------------------------------
+Property Get sfLF() As Variant
+&apos;&apos;&apos; Linefeed
+ sfLF = Chr(10)
+End Property &apos; ScriptForge.SF_String.sfLF
+
+REM -----------------------------------------------------------------------------
+Property Get sfNEWLINE() As Variant
+&apos;&apos;&apos; Linefeed or Carriage return + Linefeed
+ sfNEWLINE = Iif(GetGuiType() = 1, Chr(13), &quot;&quot;) &amp; Chr(10)
+End Property &apos; ScriptForge.SF_String.sfNEWLINE
+
+REM -----------------------------------------------------------------------------
+Property Get sfTAB() As Variant
+&apos;&apos;&apos; Horizontal tabulation
+ sfTAB = Chr(9)
+End Property &apos; ScriptForge.SF_String.sfTAB
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_String&quot;
+End Property &apos; ScriptForge.SF_String.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.String&quot;
+End Property &apos; ScriptForge.SF_String.ServiceName
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Capitalize(Optional ByRef InputStr As Variant) As String
+&apos;&apos;&apos; Return the input string with the 1st character of each word in title case
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string with the 1st character of each word in title case
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Capitalize(&quot;this is a title for jean-pierre&quot;) returns &quot;This Is A Title For Jean-Pierre&quot;
+
+Dim sCapital As String &apos; Return value
+Dim lLength As Long &apos; Length of input string
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
+Const cstThisSub = &quot;String.Capitalize&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sCapital = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ If lLength &gt; 0 Then
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+ Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ sCapital = oChar.toTitle(InputStr, 0, lLength * 4, oLocale) &apos; length * 4 because length is expressed in bytes
+ End If
+
+Finally:
+ Capitalize = sCapital
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Capitalize
+
+REM -----------------------------------------------------------------------------
+Public Function Count(Optional ByRef InputStr As Variant _
+ , Optional ByVal Substring As Variant _
+ , Optional ByRef IsRegex As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Long
+&apos;&apos;&apos; Counts the number of occurrences of a substring or a regular expression within a string
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input stringto examine
+&apos;&apos;&apos; Substring: the substring to identify
+&apos;&apos;&apos; IsRegex: True if Substring is a regular expression (default = False)
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The number of occurrences as a Long
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Count(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;\b[a-z]+\b&quot;, IsRegex := True, CaseSensitive := True)
+&apos;&apos;&apos; returns 7 (the number of words in lower case)
+&apos;&apos;&apos; SF_String.Count(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;or&quot;, CaseSensitive := False)
+&apos;&apos;&apos; returns 2
+
+
+Dim lOccurrences As Long &apos; Return value
+Dim lStart As Long &apos; Start index of search
+Dim sSubstring As String &apos; Substring to replace
+Dim iCaseSensitive As Integer &apos; Integer alias for boolean CaseSensitive
+Const cstThisSub = &quot;String.Count&quot;
+Const cstSubArgs = &quot;InputStr, Substring, [IsRegex=False], [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ lOccurrences = 0
+
+Check:
+ If IsMissing(IsRegex) Or IsEmpty(IsRegex) Then IsRegex = False
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Substring, &quot;Substring&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(IsRegex, &quot;IsRegex&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ iCaseSensitive = Iif(CaseSensitive, 0, 1) &apos; 1 = False ;)
+ lStart = 1
+
+ Do While lStart &gt;= 1 And lStart &lt;= Len(InputStr)
+ Select Case IsRegex
+ Case False &apos; Use InStr
+ lStart = InStr(lStart, InputStr, Substring, iCaseSensitive)
+ If lStart = 0 Then Exit Do
+ lStart = lStart + Len(Substring)
+ Case True &apos; Use FindRegex
+ sSubstring = SF_String.FindRegex(InputStr, Substring, lStart, CaseSensitive)
+ If lStart = 0 Then Exit Do
+ lStart = lStart + Len(sSubstring)
+ End Select
+ lOccurrences = lOccurrences + 1
+ Loop
+
+Finally:
+ Count = lOccurrences
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Count
+
+REM -----------------------------------------------------------------------------
+Public Function EndsWith(Optional ByRef InputStr As Variant _
+ , Optional ByVal Substring As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the last characters of InputStr are identical to Substring
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Substring: the suffixing characters
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the comparison is satisfactory
+&apos;&apos;&apos; False if either InputStr or Substring have a length = 0
+&apos;&apos;&apos; False if Substr is longer than InputStr
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.EndsWith(&quot;abcdefg&quot;, &quot;EFG&quot;) returns True
+&apos;&apos;&apos; SF_String.EndsWith(&quot;abcdefg&quot;, &quot;EFG&quot;, CaseSensitive := True) returns False
+
+Dim bEndsWith As Boolean &apos; Return value
+Dim lSub As Long &apos; Length of SUbstring
+Const cstThisSub = &quot;String.EndsWith&quot;
+Const cstSubArgs = &quot;InputStr, Substring, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bEndsWith = False
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Substring, &quot;Substring&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lSub = Len(Substring)
+ If Len(InputStr) &gt; 0 And lSub &gt; 0 And lSub &lt;= Len(InputStr) Then
+ bEndsWith = ( StrComp(Right(InputStr, lSub), Substring, Iif(CaseSensitive, 1, 0)) = 0 )
+ End If
+
+Finally:
+ EndsWith = bEndsWith
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.EndsWith
+
+REM -----------------------------------------------------------------------------
+Public Function Escape(Optional ByRef InputStr As Variant) As String
+&apos;&apos;&apos; Convert any hard line breaks or tabs by their escaped equivalent
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string after replacement of &quot;\&quot;, Chr(10), Chr(13), Chr(9)characters
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Escape(&quot;abc&quot; &amp; Chr(10) &amp; Chr(9) &amp; &quot;def\n&quot;) returns &quot;abc\n\tdef\\n&quot;
+
+Dim sEscape As String &apos; Return value
+Const cstThisSub = &quot;String.Escape&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sEscape = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ sEscape = SF_String.ReplaceStr( InputStr _
+ , Array(&quot;\&quot;, SF_String.sfLF, SF_String.sfCR, SF_String.sfTAB) _
+ , Array(&quot;\\&quot;, &quot;\n&quot;, &quot;\r&quot;, &quot;\t&quot;) _
+ )
+
+Finally:
+ Escape = sEscape
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Escape
+
+REM -----------------------------------------------------------------------------
+Public Function ExpandTabs(Optional ByRef InputStr As Variant _
+ , Optional ByVal TabSize As Variant _
+ ) As String
+&apos;&apos;&apos; Return the input string with each TAB (Chr(9)) character replaced by the adequate number of spaces
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; TabSize: defines the TAB positions at TabSize + 1, 2 * TabSize + 1 , ... N * TabSize + 1
+&apos;&apos;&apos; Default = 8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string with spaces replacing the TAB characters
+&apos;&apos;&apos; If the input string contains line breaks, the TAB positions are reset
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.ExpandTabs(&quot;abc&quot; &amp; SF_String.sfTAB &amp; SF_String.sfTAB &amp; &quot;def&quot;, 4) returns &quot;abc def&quot;
+&apos;&apos;&apos; SF_String.ExpandTabs(&quot;abc&quot; &amp; SF_String.sfTAB &amp; &quot;def&quot; &amp; SF_String.sfLF &amp; SF_String.sfTAB &amp; &quot;ghi&quot;)
+&apos;&apos;&apos; returns &quot;abc def&quot; &amp; SF_String.sfLF &amp; &quot; ghi&quot;
+
+Dim sExpanded As String &apos; Return value
+Dim lCharPosition As Long &apos; Position of current character in current line in expanded string
+Dim lSpaces As Long &apos; Spaces counter
+Dim sChar As String &apos; A single character
+Dim i As Long
+Const cstTabSize = 8
+Const cstThisSub = &quot;String.ExpandTabs&quot;
+Const cstSubArgs = &quot;InputStr, [TabSize=8]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sExpanded = &quot;&quot;
+
+Check:
+ If IsMissing(TabSize) Or IsEmpty(TabSize) Then TabSize = cstTabSize
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(TabSize, &quot;TabSize&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+ If TabSize &lt;= 0 Then TabSize = cstTabSize
+
+Try:
+ lCharPosition = 0
+ If Len(InputStr) &gt; 0 Then
+ For i = 1 To Len(InputStr)
+ sChar = Mid(InputStr, i, 1)
+ Select Case sChar
+ Case SF_String.sfLF, Chr(12), SF_String.sfCR, Chr(28), Chr(29), Chr(30), Chr(133), Chr(8232), Chr(8233)
+ sExpanded = sExpanded &amp; sChar
+ lCharPosition = 0
+ Case SF_String.sfTAB
+ lSpaces = Int(lCharPosition / TabSize + 1) * TabSize - lCharPosition
+ sExpanded = sExpanded &amp; Space(lSpaces)
+ lCharPosition = lCharPosition + lSpaces
+ Case Else
+ sExpanded = sExpanded &amp; sChar
+ lCharPosition = lCharPosition + 1
+ End Select
+ Next i
+ End If
+
+Finally:
+ ExpandTabs = sExpanded
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.ExpandTabs
+
+REM -----------------------------------------------------------------------------
+Public Function FilterNotPrintable(Optional ByRef InputStr As Variant _
+ , Optional ByVal ReplacedBy As Variant _
+ ) As String
+&apos;&apos;&apos; Return the input string in which all the not printable characters are replaced by ReplacedBy
+&apos;&apos;&apos; Among others, control characters (Ascii &lt;= 1F) are not printable
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; ReplacedBy: zero, one or more characters replacing the found not printable characters
+&apos;&apos;&apos; Default = the zero-length string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string in which all the not printable characters are replaced by ReplacedBy
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.FilterNotPrintable(&quot;àén ΣlPµ&quot; &amp; Chr(10) &amp; &quot; Русский&quot;, &quot;\n&quot;) returns &quot;àén ΣlPµ\n Русский&quot;
+
+Dim sPrintable As String &apos; Return value
+Dim bPrintable As Boolean &apos; Is a single character printable ?
+Dim lLength As Long &apos; Length of InputStr
+Dim lReplace As Long &apos; Length of ReplacedBy
+Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
+Dim sChar As String &apos; A single character
+Dim lPRINTABLE As Long : lPRINTABLE = com.sun.star.i18n.KCharacterType.PRINTABLE
+Dim i As Long
+Const cstThisSub = &quot;String.FilterNotPrintable&quot;
+Const cstSubArgs = &quot;InputStr, [ReplacedBy=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sPrintable = &quot;&quot;
+
+Check:
+ If IsMissing(ReplacedBy) Or IsEmpty(ReplacedBy) Then ReplacedBy = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(ReplacedBy, &quot;ReplacedBy&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ lReplace = Len(ReplacedBy)
+ If lLength &gt; 0 Then
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+ Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ For i = 0 To lLength - 1
+ sChar = Mid(InputStr, i + 1, 1)
+ lType = oChar.getCharacterType(sChar, 0, oLocale)
+ &apos; Parenthses (), [], {} have a KCharacterType = 0
+ bPrintable = ( (lType And lPRINTABLE) = lPRINTABLE Or (lType = 0 And Asc(sChar) &lt;= 127) )
+ If Not bPrintable Then
+ If lReplace &gt; 0 Then sPrintable = sPrintable &amp; ReplacedBy
+ Else
+ sPrintable = sPrintable &amp; sChar
+ End If
+ Next i
+ End If
+
+Finally:
+ FilterNotPrintable = sPrintable
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.FilterNotPrintable
+
+REM -----------------------------------------------------------------------------
+Public Function FindRegex(Optional ByRef InputStr As Variant _
+ , Optional ByVal Regex As Variant _
+ , Optional ByRef Start As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ , Optional ByVal Forward As Variant _
+ ) As String
+&apos;&apos;&apos; Find in InputStr a substring matching a given regular expression
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string to be searched for the expression
+&apos;&apos;&apos; Regex: the regular expression
+&apos;&apos;&apos; Start (passed by reference): where to start searching from
+&apos;&apos;&apos; Should be = 1 (Forward = True) or = Len(InputStr) (Forward = False) the 1st time
+&apos;&apos;&apos; After execution points to the first character of the found substring
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Forward: True (default) or False (backward)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The found substring matching the regular expression
+&apos;&apos;&apos; A zero-length string if not found (Start is set to 0)
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim lStart As Long : lStart = 1
+&apos;&apos;&apos; SF_String.FindRegex(&quot;abCcdefghHij&quot;, &quot;C.*H&quot;, lStart, CaseSensitive := True) returns &quot;CcdefghH&quot;
+&apos;&apos;&apos; Above statement may be reexecuted for searching the same or another pattern
+&apos;&apos;&apos; by starting from lStart + Len(matching string)
+
+Dim sOutput As String &apos; Return value
+Dim oTextSearch As Object &apos; com.sun.star.util.TextSearch
+Dim vOptions As Variant &apos; com.sun.star.util.SearchOptions
+Dim lEnd As Long &apos; Upper limit of search area
+Dim vResult As Object &apos; com.sun.star.util.SearchResult
+Const cstThisSub = &quot;String.FindRegex&quot;
+Const cstSubArgs = &quot;InputStr, Regex, [Start=1], [CaseSensitive=False], [Forward=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sOutput = &quot;&quot;
+
+Check:
+ If IsMissing(Start) Or IsEmpty(Start) Then Start = 1
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If IsMissing(Forward) Or IsEmpty(Forward) Then Forward = True
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Start, &quot;Start&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Forward, &quot;Forward&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+ If Start &lt;= 0 Or Start &gt; Len(InputStr) Then GoTo Finally
+
+Try:
+ sOutput = &quot;&quot;
+ Set oTextSearch = SF_Utils._GetUNOService(&quot;TextSearch&quot;)
+ &apos; Set pattern search options
+ vOptions = SF_Utils._GetUNOService(&quot;SearchOptions&quot;)
+ With vOptions
+ .searchString = Regex
+ If CaseSensitive Then .transliterateFlags = 0 Else .transliterateFlags = com.sun.star.i18n.TransliterationModules.IGNORE_CASE
+ End With
+ &apos; Run search
+ With oTextSearch
+ .setOptions(vOptions)
+ If Forward Then
+ lEnd = Len(InputStr)
+ vResult = .searchForward(InputStr, Start - 1, lEnd)
+ Else
+ lEnd = 1
+ vResult = .searchBackward(InputStr, Start, lEnd - 1)
+ End If
+ End With
+ &apos; https://api.libreoffice.org/docs/idl/ref/structcom_1_1sun_1_1star_1_1util_1_1SearchResult.html
+ With vResult
+ If .subRegExpressions &gt;= 1 Then
+ If Forward Then
+ Start = .startOffset(0) + 1
+ lEnd = .endOffset(0) + 1
+ Else
+ Start = .endOffset(0) + 1
+ lEnd = .startOffset(0) + 1
+ End If
+ sOutput = Mid(InputStr, Start, lEnd - Start)
+ Else
+ Start = 0
+ End If
+ End With
+
+Finally:
+ FindRegex = sOutput
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.FindRegex
+
+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;String.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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 &quot;SFCR&quot; : GetProperty = sfCR
+ Case &quot;SFCRLF&quot; : GetProperty = sfCRLF
+ Case &quot;SFLF&quot; : GetProperty = sfLF
+ Case &quot;SFNEWLINE&quot; : GetProperty = sfNEWLINE
+ Case &quot;SFTAB&quot; : GetProperty = sfTAB
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function HashStr(Optional ByVal InputStr As Variant _
+ , Optional ByVal Algorithm As Variant _
+ ) As String
+&apos;&apos;&apos; Return an hexadecimal string representing a checksum of the given input string
+&apos;&apos;&apos; Next algorithms are supported: MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the string to be hashed
+&apos;&apos;&apos; Algorithm: The hashing algorithm to use
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The requested checksum as a string. Hexadecimal digits are lower-cased
+&apos;&apos;&apos; A zero-length string when an error occurred
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Print SF_String.HashStr(&quot;œ∑¡™£¢∞§¶•ªº–≠œ∑´®†¥¨ˆøπ“‘åß∂ƒ©˙∆˚¬&quot;, &quot;MD5&quot;) &apos; 616eb9c513ad07cd02924b4d285b9987
+
+Dim sHash As String &apos; Return value
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_String__HashStr&quot;
+Const cstThisSub = &quot;String.HashStr&quot;
+Const cstSubArgs = &quot;InputStr, Algorithm=&quot;&quot;MD5&quot;&quot;|&quot;&quot;SHA1&quot;&quot;|&quot;&quot;SHA224&quot;&quot;|&quot;&quot;SHA256&quot;&quot;|&quot;&quot;SHA384&quot;&quot;|&quot;&quot;SHA512&quot;&quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sHash = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Algorithm, &quot;Algorithm&quot;, V_STRING _
+ , Array(&quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA224&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot;)) Then GoTo Finally
+ End If
+
+Try:
+ With ScriptForge.SF_Session
+ sHash = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , InputStr, LCase(Algorithm))
+ End With
+
+Finally:
+ HashStr = sHash
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.HashStr
+
+REM -----------------------------------------------------------------------------
+Public Function HtmlEncode(Optional ByRef InputStr As Variant) As String
+&apos;&apos;&apos; &amp;-encoding of the input string (e.g. &quot;é&quot; becomes &quot;&amp;eacute;&quot; or numeric equivalent
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the encoded string
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.HtmlEncode(&quot;&lt;a href=&quot;&quot;https://a.b.com&quot;&quot;&gt;From α to ω&lt;/a&gt;&quot;)
+&apos;&apos;&apos; returns &quot;&amp;lt;a href=&amp;quot;https://a.b.com&amp;quot;&amp;gt;From &amp;#945; to &amp;#969;&amp;lt;/a&amp;gt;&quot;
+
+Dim sEncode As String &apos; Return value
+Dim lPos As Long &apos; Position in InputStr
+Dim sChar As String &apos; A single character extracted from InputStr
+Dim i As Long
+Const cstThisSub = &quot;String.HtmlEncode&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sEncode = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then
+ lPos = 1
+ sEncode = InputStr
+ Do While lPos &lt;= Len(sEncode)
+ sChar = Mid(sEncode, lPos, 1)
+ &apos; Leave as is or encode every single char
+ Select Case sChar
+ Case &quot;&quot;&quot;&quot; : sChar = &quot;&amp;quot;&quot;
+ Case &quot;&amp;&quot; : sChar = &quot;&amp;amp;&quot;
+ Case &quot;&lt;&quot; : sChar = &quot;&amp;lt;&quot;
+ Case &quot;&gt;&quot; : sChar = &quot;&amp;gt;&quot;
+ Case &quot;&apos;&quot; : sChar = &quot;&amp;apos;&quot;
+ Case &quot;:&quot;, &quot;/&quot;, &quot;?&quot;, &quot;#&quot;, &quot;[&quot;, &quot;]&quot;, &quot;@&quot; &apos; Reserved characters
+ Case SF_String.sfCR : sChar = &quot;&quot; &apos; Carriage return
+ Case SF_String.sfLF : sChar = &quot;&lt;br&gt;&quot; &apos; Line Feed
+ Case &lt; Chr(126)
+ Case &quot;€&quot; : sChar = &quot;&amp;euro;&quot;
+ Case Else : sChar = &quot;&amp;#&quot; &amp; Asc(sChar) &amp; &quot;;&quot;
+ End Select
+ If Len(sChar) = 1 Then
+ Mid(sEncode, lPos, 1) = sChar
+ Else
+ sEncode = Left(sEncode, lPos - 1) &amp; sChar &amp; Mid(sEncode, lPos + 1)
+ End If
+ lPos = lPos + Len(sChar)
+ Loop
+ End If
+
+Finally:
+ HtmlEncode = sEncode
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.HtmlEncode
+
+REM -----------------------------------------------------------------------------
+Public Function IsADate(Optional ByRef InputStr As Variant _
+ , Optional ByVal DateFormat _
+ ) As Boolean
+&apos;&apos;&apos; Return True if the string is a valid date respecting the given format
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; DateFormat: either YYYY-MM-DD (default), DD-MM-YYYY or MM-DD-YYYY
+&apos;&apos;&apos; The dash (-) may be replaced by a dot (.), a slash (/) or a space
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains a valid date and there is at least one character
+&apos;&apos;&apos; False otherwise or if the date format is invalid
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsADate(&quot;2019-12-31&quot;, &quot;YYYY-MM-DD&quot;) returns True
+
+Dim bADate As Boolean &apos; Return value
+Dim sFormat As String &apos; Alias for DateFormat
+Dim iYear As Integer &apos; Alias of year in input string
+Dim iMonth As Integer &apos; Alias of month in input string
+Dim iDay As Integer &apos; Alias of day in input string
+Dim dDate As Date &apos; Date value
+Const cstFormat = &quot;YYYY-MM-DD&quot; &apos; Default date format
+Const cstFormatRegex = &quot;(YYYY[- /.]MM[- /.]DD|MM[- /.]DD[- /.]YYYY|DD[- /.]MM[- /.]YYYY)&quot;
+ &apos; The regular expression the format must match
+Const cstThisSub = &quot;String.IsADate&quot;
+Const cstSubArgs = &quot;InputStr, [DateFormat=&quot;&quot;&quot; &amp; cstFormat &amp; &quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bADate = False
+
+Check:
+ If IsMissing(DateFormat) Or IsEmpty(DateFormat) Then DateFormat = &quot;YYYY-MM-DD&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(DateFormat, &quot;DateFormat&quot;, V_STRING) Then GoTo Finally
+ End If
+ sFormat = UCase(DateFormat)
+ If Len(sFormat) &lt;&gt; Len(cstFormat)Then GoTo Finally
+ If sFormat &lt;&gt; cstFormat Then &apos; Do not check if default format
+ If Not SF_String.IsRegex(sFormat, cstFormatRegex) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) = Len(DateFormat) Then
+ &apos; Extract the date components YYYY, MM, DD from the input string
+ iYear = CInt(Mid(InputStr, InStr(sFormat, &quot;YYYY&quot;), 4))
+ iMonth = CInt(Mid(InputStr, InStr(sFormat, &quot;MM&quot;), 2))
+ iDay = CInt(Mid(InputStr, InStr(sFormat, &quot;DD&quot;), 2))
+ &apos; Check the validity of the date
+ On Local Error GoTo NotADate
+ dDate = DateSerial(iYear, iMonth, iDay)
+ bADate = True &apos; Statement reached only if no error
+ End If
+
+Finally:
+ IsADate = bADate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+NotADate:
+ On Error GoTo 0 &apos; Reset the error object
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsADate
+
+REM -----------------------------------------------------------------------------
+Public Function IsAlpha(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are alphabetic
+&apos;&apos;&apos; Alphabetic characters are those characters defined in the Unicode character database as “Letter”
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string is alphabetic and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsAlpha(&quot;àénΣlPµ&quot;) returns True
+&apos;&apos;&apos; Note:
+&apos;&apos;&apos; Use SF_String.IsRegex(&quot;...&quot;, REGEXALPHA) to limit characters to latin alphabet
+
+Dim bAlpha As Boolean &apos; Return value
+Dim lLength As Long &apos; Length of InputStr
+Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
+Dim lLETTER As Long : lLETTER = com.sun.star.i18n.KCharacterType.LETTER
+Dim i As Long
+Const cstThisSub = &quot;String.IsAlpha&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bAlpha = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ If lLength &gt; 0 Then
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+ Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ For i = 0 To lLength - 1
+ lType = oChar.getCharacterType(InputStr, i, oLocale)
+ bAlpha = ( (lType And lLETTER) = lLETTER )
+ If Not bAlpha Then Exit For
+ Next i
+ End If
+
+Finally:
+ IsAlpha = bAlpha
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsAlpha
+
+REM -----------------------------------------------------------------------------
+Public Function IsAlphaNum(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are alphabetic, digits or &quot;_&quot; (underscore)
+&apos;&apos;&apos; The first character must not be a digit
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string is alphanumeric and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsAlphaNum(&quot;_ABC_123456_abcàénΣlPµ&quot;) returns True
+
+Dim bAlphaNum As Boolean &apos; Return value
+Dim sInputStr As String &apos; Alias of InputStr without underscores
+Dim sFirst As String &apos; Leftmost character of InputStr
+Dim lLength As Long &apos; Length of InputStr
+Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
+Dim lLETTER As Long : lLETTER = com.sun.star.i18n.KCharacterType.LETTER
+Dim lDIGIT As Long : lDIGIT = com.sun.star.i18n.KCharacterType.DIGIT
+Dim i As Long
+Const cstThisSub = &quot;String.IsAlphaNum&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bAlphaNum = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ If lLength &gt; 0 Then
+ sFirst = Left(InputStr, 1)
+ bAlphanum = ( sFirst &lt; &quot;0&quot; Or sFirst &gt; &quot;9&quot; )
+ If bAlphaNum Then
+ sInputStr = Replace(InputStr, &quot;_&quot;, &quot;A&quot;) &apos; Replace by an arbitrary alphabetic character
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+ Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ For i = 0 To lLength - 1
+ lType = oChar.getCharacterType(sInputStr, i, oLocale)
+ bAlphaNum = ( (lType And lLETTER) = lLETTER _
+ Or (lType And lDIGIT) = lDIGIT )
+ If Not bAlphaNum Then Exit For
+ Next i
+ End If
+ End If
+
+Finally:
+ IsAlphaNum = bAlphaNum
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsAlphaNum
+
+REM -----------------------------------------------------------------------------
+Public Function IsAscii(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are Ascii characters
+&apos;&apos;&apos; Ascii characters are those characters defined between &amp;H00 and &amp;H7F
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string is Ascii and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsAscii(&quot;a%?,25&quot;) returns True
+
+Dim bAscii As Boolean &apos; Return value
+Dim lLength As Long &apos; Length of InputStr
+Dim sChar As String &apos; Single character
+Dim i As Long
+Const cstThisSub = &quot;String.IsAscii&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bAscii = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ If lLength &gt; 0 Then
+ For i = 1 To lLength
+ sChar = Mid(InputStr, i, 1)
+ bAscii = ( Asc(sChar) &lt;= 127 )
+ If Not bAscii Then Exit For
+ Next i
+ End If
+
+Finally:
+ IsAscii = bAscii
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsAscii
+
+REM -----------------------------------------------------------------------------
+Public Function IsDigit(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are digits
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains only digits and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsDigit(&quot;123456&quot;) returns True
+
+Dim bDigit As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsDigit&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bDigit = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bDigit = SF_String.IsRegex(InputStr, REGEXDIGITS, CaseSensitive := False)
+
+Finally:
+ IsDigit = bDigit
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsDigit
+
+REM -----------------------------------------------------------------------------
+Public Function IsEmail(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if the string is a valid email address
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains an email address and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsEmail(&quot;first.last@something.org&quot;) returns True
+
+Dim bEmail As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsEmail&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bEmail = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bEmail = SF_String.IsRegex(InputStr, REGEXEMAIL, CaseSensitive := False)
+
+Finally:
+ IsEmail = bEmail
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsEmail
+
+REM -----------------------------------------------------------------------------
+Public Function IsFileName(Optional ByRef InputStr As Variant _
+ , Optional ByVal OSName As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Return True if the string is a valid filename in a given operating system
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; OSName: Windows, Linux, macOS or Solaris
+&apos;&apos;&apos; The default is the current operating system on which the script is run
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains a valid filename and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsFileName(&quot;/home/a file name.odt&quot;, &quot;LINUX&quot;) returns True
+
+Dim bFileName As Boolean &apos; Return value
+Dim sRegex As String &apos; Regex to apply depending on OS
+Const cstThisSub = &quot;String.IsFileName&quot;
+Const cstSubArgs = &quot;InputStr, [OSName=&quot;&quot;Windows&quot;&quot;|&quot;&quot;Linux&quot;&quot;|&quot;&quot;macOS&quot;&quot;|Solaris&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bFileName = False
+
+Check:
+ If IsMissing(OSName) Or IsEmpty(OSName) Then
+ If _SF_.OSname = &quot;&quot; Then _SF_.OSName = SF_Platform.OSName
+ OSName = _SF_.OSName
+ End If
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(OSName, &quot;OSName&quot;, V_STRING, Array(&quot;Windows&quot;, &quot;Linux&quot;, &quot;macOS&quot;, &quot;Solaris&quot;)) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then
+ Select Case UCase(OSName)
+ Case &quot;LINUX&quot;, &quot;MACOS&quot;, &quot;SOLARIS&quot; : sRegex = REGEXFILELINUX
+ Case &quot;WINDOWS&quot; : sRegex = REGEXFILEWIN
+ End Select
+ bFileName = SF_String.IsRegex(InputStr, sRegex, CaseSensitive := False)
+ End If
+
+Finally:
+ IsFileName = bFileName
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsFileName
+
+REM -----------------------------------------------------------------------------
+Public Function IsHexDigit(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are hexadecimal digits
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains only hexadecimal igits and there is at least one character
+&apos;&apos;&apos; The prefixes &quot;0x&quot; and &quot;&amp;H&quot; are admitted
+&apos;&apos;&apos; False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsHexDigit(&quot;&amp;H00FF&quot;) returns True
+
+Dim bHexDigit As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsHexDigit&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bHexDigit = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bHexDigit = SF_String.IsRegex(InputStr, REGEXHEXA, CaseSensitive := False)
+
+Finally:
+ IsHexDigit = bHexDigit
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsHexDigit
+
+REM -----------------------------------------------------------------------------
+Public Function IsIBAN(Optional ByVal InputStr As Variant) As Boolean
+&apos;&apos;&apos; Returns True if the input string is a valid International Bank Account Number
+&apos;&apos;&apos; Read https://en.wikipedia.org/wiki/International_Bank_Account_Number
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains a valid IBAN number. The comparison is not case-sensitive
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsIBAN(&quot;BR15 0000 0000 0000 1093 2840 814 P2&quot;) returns True
+
+Dim bIBAN As Boolean &apos; Return value
+Dim sIBAN As String &apos; Transformed input string
+Dim sChar As String &apos; A single character
+Dim sLetter As String &apos; Integer representation of letters
+Dim iIndex As Integer &apos; Index in IBAN string
+Dim sLong As String &apos; String representation of a Long
+Dim iModulo97 As Integer &apos; Remainder of division by 97
+Dim i As Integer
+Const cstThisSub = &quot;String.IsIBAN&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bIBAN = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ sIBAN = &quot;&quot;
+ &apos; 1. Remove spaces. Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid
+ &apos; NOT DONE: Country specific
+ sIBAN = Replace(InputStr, &quot; &quot;, &quot;&quot;)
+ If Len(sIBAN) &lt; 5 Or Len(sIBAN) &gt; 34 Then GoTo Finally
+
+ &apos; 2. Move the four initial characters to the end of the string. String is case-insensitive
+ sIBAN = UCase(Mid(sIBAN, 5) &amp; Left(sIBAN, 4))
+
+ &apos; 3. Replace each letter in the string with two digits, thereby expanding the string, where A = 10, B = 11, ..., Z = 35
+ iIndex = 1
+ Do While iIndex &lt; Len(sIBAN)
+ sChar = Mid(sIBAN, iIndex, 1)
+ If sChar &gt;= &quot;A&quot; And sChar &lt;= &quot;Z&quot; Then
+ sLetter = CStr(Asc(sChar) - Asc(&quot;A&quot;) + 10)
+ sIBAN = Left(sIBAN, iIndex - 1) &amp; sLetter &amp; Mid(sIBAN, iIndex + 1)
+ iIndex = iIndex + 2
+ ElseIf sChar &lt; &quot;0&quot; Or sChar &gt; &quot;9&quot; Then &apos; Remove any non-alphanumeric character
+ GoTo Finally
+ Else
+ iIndex = iIndex + 1
+ End If
+ Loop
+
+ &apos; 4. Interpret the string as a decimal integer and compute the remainder of that number on division by 97
+ &apos; Computation is done in chunks of 9 digits
+ iIndex = 3
+ sLong = Left(sIBAN, 2)
+ Do While iIndex &lt;= Len(sIBAN)
+ sLong = sLong &amp; Mid(sIBAN, iIndex, 7)
+ iModulo97 = CLng(sLong) Mod 97
+ iIndex = iIndex + Len(sLong) - 2
+ sLong = Right(&quot;0&quot; &amp; CStr(iModulo97), 2) &apos; Force leading zero
+ Loop
+
+ bIBAN = ( iModulo97 = 1 )
+
+Finally:
+ IsIBAN = bIBAN
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsIBAN
+
+REM -----------------------------------------------------------------------------
+Public Function IsIPv4(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if the string is a valid IPv4 address
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains a valid IPv4 address and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsIPv4(&quot;192.168.1.50&quot;) returns True
+
+Dim bIPv4 As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsIPv4&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bIPv4 = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bIPv4 = SF_String.IsRegex(InputStr, REGEXIPV4, CaseSensitive := False)
+
+Finally:
+ IsIPv4 = bIPv4
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsIPv4
+
+REM -----------------------------------------------------------------------------
+Public Function IsLike(Optional ByRef InputStr As Variant _
+ , Optional ByVal Pattern As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the whole input string matches a given pattern containing wildcards
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Pattern: the pattern as a string
+&apos;&apos;&apos; Admitted wildcard are: the &quot;?&quot; represents any single character
+&apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if a match is found
+&apos;&apos;&apos; Zero-length input or pattern strings always return False
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsLike(&quot;aAbB&quot;, &quot;?A*&quot;) returns True
+&apos;&apos;&apos; SF_String.IsLike(&quot;C:\a\b\c\f.odb&quot;, &quot;?:*.*&quot;) returns True
+
+Dim bLike As Boolean &apos; Return value
+&apos; Build an equivalent regular expression by escaping the special characters present in Pattern
+Dim sRegex As String &apos; Equivalent regular expression
+Const cstSpecialChars = &quot;\,^,$,.,|,+,(,),[,{,?,*&quot; &apos; List of special chars in regular expressions
+Const cstEscapedChars = &quot;\\,\^,\$,\.,\|,\+,\(,\),\[,\{,.,.*&quot;
+
+Const cstThisSub = &quot;String.IsLike&quot;
+Const cstSubArgs = &quot;InputStr, Pattern, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bLike = False
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Pattern, &quot;Pattern&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 And Len(Pattern) &gt; 0 Then
+ &apos; Substitute special chars by escaped chars
+ sRegex = SF_String.ReplaceStr(Pattern, Split(cstSPecialChars, &quot;,&quot;), Split(cstEscapedChars, &quot;,&quot;))
+ bLike = SF_String.IsRegex(InputStr, sRegex, CaseSensitive)
+ End If
+
+Finally:
+ IsLike = bLike
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsLike
+
+REM -----------------------------------------------------------------------------
+Public Function IsLower(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are in lower case
+&apos;&apos;&apos; Non alphabetic characters are ignored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains only lower case characters and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsLower(&quot;abc&apos;(-xyz&quot;) returns True
+
+Dim bLower As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsLower&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bLower = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bLower = ( StrComp(InputStr, LCase(InputStr), 1) = 0 )
+
+Finally:
+ IsLower = bLower
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsLower
+
+REM -----------------------------------------------------------------------------
+Public Function IsPrintable(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are printable
+&apos;&apos;&apos; In particular, control characters (Ascii &lt;= 1F) are not printable
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string is printable and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsPrintable(&quot;àén ΣlPµ Русский&quot;) returns True
+
+Dim bPrintable As Boolean &apos; Return value
+Dim lLength As Long &apos; Length of InputStr
+Dim oChar As Object &apos; com.sun.star.i18n.CharacterClassification
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim lType As Long &apos; com.sun.star.i18n.KCharacterType
+Dim sChar As String &apos; A single character
+Dim lPRINTABLE As Long : lPRINTABLE = com.sun.star.i18n.KCharacterType.PRINTABLE
+Dim i As Long
+Const cstThisSub = &quot;String.IsPrintable&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrintable = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ If lLength &gt; 0 Then
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+ Set oChar = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ For i = 0 To lLength - 1
+ sChar = Mid(InputStr, i + 1, 1)
+ lType = oChar.getCharacterType(sChar, 0, oLocale)
+ &apos; Parenthses (), [], {} have a KCharacterType = 0
+ bPrintable = ( (lType And lPRINTABLE) = lPRINTABLE Or (lType = 0 And Asc(sChar) &lt;= 127) )
+ If Not bPrintable Then Exit For
+ Next i
+ End If
+
+Finally:
+ IsPrintable = bPrintable
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsPrintable
+
+REM -----------------------------------------------------------------------------
+Public Function IsRegex(Optional ByRef InputStr As Variant _
+ , Optional ByVal Regex As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the whole input string matches a given regular expression
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Regex: the regular expression as a string
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if a match is found
+&apos;&apos;&apos; Zero-length input or regex strings always return False
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsRegex(&quot;aAbB&quot;, &quot;[A-Za-z]+&quot;) returns True
+
+Dim bRegex As Boolean &apos; Return value
+Dim lStart As Long &apos; Must be 1
+Dim sMatch As String &apos; Matching string
+Const cstBegin = &quot;^&quot; &apos; Beginning of line symbol
+Const cstEnd = &quot;$&quot; &apos; End of line symbol
+Const cstThisSub = &quot;String.IsRegex&quot;
+Const cstSubArgs = &quot;InputStr, Regex, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRegex = False
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 And Len(Regex) &gt; 0 Then
+ &apos; Whole string must match Regex
+ lStart = 1
+ If Left(Regex, 1) &lt;&gt; cstBegin Then Regex = cstBegin &amp; Regex
+ If Right(Regex, 1) &lt;&gt; cstEnd Then Regex = Regex &amp; cstEnd
+ sMatch = SF_String.FindRegex(InputStr, Regex, lStart, CaseSensitive)
+ &apos; Match ?
+ bRegex = ( lStart = 1 And Len(sMatch) = Len(InputStr) )
+ End If
+
+Finally:
+ IsRegex = bRegex
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsRegex
+
+REM -----------------------------------------------------------------------------
+Public Function IsSheetName(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if the input string can serve as a valid Calc sheet name
+&apos;&apos;&apos; The sheet name must not contain the characters [ ] * ? : / \
+&apos;&apos;&apos; or the character &apos; (apostrophe) as first or last character.
+
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string is validated as a potential Calc sheet name, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsSheetName(&quot;1àbc + &quot;&quot;def&quot;&quot;&quot;) returns True
+
+Dim bSheetName As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsSheetName&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSheetName = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then
+ If Left(InputStr, 1) = &quot;&apos;&quot; Or Right(InputStr, 1) = &quot;&apos;&quot; Then
+ ElseIf InStr(InputStr, &quot;[&quot;) _
+ + InStr(InputStr, &quot;]&quot;) _
+ + InStr(InputStr, &quot;*&quot;) _
+ + InStr(InputStr, &quot;?&quot;) _
+ + InStr(InputStr, &quot;:&quot;) _
+ + InStr(InputStr, &quot;/&quot;) _
+ + InStr(InputStr, &quot;\&quot;) _
+ = 0 Then
+ bSheetName = True
+ End If
+ End If
+
+Finally:
+ IsSheetName = bSheetName
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsSheetName
+
+REM -----------------------------------------------------------------------------
+Public Function IsTitle(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if the 1st character of every word is in upper case and the other characters are in lower case
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string is capitalized and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsTitle(&quot;This Is A Title For Jean-Pierre&quot;) returns True
+
+Dim bTitle As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsTitle&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bTitle = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bTitle = ( StrComp(InputStr, SF_String.Capitalize(InputStr), 1) = 0 )
+
+Finally:
+ IsTitle = bTitle
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsTitle
+
+REM -----------------------------------------------------------------------------
+Public Function IsUpper(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are in upper case
+&apos;&apos;&apos; Non alphabetic characters are ignored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains only upper case characters and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsUpper(&quot;ABC&apos;(-XYZ&quot;) returns True
+
+Dim bUpper As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsUpper&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bUpper = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bUpper = ( StrComp(InputStr, UCase(InputStr), 1) = 0 )
+
+Finally:
+ IsUpper = bUpper
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsUpper
+
+REM -----------------------------------------------------------------------------
+Public Function IsUrl(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if the string is a valid absolute URL (Uniform Resource Locator)
+&apos;&apos;&apos; The parsing is done by the ParseStrict method of the URLTransformer UNO service
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XURLTransformer.html
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains a URL and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsUrl(&quot;http://foo.bar/?q=Test%20URL-encoded%20stuff&quot;) returns True
+
+Dim bUrl As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsUrl&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bUrl = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bUrl = ( Len(SF_FileSystem._ParseUrl(InputStr).Main) &gt; 0 )
+
+Finally:
+ IsUrl = bUrl
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsUrl
+
+REM -----------------------------------------------------------------------------
+Public Function IsWhitespace(Optional ByRef InputStr As Variant) As Boolean
+&apos;&apos;&apos; Return True if all characters in the string are whitespaces
+&apos;&apos;&apos; Whitespaces include Space(32), HT(9), LF(10), VT(11), FF(12), CR(13), Next Line(133), No-break space(160),
+&apos;&apos;&apos; Line separator(8232), Paragraph separator(8233)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the string contains only whitespaces and there is at least one character, False otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.IsWhitespace(&quot; &quot; &amp; Chr(9) &amp; Chr(10)) returns True
+
+Dim bWhitespace As Boolean &apos; Return value
+Const cstThisSub = &quot;String.IsWhitespace&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bWhitespace = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then bWhitespace = SF_String.IsRegex(InputStr, REGEXWHITESPACES, CaseSensitive := False)
+
+Finally:
+ IsWhitespace = bWhitespace
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.IsWhitespace
+
+REM -----------------------------------------------------------------------------
+Public Function JustifyCenter(Optional ByRef InputStr As Variant _
+ , Optional ByVal Length As Variant _
+ , Optional ByVal Padding As Variant _
+ ) As String
+&apos;&apos;&apos; Return the input string center justified
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Length: the resulting string length (default = length of input string)
+&apos;&apos;&apos; Padding: the padding (single) character (default = the ascii space)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string without its leading and trailing white spaces
+&apos;&apos;&apos; completed left and right up to a total length of Length with the character Padding
+&apos;&apos;&apos; If the input string is empty, the returned string is empty too
+&apos;&apos;&apos; If the requested length is shorter than the center justified input string,
+&apos;&apos;&apos; then the returned string is truncated
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.JustifyCenter(&quot; ABCDE &quot;, Padding := &quot;x&quot;) returns &quot;xxABCDEFxx&quot;
+
+Dim sJustify As String &apos; Return value
+Dim lLength As Long &apos; Length of input string
+Dim lJustLength As Long &apos; Length of trimmed input string
+Dim sPadding As String &apos; Series of Padding characters
+Const cstThisSub = &quot;String.JustifyCenter&quot;
+Const cstSubArgs = &quot;InputStr, [length=Len(InputStr)], [Padding=&quot;&quot; &quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sJustify = &quot;&quot;
+
+Check:
+ If IsMissing(Length) Or IsEmpty(Length) Then Length = 0
+ If IsMissing(Padding) Or IsMissing(Padding) Then Padding = &quot; &quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Length, &quot;Length&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(Padding, &quot;Padding&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(Padding) = 0 Then Padding = &quot; &quot; Else Padding = Left(Padding, 1)
+
+Try:
+ lLength = Len(InputStr)
+ If Length = 0 Then Length = lLength
+ If lLength &gt; 0 Then
+ sJustify = SF_String.TrimExt(InputStr) &apos; Trim left and right
+ lJustLength = Len(sJustify)
+ If lJustLength &gt; Length Then
+ sJustify = Mid(sJustify, Int((lJustLength - Length) / 2) + 1, Length)
+ ElseIf lJustLength &lt; Length Then
+ sPadding = String(Int((Length - lJustLength) / 2), Padding)
+ sJustify = sPadding &amp; sJustify &amp; sPadding
+ If Len(sJustify) &lt; Length Then sJustify = sJustify &amp; Padding &apos; One Padding char is lacking when lJustLength is odd
+ End If
+ End If
+
+Finally:
+ JustifyCenter = sJustify
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.JustifyCenter
+
+REM -----------------------------------------------------------------------------
+Public Function JustifyLeft(Optional ByRef InputStr As Variant _
+ , Optional ByVal Length As Variant _
+ , Optional ByVal Padding As Variant _
+ ) As String
+&apos;&apos;&apos; Return the input string left justified
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Length: the resulting string length (default = length of input string)
+&apos;&apos;&apos; Padding: the padding (single) character (default = the ascii space)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string without its leading white spaces
+&apos;&apos;&apos; filled up to a total length of Length with the character Padding
+&apos;&apos;&apos; If the input string is empty, the returned string is empty too
+&apos;&apos;&apos; If the requested length is shorter than the left justified input string,
+&apos;&apos;&apos; then the returned string is truncated
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.JustifyLeft(&quot; ABCDE &quot;, Padding := &quot;x&quot;) returns &quot;ABCDE xxx&quot;
+
+Dim sJustify As String &apos; Return value
+Dim lLength As Long &apos; Length of input string
+Const cstThisSub = &quot;String.JustifyLeft&quot;
+Const cstSubArgs = &quot;InputStr, [length=Len(InputStr)], [Padding=&quot;&quot; &quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sJustify = &quot;&quot;
+
+Check:
+ If IsMissing(Length) Or IsEmpty(Length) Then Length = 0
+ If IsMissing(Padding) Or IsMissing(Padding) Then Padding = &quot; &quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Length, &quot;Length&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(Padding, &quot;Padding&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(Padding) = 0 Then Padding = &quot; &quot; Else Padding = Left(Padding, 1)
+
+Try:
+ lLength = Len(InputStr)
+ If Length = 0 Then Length = lLength
+ If lLength &gt; 0 Then
+ sJustify = SF_String.ReplaceRegex(InputStr, REGEXLTRIM, &quot;&quot;) &apos; Trim left
+ If Len(sJustify) &gt;= Length Then
+ sJustify = Left(sJustify, Length)
+ Else
+ sJustify = sJustify &amp; String(Length - Len(sJustify), Padding)
+ End If
+ End If
+
+Finally:
+ JustifyLeft = sJustify
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.JustifyLeft
+
+REM -----------------------------------------------------------------------------
+Public Function JustifyRight(Optional ByRef InputStr As Variant _
+ , Optional ByVal Length As Variant _
+ , Optional ByVal Padding As Variant _
+ ) As String
+&apos;&apos;&apos; Return the input string right justified
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Length: the resulting string length (default = length of input string)
+&apos;&apos;&apos; Padding: the padding (single) character (default = the ascii space)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string without its trailing white spaces
+&apos;&apos;&apos; preceded up to a total length of Length with the character Padding
+&apos;&apos;&apos; If the input string is empty, the returned string is empty too
+&apos;&apos;&apos; If the requested length is shorter than the right justified input string,
+&apos;&apos;&apos; then the returned string is right-truncated
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.JustifyRight(&quot; ABCDE &quot;, Padding := &quot;x&quot;) returns &quot;x ABCDE&quot;
+
+Dim sJustify As String &apos; Return value
+Dim lLength As Long &apos; Length of input string
+Const cstThisSub = &quot;String.JustifyRight&quot;
+Const cstSubArgs = &quot;InputStr, [length=Len(InputStr)], [Padding=&quot;&quot; &quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sJustify = &quot;&quot;
+
+Check:
+ If IsMissing(Length) Or IsEmpty(Length) Then Length = 0
+ If IsMissing(Padding) Or IsMissing(Padding) Then Padding = &quot; &quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Length, &quot;Length&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(Padding, &quot;Padding&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Len(Padding) = 0 Then Padding = &quot; &quot; Else Padding = Left(Padding, 1)
+
+Try:
+ lLength = Len(InputStr)
+ If Length = 0 Then Length = lLength
+ If lLength &gt; 0 Then
+ sJustify = SF_String.ReplaceRegex(InputStr, REGEXRTRIM, &quot;&quot;) &apos; Trim right
+ If Len(sJustify) &gt;= Length Then
+ sJustify = Right(sJustify, Length)
+ Else
+ sJustify = String(Length - Len(sJustify), Padding) &amp; sJustify
+ End If
+ End If
+
+Finally:
+ JustifyRight = sJustify
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.JustifyRight
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the String service as an array
+
+ Methods = Array( _
+ &quot;Capitalize&quot; _
+ , &quot;Count&quot; _
+ , &quot;EndWith&quot; _
+ , &quot;Escape&quot; _
+ , &quot;ExpandTabs&quot; _
+ , &quot;FilterNotPrintable&quot; _
+ , &quot;FindRegex&quot; _
+ , &quot;HashStr&quot; _
+ , &quot;HtmlEncode&quot; _
+ , &quot;IsADate&quot; _
+ , &quot;IsAlpha&quot; _
+ , &quot;IsAlphaNum&quot; _
+ , &quot;IsAscii&quot; _
+ , &quot;IsDigit&quot; _
+ , &quot;IsEmail&quot; _
+ , &quot;IsFileName&quot; _
+ , &quot;IsHexDigit&quot; _
+ , &quot;IsIPv4&quot; _
+ , &quot;IsLike&quot; _
+ , &quot;IsLower&quot; _
+ , &quot;IsPrintable&quot; _
+ , &quot;IsRegex&quot; _
+ , &quot;IsSheetName&quot; _
+ , &quot;IsTitle&quot; _
+ , &quot;IsUpper&quot; _
+ , &quot;IsUrl&quot; _
+ , &quot;IsWhitespace&quot; _
+ , &quot;JustifyCenter&quot; _
+ , &quot;JustifyLeft&quot; _
+ , &quot;JustifyRight&quot; _
+ , &quot;Quote&quot; _
+ , &quot;ReplaceChar&quot; _
+ , &quot;ReplaceRegex&quot; _
+ , &quot;ReplaceStr&quot; _
+ , &quot;Represent&quot; _
+ , &quot;Reverse&quot; _
+ , &quot;SplitLines&quot; _
+ , &quot;SplitNotQuoted&quot; _
+ , &quot;StartsWith&quot; _
+ , &quot;TrimExt&quot; _
+ , &quot;Unescape&quot; _
+ , &quot;Unquote&quot; _
+ , &quot;Wrap&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_String.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties as an array
+
+ Properties = Array( _
+ &quot;sfCR&quot; _
+ , &quot;sfCRLF&quot; _
+ , &quot;sfLF&quot; _
+ , &quot;sfNEWLINE&quot; _
+ , &quot;sfTAB&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Session.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Quote(Optional ByRef InputStr As Variant _
+ , Optional ByVal QuoteChar As String _
+ ) As String
+&apos;&apos;&apos; Return the input string surrounded with double quotes
+&apos;&apos;&apos; Used f.i. to prepare a string field to be stored in a csv-like file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; QuoteChar: either &quot; (default) or &apos;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Existing - including leading and/or trailing - double quotes are doubled
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Quote(&quot;àé&quot;&quot;n ΣlPµ Русский&quot;) returns &quot;&quot;&quot;àé&quot;&quot;&quot;&quot;n ΣlPµ Русский&quot;&quot;&quot;
+
+Dim sQuote As String &apos; Return value
+Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
+Const cstEscape = &quot;\&quot;
+Const cstThisSub = &quot;String.Quote&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sQuote = &quot;&quot;
+
+Check:
+ If IsMissing(QuoteChar) Or IsEmpty(QuoteChar) Then QuoteChar = cstDouble
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(QuoteChar, &quot;QuoteChar&quot;, V_STRING, Array(cstDouble, cstSingle)) Then GoTo Finally
+ End If
+
+Try:
+ If QuoteChar = cstDouble Then
+ sQuote = cstDouble &amp; Replace(InputStr, cstDouble, cstDouble &amp; cstDouble) &amp; cstDouble
+ Else
+ sQuote = Replace(InputStr, cstEscape, cstEscape &amp; cstEscape)
+ sQuote = cstSingle &amp; Replace(sQuote, cstSingle, cstEscape &amp; cstSingle) &amp; cstSingle
+ End If
+
+Finally:
+ Quote = sQuote
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Quote
+
+REM -----------------------------------------------------------------------------
+Public Function ReplaceChar(Optional ByRef InputStr As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal After As Variant _
+ ) As String
+&apos;&apos;&apos; Replace in InputStr all occurrences of any character from Before
+&apos;&apos;&apos; by the corresponding character in After
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string on which replacements should occur
+&apos;&apos;&apos; Before: a string of characters to replace 1 by 1 in InputStr
+&apos;&apos;&apos; After: the replacing characters
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new string after replacement of Nth character of Before by the Nth character of After
+&apos;&apos;&apos; Replacements are done one by one =&gt; potential overlaps
+&apos;&apos;&apos; If the length of Before is larger than the length of After,
+&apos;&apos;&apos; the residual characters of Before are replaced by the last character of After
+&apos;&apos;&apos; The input string when Before is the zero-length string
+&apos;&apos;&apos; Examples: easily remove accents
+&apos;&apos;&apos; SF_String.ReplaceChar(&quot;Protégez votre vie privée&quot;, &quot;àâãçèéêëîïôöûüýÿ&quot;, &quot;aaaceeeeiioouuyy&quot;)
+&apos;&apos;&apos; returns &quot;Protegez votre vie privee&quot;
+&apos;&apos;&apos; SF_String.ReplaceChar(&quot;Protégez votre vie privée&quot;, SF_String.CHARSWITHACCENT, SF_String.CHARSWITHOUTACCENT)
+
+Dim sOutput As String &apos; Return value
+Dim iCaseSensitive As Integer &apos; Always 0 (True)
+Dim sBefore As String &apos; A single character extracted from InputStr
+Dim sAfter As String &apos; A single character extracted from After
+Dim lInStr As Long &apos; Output of InStr()
+Dim i As Long
+Const cstThisSub = &quot;String.ReplaceChar&quot;
+Const cstSubArgs = &quot;InputStr, Before, After&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sOutput = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Before, &quot;Before&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(After, &quot;After&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Replace standard function =&gt; Replace(string, before, after, start, occurrences, casesensitive)
+ sOutput = InputStr
+ iCaseSensitive = 0
+
+ &apos; Replace one by one up length of Before and After
+ If Len(Before) &gt; 0 Then
+ i = 1
+ Do While i &lt;= Len(sOutput)
+ sBefore = Mid(sOutput, i, 1)
+ lInStr = InStr(1, Before, sBefore, iCaseSensitive)
+ If lInStr &gt; 0 Then
+ If Len(After) = 0 Then
+ sAfter = &quot;&quot;
+ ElseIf lInStr &gt; Len(After) Then
+ sAfter = Right(After, 1)
+ Else
+ sAfter = Mid(After, lInStr, 1)
+ End If
+ sOutput = Left(sOutput, i - 1) &amp; Replace(sOutput, sBefore, sAfter, i, Empty, iCaseSensitive)
+ End If
+ i = i + 1
+ Loop
+ End If
+
+Finally:
+ ReplaceChar = sOutput
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.ReplaceChar
+
+REM -----------------------------------------------------------------------------
+Public Function ReplaceRegex(Optional ByRef InputStr As Variant _
+ , Optional ByVal Regex As Variant _
+ , Optional ByRef NewStr As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As String
+&apos;&apos;&apos; Replace in InputStr all occurrences of a given regular expression by NewStr
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string where replacements should occur
+&apos;&apos;&apos; Regex: the regular expression
+&apos;&apos;&apos; NewStr: the replacing string
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new string after all replacements
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.ReplaceRegex(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;[a-z]&quot;, &quot;x&quot;, CaseSensitive := True)
+&apos;&apos;&apos; returns &quot;Lxxxx xxxxx xxxxx xxx xxxx, xxxxxxxxxxx xxxxxxxxxx xxxx.&quot;
+&apos;&apos;&apos; SF_String.ReplaceRegex(&quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;, &quot;\b[a-z]+\b&quot;, &quot;x&quot;, CaseSensitive := False)
+&apos;&apos;&apos; returns &quot;x x x x x, x x x.&quot; (each word is replaced by x)
+
+
+Dim sOutput As String &apos; Return value
+Dim lStartOld As Long &apos; Previous start of search
+Dim lStartNew As Long &apos; Next start of search
+Dim sSubstring As String &apos; Substring to replace
+Const cstThisSub = &quot;String.ReplaceRegex&quot;
+Const cstSubArgs = &quot;InputStr, Regex, NewStr, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sOutput = &quot;&quot;
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(NewStr, &quot;NewStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ sOutput = &quot;&quot;
+ lStartNew = 1
+ lStartOld = 1
+
+ Do While lStartNew &gt;= 1 And lStartNew &lt;= Len(InputStr)
+ sSubstring = SF_String.FindRegex(InputStr, Regex, lStartNew, CaseSensitive)
+ If lStartNew = 0 Then &apos; Regex not found
+ &apos; Copy remaining substring of InputStr before leaving
+ sOutput = sOutput &amp; Mid(InputStr, lStartOld)
+ Exit Do
+ End If
+ &apos; Append the interval between 2 occurrences and the replacing string
+ If lStartNew &gt; lStartOld Then sOutput = sOutput &amp; Mid(InputStr, lStartOld, lStartNew - lStartOld)
+ sOutput = sOutput &amp; NewStr
+ lStartOld = lStartNew + Len(sSubstring)
+ lStartNew = lStartOld
+ Loop
+
+Finally:
+ ReplaceRegex = sOutput
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.ReplaceRegex
+
+REM -----------------------------------------------------------------------------
+Public Function ReplaceStr(Optional ByRef InputStr As Variant _
+ , Optional ByVal OldStr As Variant _
+ , Optional ByVal NewStr As Variant _
+ , Optional ByVal Occurrences As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As String
+&apos;&apos;&apos; Replace in InputStr some or all occurrences of OldStr by NewStr
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string on which replacements should occur
+&apos;&apos;&apos; OldStr: the string to replace or a 1D array of strings to replace
+&apos;&apos;&apos; Zero-length strings are ignored
+&apos;&apos;&apos; NewStr: the replacing string or a 1D array of replacing strings
+&apos;&apos;&apos; If OldStr is an array
+&apos;&apos;&apos; each occurrence of any of the items of OldStr is replaced by NewStr
+&apos;&apos;&apos; If OldStr and NewStr are arrays
+&apos;&apos;&apos; replacements occur one by one up to the UBound of NewStr
+&apos;&apos;&apos; remaining OldStr(ings) are replaced by the last element of NewStr
+&apos;&apos;&apos; Occurrences: the maximum number of replacements (0, default, = all occurrences)
+&apos;&apos;&apos; Is applied for each single replacement when OldStr is an array
+&apos;&apos;&apos; CaseSensitive: True or False (default)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new string after replacements
+&apos;&apos;&apos; Replacements are done one by one when OldStr is an array =&gt; potential overlaps
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.ReplaceStr(&quot;abCcdefghHij&quot;, Array(&quot;c&quot;, &quot;h&quot;), Array(&quot;Y&quot;, &quot;Z&quot;), CaseSensitive := False) returns &quot;abYYdefgZZij&quot;
+
+Dim sOutput As String &apos; Return value
+Dim iCaseSensitive As Integer &apos; Integer alias for boolean CaseSensitive
+Dim vOccurrences As Variant &apos; Variant alias for Integer Occurrences
+Dim sNewStr As String &apos; Alias for a NewStr item
+Dim i As Long, j As Long
+Const cstThisSub = &quot;String.ReplaceStr&quot;
+Const cstSubArgs = &quot;InputStr, OldStr, NewStr, [Occurrences=0], [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sOutput = &quot;&quot;
+
+Check:
+ If IsMissing(Occurrences) Or IsEmpty(Occurrences) Then Occurrences = 0
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If IsArray(OldStr) Then
+ If Not SF_Utils._ValidateArray(OldStr, &quot;OldStr&quot;, 1, V_STRING, True) Then GoTo Finally
+ Else
+ If Not SF_Utils._Validate(OldStr, &quot;OldStr&quot;, V_STRING) Then GoTo Finally
+ End If
+ If IsArray(NewStr) Then
+ If Not SF_Utils._ValidateArray(NewStr, &quot;NewStr&quot;, 1, V_STRING, True) Then GoTo Finally
+ Else
+ If Not SF_Utils._Validate(NewStr, &quot;NewStr&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Not SF_Utils._Validate(Occurrences, &quot;Occurrences&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Replace standard function =&gt; Replace(string, before, after, start, occurrences, casesensitive)
+ sOutput = InputStr
+ iCaseSensitive = Iif(CaseSensitive, 0, 1) &apos; 1 = False ;)
+ vOccurrences = Iif(Occurrences = 0, Empty, Occurrences) &apos; Empty = no limit
+ If Not IsArray(OldStr) Then OldStr = Array(OldStr)
+ If Not IsArray(NewStr) Then NewStr = Array(NewStr)
+
+ &apos; Replace one by one up to UBounds of Old and NewStr
+ j = LBound(NewStr) - 1
+ For i = LBound(OldStr) To UBound(OldStr)
+ j = j + 1
+ If j &lt;= UBound(NewStr) Then sNewStr = NewStr(j) &apos; Else do not change
+ If StrComp(OldStr(i), sNewStr, 1) &lt;&gt; 0 Then
+ sOutput = Replace(sOutput, OldStr(i), sNewStr, 1, vOccurrences, iCaseSensitive)
+ End If
+ Next i
+
+Finally:
+ ReplaceStr = sOutput
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.ReplaceStr
+
+REM -----------------------------------------------------------------------------
+Public Function Represent(Optional ByRef AnyValue As Variant _
+ , Optional ByVal MaxLength As Variant _
+ ) As String
+&apos;&apos;&apos; Return a readable (string) form of the argument, truncated at MaxLength
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; AnyValue: really any value (object, date, whatever)
+&apos;&apos;&apos; MaxLength: the maximum length of the resulting string (Default = 0, unlimited)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The argument converted or transformed into a string of a maximum length = MaxLength
+&apos;&apos;&apos; Objects are surrounded with square brackets ([])
+&apos;&apos;&apos; In strings, tabs and line breaks are replaced by \t, \n or \r
+&apos;&apos;&apos; If the effective length exceeds MaxLength, the final part of the string is replaced by &quot; ... (N)&quot;
+&apos;&apos;&apos; where N = the total length of the string before truncation
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Represent(&quot;this is a usual string&quot;) returns &quot;this is a usual string&quot;
+&apos;&apos;&apos; SF_String.Represent(&quot;this is a usual string&quot;, 15) returns &quot;this i ... (22)&quot;
+&apos;&apos;&apos; SF_String.Represent(&quot;this is a&quot; &amp; Chr(10) &amp; &quot; 2-lines string&quot;) returns &quot;this is a\n 2-lines string&quot;
+&apos;&apos;&apos; SF_String.Represent(Empty) returns &quot;[EMPTY]&quot;
+&apos;&apos;&apos; SF_String.Represent(Null) returns &quot;[NULL]&quot;
+&apos;&apos;&apos; SF_String.Represent(Pi) returns &quot;3.142&quot;
+&apos;&apos;&apos; SF_String.Represent(CreateUnoService(&quot;com.sun.star.util.PathSettings&quot;)) returns &quot;[com.sun.star.comp.framework.PathSettings]&quot;
+&apos;&apos;&apos; SF_String.Represent(Array(1, 2, &quot;Text&quot; &amp; Chr(9) &amp; &quot;here&quot;)) returns &quot;[ARRAY] (0:2) (1, 2, Text\there)&quot;
+&apos;&apos;&apos; Dim myDict As Variant : myDict = CreateScriptService(&quot;Dictionary&quot;)
+&apos;&apos;&apos; myDict.Add(&quot;A&quot;, 1) : myDict.Add(&quot;B&quot;, 2)
+&apos;&apos;&apos; SF_String.Represent(myDict) returns &quot;[Dictionary] (&quot;A&quot;:1, &quot;B&quot;:2)&quot;
+
+Dim sRepr As String &apos; Return value
+Const cstThisSub = &quot;String.Represent&quot;
+Const cstSubArgs = &quot;AnyValue, [MaxLength=0]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sRepr = &quot;&quot;
+
+Check:
+ If IsMissing(AnyValue) Then AnyValue = Empty
+ If IsMissing(MaxLength) Or IsEmpty(MaxLength) Then MaxLength = 0
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(MaxLength, &quot;MaxLength&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ sRepr = SF_Utils._Repr(AnyValue, MaxLength)
+ If MaxLength &gt; 0 And MaxLength &lt; Len(sRepr) Then sRepr = sRepr &amp; &quot; ... (&quot; &amp; Len(sRepr) &amp; &quot;)&quot;
+
+Finally:
+ Represent = sRepr
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Represent
+
+REM -----------------------------------------------------------------------------
+Public Function Reverse(Optional ByRef InputStr As Variant) As String
+&apos;&apos;&apos; Return the input string in reversed order
+&apos;&apos;&apos; It is equivalent to the standard StrReverse Basic function
+&apos;&apos;&apos; The latter requires the OpTion VBASupport 1 statement to be present in the module
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string in reversed order
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Reverse(&quot;abcdefghij&quot;) returns &quot;jihgfedcba&quot;
+
+Dim sReversed As String &apos; Return value
+Dim lLength As Long &apos; Length of input string
+Dim i As Long
+Const cstThisSub = &quot;String.Reverse&quot;
+Const cstSubArgs = &quot;InputSt&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sReversed = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ lLength = Len(InputStr)
+ If lLength &gt; 0 Then
+ sReversed = Space(lLength)
+ For i = 1 To lLength
+ Mid(sReversed, i, 1) = Mid(InputStr, lLength - i + 1)
+ Next i
+ End If
+
+Finally:
+ Reverse = sReversed
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Reverse
+
+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;String.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; ScriptForge.SF_String.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function SplitLines(Optional ByRef InputStr As Variant _
+ , Optional ByVal KeepBreaks As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return an array of the lines in a string, breaking at line boundaries
+&apos;&apos;&apos; Line boundaries include LF(10), VT(12), CR(13), LF+CR, File separator(28), Group separator(29), Record separator(30),
+&apos;&apos;&apos; Next Line(133), Line separator(8232), Paragraph separator(8233)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; KeepBreaks: when True, line breaks are preserved in the output array (default = False)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array of all the individual lines
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.SplitLines(&quot;Line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot; &amp; Chr(13) &amp; &quot;Line3&quot;) returns (&quot;Line1&quot;, &quot;Line2&quot;, &quot;Line3&quot;)
+&apos;&apos;&apos; SF_String.SplitLines(&quot;Line1&quot; &amp; Chr(10) &amp; &quot;Line2&quot; &amp; Chr(13) &amp; &quot;Line3&quot; &amp; Chr(10)) returns (&quot;Line1&quot;, &quot;Line2&quot;, &quot;Line3&quot;, &quot;&quot;)
+
+Dim vSplit As Variant &apos; Return value
+Dim vLineBreaks As Variant &apos; Array of recognized line breaks
+Dim vTokenizedBreaks As Variant &apos; Array of line breaks extended with tokens
+Dim sAlias As String &apos; Alias for input string
+&apos; The procedure uses (dirty) placeholders to identify line breaks
+&apos; The used tokens are presumed unlikely present in text strings
+Dim sTokenCRLF As String &apos; Token to identify combined CR + LF
+Dim sToken As String &apos; Token to identify any line break
+Dim i As Long
+Const cstThisSub = &quot;String.SplitLines&quot;
+Const cstSubArgs = &quot;InputStr, [KeepBreaks=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSplit = Array()
+
+Check:
+ If IsMissing(KeepBreaks) Or IsEmpty(KeepBreaks) Then KeepBreaks = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(KeepBreaks, &quot;KeepBreaks&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ &apos; In next list CR + LF must precede CR and LF
+ vLineBreaks = Array(SF_String.sfCRLF, SF_String.sfLF, Chr(12), SF_String.sfCR _
+ , Chr(28), Chr(29), Chr(30), Chr(133), Chr(8232), Chr(8233))
+
+ If KeepBreaks = False Then
+ &apos; Replace line breaks by linefeeds and split on linefeeds
+ vSplit = Split(SF_String.ReplaceStr(InputStr, vLineBreaks, SF_String.sfLF, CaseSensitive := False), SF_String.sfLF)
+ Else
+ sTokenCRLF = Chr(1) &amp; &quot;$&quot; &amp; Chr(2) &amp; &quot;*&quot; &amp; Chr(3) &amp; &quot;$&quot; &amp; Chr(1)
+ sToken = Chr(1) &amp; &quot;$&quot; &amp; Chr(2) &amp; &quot;*&quot; &amp; Chr(3) &amp; &quot;$&quot; &amp; Chr(2)
+ vTokenizedBreaks = Array() : ReDim vTokenizedBreaks(0 To UBound(vLineBreaks))
+ &apos; Extend breaks with token
+ For i = 0 To UBound(vLineBreaks)
+ vTokenizedBreaks(i) = Iif(i = 0, sTokenCRLF, vLineBreaks(i)) &amp; sToken
+ Next i
+ sAlias = SF_String.ReplaceStr(InputStr, vLineBreaks, vTokenizedBreaks, CaseSensitive := False)
+ &apos; Suppress CRLF tokens and split
+ vSplit = Split(Replace(sAlias, sTokenCRLF, SF_String.sfCRLF), sToken)
+ End If
+
+Finally:
+ SplitLines = vSplit
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.SplitLines
+
+REM -----------------------------------------------------------------------------
+Public Function SplitNotQuoted(Optional ByRef InputStr As Variant _
+ , Optional ByVal Delimiter As Variant _
+ , Optional ByVal Occurrences As Variant _
+ , Optional ByVal QuoteChar As Variant _
+ ) As Variant
+&apos;&apos;&apos; Split a string on Delimiter into an array. If Delimiter is part of a quoted (sub)string, it is ignored
+&apos;&apos;&apos; (used f.i. for parsing of csv-like records)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Might contain quoted substrings:
+&apos;&apos;&apos; The quoting character must be the double quote (&quot;)
+&apos;&apos;&apos; To preserve a quoting character inside the quoted substring, use (\) or (&quot;) as escape character
+&apos;&apos;&apos; =&gt; [str\&quot;i&quot;&quot;ng] means [str&quot;i&quot;ng]
+&apos;&apos;&apos; Delimiter: A string of one or more characters that is used to delimit the input string
+&apos;&apos;&apos; The default is the space character
+&apos;&apos;&apos; Occurrences: The number of substrings to return (Default = 0, meaning no limit)
+&apos;&apos;&apos; QuoteChar: The quoting character, either &quot; (default) or &apos;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array whose items are chunks of the input string, Delimiter not included
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc def ghi&quot;) returns (&quot;abc&quot;, &quot;def&quot;, &quot;ghi&quot;)
+&apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc,&quot;&quot;def,ghi&quot;&quot;&quot;, &quot;,&quot;) returns (&quot;abc&quot;, &quot;&quot;&quot;def,ghi&quot;&quot;&quot;)
+&apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc,&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;, &quot;,&quot;) returns (&quot;abc&quot;, &quot;&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;)
+&apos;&apos;&apos; SF_String.SplitNotQuoted(&quot;abc,&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;&quot;,&quot;, &quot;,&quot;) returns (&quot;abc&quot;, &quot;&quot;&quot;def\&quot;&quot;,ghi&quot;&quot;&quot;, &quot;&quot;)
+
+Dim vSplit As Variant &apos; Return value
+Dim lDelimLen As Long &apos; Length of Delimiter
+Dim vStart As Variant &apos; Array of start positions of quoted strings
+Dim vEnd As Variant &apos; Array of end positions of quoted strings
+Dim lInStr As Long &apos; InStr() on input string
+Dim lInStrPrev As Long &apos; Previous value of lInputStr
+Dim lBound As Long &apos; UBound of vStart and vEnd
+Dim lMin As Long &apos; Lower bound to consider when searching vStart and vEnd
+Dim oCharacterClass As Object &apos; com.sun.star.i18n.CharacterClassification
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oParse As Object &apos; com.sun.star.i18n.ParseResult
+Dim sChunk As String &apos; Substring of InputStr
+Dim bSplit As Boolean &apos; New chunk found or not
+Dim i As Long
+Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
+Const cstThisSub = &quot;String.SplitNotQuoted&quot;
+Const cstSubArgs = &quot;InputStr, [Delimiter=&quot;&quot; &quot;&quot;], [Occurrences=0], [QuoteChar=&quot;&quot;&quot; &amp; cstDouble &amp; &quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSplit = Array()
+
+Check:
+ If IsMissing(Delimiter) Or IsEmpty(Delimiter) Then Delimiter = &quot; &quot;
+ If IsMissing(Occurrences) Or IsEmpty(Occurrences) Then Occurrences = 0
+ If IsMissing(QuoteChar) Or IsEmpty(QuoteChar) Then QuoteChar = cstDouble
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Delimiter, &quot;Delimiter&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Occurrences, &quot;Occurrences&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(QuoteChar, &quot;QuoteChar&quot;, V_STRING, Array(cstDouble, cstSingle)) Then GoTo Finally
+ End If
+ If Len(Delimiter) = 0 Then Delimiter = &quot; &quot;
+
+Try:
+ If Occurrences = 1 Or InStr(1, InputStr, Delimiter, 0) = 0 Then &apos; No reason to split
+ vSplit = Array(InputStr)
+ ElseIf InStr(1, InputStr, QuoteChar, 0) = 0 Then &apos; No reason to make a complex split
+ If Occurrences &gt; 0 Then vSplit = Split(InputStr, Delimiter, Occurrences) Else vSplit = Split(InputStr, Delimiter)
+ Else
+ If Occurrences &lt; 0 Then Occurrences = 0
+ Set oCharacterClass = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+
+ &apos; Build an array of start/end positions of quoted strings containing at least 1x the Delimiter
+ vStart = Array() : vEnd = Array()
+ lInStr = InStr(1, InputStr, QuoteChar)
+ Do While lInStr &gt; 0
+ lBound = UBound(vStart)
+ &apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1i18n_1_1XCharacterClassification.html#ad5f1be91fbe86853200391f828d4166b
+ Set oParse = oCharacterClass.parsePredefinedToken( _
+ Iif(QuoteChar = cstDouble, com.sun.star.i18n.KParseType.DOUBLE_QUOTE_STRING, com.sun.star.i18n.KParseType.SINGLE_QUOTE_NAME) _
+ , InputStr, lInStr - 1, oLocale, 0, &quot;&quot;, 0, &quot;&quot;)
+ If oParse.CharLen &gt; 0 Then &apos; Is parsing successful ?
+ &apos; Is there some delimiter ?
+ If InStr(1, oParse.DequotedNameOrString, Delimiter, 0) &gt; 0 Then
+ vStart = SF_Array.Append(vStart, lInStr + 0)
+ vEnd = SF_Array.Append(vEnd, lInStr + oParse.CharLen - 1)
+ End If
+ lInStr = InStr(lInStr + oParse.CharLen, InputStr, QuoteChar)
+ Else
+ lInStr = 0
+ End If
+ Loop
+
+ lBound = UBound(vStart)
+ lDelimLen = Len(Delimiter)
+ If lBound &lt; 0 Then &apos; Usual split is applicable
+ vSplit = Split(InputStr, Delimiter, Occurrences)
+ Else
+ &apos; Split chunk by chunk
+ lMin = 0
+ lInStrPrev = 0
+ lInStr = InStr(1, InputStr, Delimiter, 0)
+ Do While lInStr &gt; 0
+ If Occurrences &gt; 0 And Occurrences = UBound(vSplit) - 1 Then Exit Do
+ bSplit = False
+ &apos; Ignore found Delimiter if in quoted string
+ For i = lMin To lBound
+ If lInStr &lt; vStart(i) Then
+ bSplit = True
+ Exit For
+ ElseIf lInStr &gt; vStart(i) And lInStr &lt; vEnd (i) Then
+ Exit For
+ Else
+ lMin = i + 1
+ If i = lBound Then bSplit = True Else bSplit = ( lInStr &lt; vStart(lMin) )
+ End If
+ Next i
+ &apos; Build next chunk and store in split array
+ If bSplit Then
+ If lInStrPrev = 0 Then &apos; First chunk
+ sChunk = Left(InputStr, lInStr - 1)
+ Else
+ sChunk = Mid(InputStr, lInStrPrev + lDelimLen, lInStr - lInStrPrev - lDelimLen)
+ End If
+ vSplit = SF_Array.Append(vSplit, sChunk &amp; &quot;&quot;)
+ lInStrPrev = lInStr
+ End If
+ lInStr = InStr(lInStr + lDelimLen, InputStr, Delimiter, 0)
+ Loop
+ If Occurrences = 0 Or Occurrences &gt; UBound(vSplit) + 1 Then
+ sChunk = Mid(InputStr, lInStrPrev + lDelimLen) &apos; Append last chunk
+ vSplit = SF_Array.Append(vSplit, sChunk &amp; &quot;&quot;)
+ End If
+ End If
+ End If
+
+Finally:
+ SplitNotQuoted = vSplit
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.SplitNotQuoted
+
+REM -----------------------------------------------------------------------------
+Public Function StartsWith(Optional ByRef InputStr As Variant _
+ , Optional ByVal Substring As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the first characters of InputStr are identical to Substring
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Substring: the prefixing characters
+&apos;&apos;&apos; CaseSensitive: default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the comparison is satisfactory
+&apos;&apos;&apos; False if either InputStr or Substring have a length = 0
+&apos;&apos;&apos; False if Substr is longer than InputStr
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.StartsWith(&quot;abcdefg&quot;, &quot;ABC&quot;) returns True
+&apos;&apos;&apos; SF_String.StartsWith(&quot;abcdefg&quot;, &quot;ABC&quot;, CaseSensitive := True) returns False
+
+Dim bStartsWith As Boolean &apos; Return value
+Dim lSub As Long &apos; Length of SUbstring
+Const cstThisSub = &quot;String.StartsWith&quot;
+Const cstSubArgs = &quot;InputStr, Substring, [CaseSensitive=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bStartsWith = False
+
+Check:
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Substring, &quot;Substring&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ lSub = Len(Substring)
+ If Len(InputStr) &gt; 0 And lSub &gt; 0 And lSub &lt;= Len(InputStr) Then
+ bStartsWith = ( StrComp(Left(InputStr, lSub), Substring, Iif(CaseSensitive, 1, 0)) = 0 )
+ End If
+
+Finally:
+ StartsWith = bStartsWith
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.StartsWith
+
+REM -----------------------------------------------------------------------------
+Public Function TrimExt(Optional ByRef InputStr As Variant) As String
+&apos;&apos;&apos; Return the input string without its leading and trailing whitespaces
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string without its leading and trailing white spaces
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.TrimExt(&quot; ABCDE&quot; &amp; Chr(9) &amp; Chr(10) &amp; Chr(13) &amp; &quot; &quot;) returns &quot;ABCDE&quot;
+
+Dim sTrim As String &apos; Return value
+Const cstThisSub = &quot;String.TrimExt&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sTrim = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then
+ sTrim = SF_String.ReplaceRegex(InputStr, REGEXLTRIM, &quot;&quot;) &apos; Trim left
+ sTrim = SF_String.ReplaceRegex(sTrim, REGEXRTRIM, &quot;&quot;) &apos; Trim right
+ End If
+
+Finally:
+ TrimExt = sTrim
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.TrimExt
+
+REM -----------------------------------------------------------------------------
+Public Function Unescape(Optional ByRef InputStr As Variant) As String
+&apos;&apos;&apos; Convert any escaped characters in the input string
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string after replacement of \\, \n, \r, \t sequences
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Unescape(&quot;abc\n\tdef\\n&quot;) returns &quot;abc&quot; &amp; Chr(10) &amp; Chr(9) &amp; &quot;def\n&quot;
+
+Dim sUnescape As String &apos; Return value
+Dim sToken As String &apos; Placeholder unlikely to be present in input string
+Const cstThisSub = &quot;String.Unescape&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sUnescape = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ sToken = Chr(1) &amp; &quot;$&quot; &amp; Chr(2) &amp; &quot;*&quot; &amp; Chr(3) &amp; &quot;$&quot; &amp; Chr(1) &apos; Placeholder for &quot;\\&quot;
+ sUnescape = SF_String.ReplaceStr( InputStr _
+ , Array(&quot;\\&quot;, &quot;\n&quot;, &quot;\r&quot;, &quot;\t&quot;, sToken) _
+ , Array(sToken, SF_String.sfLF, SF_String.sfCR, SF_String.sfTAB, &quot;\&quot;) _
+ )
+
+Finally:
+ Unescape = sUnescape
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Unescape
+
+REM -----------------------------------------------------------------------------
+Public Function Unquote(Optional ByRef InputStr As Variant _
+ , Optional ByVal QuoteChar As String _
+ ) As String
+&apos;&apos;&apos; Reset a quoted string to its original content
+&apos;&apos;&apos; (used f.i. for parsing of csv-like records)
+&apos;&apos;&apos; When the input string contains the quote character, the latter must be escaped:
+&apos;&apos;&apos; - QuoteChar = double quote, by doubling it (&quot;&quot;)
+&apos;&apos;&apos; - QuoteChar = single quote, with a preceding backslash (\&apos;)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; QuoteChar: either &quot; (default) or &apos;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string after removal of leading/trailing quotes and escaped single/double quotes
+&apos;&apos;&apos; The input string if not a quoted string
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Unquote(&quot;&quot;&quot;àé&quot;&quot;&quot;&quot;n ΣlPµ Русский&quot;&quot;&quot;) returns &quot;àé&quot;&quot;n ΣlPµ Русский&quot;
+
+Dim sUnquote As String &apos; Return value
+Dim oCharacterClass As Object &apos; com.sun.star.i18n.CharacterClassification
+Dim oLocale As Object &apos; com.sun.star.lang.Locale
+Dim oParse As Object &apos; com.sun.star.i18n.ParseResult
+Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
+Const cstThisSub = &quot;String.Unquote&quot;
+Const cstSubArgs = &quot;InputStr&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sUnquote = &quot;&quot;
+
+Check:
+ If IsMissing(QuoteChar) Or IsEmpty(QuoteChar) Then QuoteChar = cstDouble
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(QuoteChar, &quot;QuoteChar&quot;, V_STRING, Array(cstDouble, cstSingle)) Then GoTo Finally
+ End If
+
+Try:
+ If Left(InputStr, 1) &lt;&gt; QuoteChar Then &apos; No need to parse further
+ sUnquote = InputStr
+ Else
+ Set oCharacterClass = SF_Utils._GetUNOService(&quot;CharacterClass&quot;)
+ Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
+
+ &apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1i18n_1_1XCharacterClassification.html#ad5f1be91fbe86853200391f828d4166b
+ Set oParse = oCharacterClass.parsePredefinedToken( _
+ Iif(QuoteChar = cstDouble, com.sun.star.i18n.KParseType.DOUBLE_QUOTE_STRING, com.sun.star.i18n.KParseType.SINGLE_QUOTE_NAME) _
+ , InputStr, 0, oLocale, 0, &quot;&quot;, 0, &quot;&quot;)
+ If oParse.CharLen &gt; 0 Then &apos; Is parsing successful ?
+ sUnquote = oParse.DequotedNameOrString
+ Else
+ sUnquote = InputStr
+ End If
+ End If
+
+Finally:
+ Unquote = sUnquote
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Unquote
+
+REM -----------------------------------------------------------------------------
+Public Function Wrap(Optional ByRef InputStr As Variant _
+ , Optional ByVal Width As Variant _
+ , Optional ByVal TabSize As Variant _
+ ) As Variant
+&apos;&apos;&apos; Wraps every single paragraph in text (a string) so every line is at most Width characters long
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: the input string
+&apos;&apos;&apos; Width: the maximum number of characters in each line, default = 70
+&apos;&apos;&apos; TabSize: before wrapping the text, the existing TAB (Chr(9)) characters are replaced with spaces.
+&apos;&apos;&apos; TabSize defines the TAB positions at TabSize + 1, 2 * TabSize + 1 , ... N * TabSize + 1
+&apos;&apos;&apos; Default = 8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Returns a zero-based array of output lines, without final newlines except the pre-existing line-breaks
+&apos;&apos;&apos; Tabs are expanded. Symbolic line breaks are replaced by their hard equivalents
+&apos;&apos;&apos; If the wrapped output has no content, the returned array is empty.
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; SF_String.Wrap(&quot;Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...&quot;, 20)
+
+Dim vWrap As Variant &apos; Return value
+Dim vWrapLines &apos; Input string split on line breaks
+Dim sWrap As String &apos; Intermediate string
+Dim sLine As String &apos; Line after splitting on line breaks
+Dim lPos As Long &apos; Position in sLine already wrapped
+Dim lStart As Long &apos; Start position before and after regex search
+Dim sSpace As String &apos; Next whitespace
+Dim sChunk As String &apos; Next wrappable text chunk
+Const cstThisSub = &quot;String.Wrap&quot;
+Const cstSubArgs = &quot;InputStr, [Width=70], [TabSize=8]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vWrap = Array()
+
+Check:
+ If IsMissing(Width) Or IsEmpty(Width) Then Width = 70
+ If IsMissing(TabSize) Or IsEmpty(TabSize) Then TabSize = 8
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Width, &quot;Width&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(TabSize, &quot;TabSize&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ If Len(InputStr) &gt; 0 Then
+ sWrap = SF_String.Unescape(InputStr) &apos; Replace symbolic breaks
+ sWrap = SF_String.ExpandTabs(sWrap, TabSize) &apos; Interpret TABs to have a meaningful Width
+ &apos; First, split full string
+ vWrapLines = SF_String.SplitLines(sWrap, KeepBreaks := True) &apos; Keep pre-existing breaks
+ If UBound(vWrapLines) = 0 And Len(sWrap) &lt;= Width Then &apos; Output a single line
+ vWrap = Array(sWrap)
+ Else
+ &apos; Second, split each line on Width
+ For Each sLine In vWrapLines
+ If Len(sLine) &lt;= Width Then
+ If UBound(vWrap) &lt; 0 Then vWrap = Array(sLine) Else vWrap = SF_Array.Append(vWrap, sLine)
+ Else
+ &apos; Scan sLine and accumulate found substrings up to Width
+ lStart = 1
+ lPos = 0
+ sWrap = &quot;&quot;
+ Do While lStart &lt;= Len(sLine)
+ sSpace = SF_String.FindRegex(sLine, REGEXSPACES, lStart)
+ If lStart = 0 Then lStart = Len(sLine) + 1
+ sChunk = Mid(sLine, lPos + 1, lStart - 1 - lPos + Len(sSpace))
+ If Len(sWrap) + Len(sChunk) &lt; Width Then &apos; Add chunk to current piece of line
+ sWrap = sWrap &amp; sChunk
+ Else &apos; Save current line and initialize next one
+ If UBound(vWrap) &lt; 0 Then vWrap = Array(sWrap) Else vWrap = SF_Array.Append(vWrap, sWrap)
+ sWrap = sChunk
+ End If
+ lPos = lPos + Len(sChunk)
+ lStart = lPos + 1
+ Loop
+ &apos; Add last chunk
+ If Len(sWrap) &gt; 0 Then
+ If UBound(vWrap) &lt; 0 Then vWrap = Array(sWrap) Else vWrap = SF_Array.Append(vWrap, sWrap)
+ End If
+ End If
+ Next sLine
+ End If
+ End If
+
+Finally:
+ Wrap = vWrap
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_String.Wrap
+
+REM ============================================================= PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr(ByRef pvString As String) As String
+&apos;&apos;&apos; Convert an arbitrary string to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Carriage Returns are replaced by \r. Other line breaks are replaced by \n
+&apos;&apos;&apos; Tabs are replaced by \t
+&apos;&apos;&apos; Backslashes are doubled
+&apos;&apos;&apos; Other non printable characters are replaced by \x00 to \xFF or \x0000 to \xFFFF
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvString: the string to make readable
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; the converted string
+
+Dim sString As String &apos; Return value
+Dim sChar As String &apos; A single character
+Dim lAsc As Long &apos; Ascii value
+Dim lPos As Long &apos; Position in sString
+Dim i As Long
+
+ &apos; Process TABs, CRs and LFs
+ sString = Replace(Replace(Replace(pvString, &quot;\&quot;, &quot;\\&quot;), SF_String.sfCR, &quot;\r&quot;), SF_String.sfTAB, &quot;\t&quot;)
+ sString = Join(SF_String.SplitLines(sString, KeepBreaks := False), &quot;\n&quot;)
+ &apos; Process not printable characters
+ If Len(sString) &gt; 0 Then
+ lPos = 1
+ Do While lPos &lt;= Len(sString)
+ sChar = Mid(sString, lPos, 1)
+ If Not SF_String.IsPrintable(sChar) Then
+ lAsc = Asc(sChar)
+ sChar = &quot;\x&quot; &amp; Iif(lAsc &lt; 255, Right(&quot;00&quot; &amp; Hex(lAsc), 2), Right(&quot;0000&quot; &amp; Hex(lAsc), 4))
+ If lPos &lt; Len(sString) Then
+ sString = Left(sString, lPos - 1) &amp; sChar &amp; Mid(sString, lPos + 1)
+ Else
+ sString = Left(sString, lPos - 1) &amp; sChar
+ End If
+ End If
+ lPos = lPos + Len(sChar)
+ Loop
+ End If
+
+ _Repr = sString
+
+End Function &apos; ScriptForge.SF_String._Repr
+
+REM ================================================ END OF SCRIPTFORGE.SF_STRING
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_TextStream.xba b/wizards/source/scriptforge/SF_TextStream.xba
new file mode 100644
index 000000000..35f1b6fb2
--- /dev/null
+++ b/wizards/source/scriptforge/SF_TextStream.xba
@@ -0,0 +1,702 @@
+<?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_TextStream" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_TextStream
+&apos;&apos;&apos; =============
+&apos;&apos;&apos; Class instantiated by the
+&apos;&apos;&apos; SF_FileSystem.CreateTextFile
+&apos;&apos;&apos; SF_FileSystem.OpenTextFile
+&apos;&apos;&apos; methods to facilitate the sequential processing of text files
+&apos;&apos;&apos; All open/read/write/close operations are presumed to happen during the same macro run
+&apos;&apos;&apos; The encoding to be used may be chosen by the user
+&apos;&apos;&apos; The list is in the Name column of https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that probably not all values are available
+&apos;&apos;&apos; Line delimiters may be chosen by the user
+&apos;&apos;&apos; In input, CR, LF or CR+LF are supported
+&apos;&apos;&apos; In output, the default value is the usual newline on the actual operating system (see SF_FileSystem.sfNEWLINE)
+&apos;&apos;&apos;
+&apos;&apos;&apos; The design choices are largely inspired by
+&apos;&apos;&apos; https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/textstream-object
+&apos;&apos;&apos; The implementation is mainly based on the XTextInputStream and XTextOutputStream UNO interfaces
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1io_1_1XTextInputStream.html
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1io_1_1XTextOutputStream.html
+&apos;&apos;&apos;
+&apos;&apos;&apos; Instantiation example:
+&apos;&apos;&apos; Dim FSO As Object, myFile As Object
+&apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading) &apos; Once per file
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_textstream.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const FILENOTOPENERROR = &quot;FILENOTOPENERROR&quot; &apos; The file is already closed
+Const FILEOPENMODEERROR = &quot;FILEOPENMODEERROR&quot; &apos; The file is open in incompatible mode
+Const ENDOFFILEERROR = &quot;ENDOFFILEERROR&quot; &apos; When file was read, an end-of-file was encountered
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be TEXTSTREAM
+Private ServiceName As String
+Private _FileName As String &apos; File where it is about
+Private _IOMode As Integer &apos; ForReading, ForWriting or ForAppending
+Private _Encoding As String &apos; https://www.iana.org/assignments/character-sets/character-sets.xhtml
+Private _NewLine As String &apos; Line break in write mode
+Private _FileExists As Boolean &apos; True if file exists before open
+Private _LineNumber As Long &apos; Number of lines read or written
+Private _FileHandler As Object &apos; com.sun.star.io.XInputStream or
+ &apos; com.sun.star.io.XOutputStream or
+ &apos; com.sun.star.io.XStream
+Private _InputStream As Object &apos; com.sun.star.io.TextInputStream
+Private _OutputStream As Object &apos; com.sun.star.io.TextOutputStream
+Private _ForceBlankLine As Boolean &apos; Workaround: XTextInputStream misses last line if file ends with newline
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;TEXTSTREAM&quot;
+ ServiceName = &quot;ScriptForge.TextStream&quot;
+ _FileName = &quot;&quot;
+ _IOMode = -1
+ _Encoding = &quot;&quot;
+ _NewLine = &quot;&quot;
+ _FileExists = False
+ _LineNumber = 0
+ Set _FileHandler = Nothing
+ Set _InputStream = Nothing
+ Set _OutputStream = Nothing
+ _ForceBlankLine = False
+End Sub &apos; ScriptForge.SF_TextStream Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; ScriptForge.SF_TextStream Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_TextStream Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get AtEndOfStream() As Boolean
+&apos;&apos;&apos; In reading mode, True indicates that the end of the file has been reached
+&apos;&apos;&apos; In write and append modes, or if the file is not ready =&gt; always True
+&apos;&apos;&apos; The property should be invoked BEFORE each ReadLine() method:
+&apos;&apos;&apos; A ReadLine() executed while AtEndOfStream is True will raise an error
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim sLine As String
+&apos;&apos;&apos; Do While Not myFile.AtEndOfStream
+&apos;&apos;&apos; sLine = myFile.ReadLine()
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; Loop
+
+ AtEndOfStream = _PropertyGet(&quot;AtEndOfStream&quot;)
+
+End Property &apos; ScriptForge.SF_TextStream.AtEndOfStream
+
+REM -----------------------------------------------------------------------------
+Property Get Encoding() As String
+&apos;&apos;&apos; Returns the name of the text file either in url or in native operating system format
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;)
+&apos;&apos;&apos; MsgBox myFile.Encoding &apos; UTF-8
+
+ Encoding = _PropertyGet(&quot;Encoding&quot;)
+
+End Property &apos; ScriptForge.SF_TextStream.Encoding
+
+REM -----------------------------------------------------------------------------
+Property Get FileName() As String
+&apos;&apos;&apos; Returns the name of the text file either in url or in native operating system format
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;)
+&apos;&apos;&apos; MsgBox myFile.FileName &apos; C:\Temp\myFile.txt
+
+ FileName = _PropertyGet(&quot;FileName&quot;)
+
+End Property &apos; ScriptForge.SF_TextStream.FileName
+
+REM -----------------------------------------------------------------------------
+Property Get IOMode() As String
+&apos;&apos;&apos; Returns either &quot;READ&quot;, &quot;WRITE&quot; or &quot;APPEND&quot;
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;)
+&apos;&apos;&apos; MsgBox myFile.IOMode &apos; READ
+
+ IOMode = _PropertyGet(&quot;IOMode&quot;)
+
+End Property &apos; ScriptForge.SF_TextStream.IOMode
+
+REM -----------------------------------------------------------------------------
+Property Get Line() As Long
+&apos;&apos;&apos; Returns the number of lines read or written so far
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;, FSO.ForAppending)
+&apos;&apos;&apos; MsgBox myFile.Line &apos; The number of lines already present in myFile
+
+ Line = _PropertyGet(&quot;Line&quot;)
+
+End Property &apos; ScriptForge.SF_TextStream.Line
+
+REM -----------------------------------------------------------------------------
+Property Get NewLine() As Variant
+&apos;&apos;&apos; Returns the current character string to be inserted between 2 successive written lines
+&apos;&apos;&apos; The default value is the native line separator in the current operating system
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox myFile.NewLine
+
+ NewLine = _PropertyGet(&quot;NewLine&quot;)
+
+End Property &apos; ScriptForge.SF_TextStream.NewLine (get)
+
+REM -----------------------------------------------------------------------------
+Property Let NewLine(ByVal pvLineBreak As Variant)
+&apos;&apos;&apos; Sets the current character string to be inserted between 2 successive written lines
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myFile.NewLine = Chr(13) &amp; Chr(10)
+
+Const cstThisSub = &quot;TextStream.setNewLine&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ If VarType(pvLineBreak) = V_STRING Then _NewLine = pvLineBreak
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_TextStream.NewLine (let)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function CloseFile() As Boolean
+&apos;&apos;&apos; Empties the output buffer if relevant. Closes the actual input or output stream
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the closure was successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR Nothing found to close
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myFile.CloseFile()
+
+Dim bClose As Boolean &apos; Return value
+Const cstThisSub = &quot;TextStream.CloseFile&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bClose = False
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsFileOpen() Then GoTo Finally
+
+Try:
+ If Not IsNull(_InputStream) Then _InputStream.closeInput()
+ If Not IsNull(_OutputStream) Then
+ _OutputStream.flush()
+ _OutputStream.closeOutput()
+ End If
+ Set _InputStream = Nothing
+ Set _OutputStream = Nothing
+ Set _FileHandler = Nothing
+ bClose = True
+
+Finally:
+ CloseFile = bClose
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_TextStream.CloseFile
+
+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;TextStream.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_TextStream.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;CloseFile&quot; _
+ , &quot;ReadAll&quot; _
+ , &quot;readLine&quot; _
+ , &quot;SkipLine&quot; _
+ , &quot;WriteBlankLines&quot; _
+ , &quot;WriteLine&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_TextStream.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;AtEndOfStream&quot; _
+ , &quot;Encoding&quot; _
+ , &quot;FileName&quot; _
+ , &quot;IOMode&quot; _
+ , &quot;Line&quot; _
+ , &quot;NewLine&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_TextStream.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function ReadAll() As String
+&apos;&apos;&apos; Returns all the remaining lines in the text stream as one string. Line breaks are NOT removed
+&apos;&apos;&apos; The resulting string can be split in lines
+&apos;&apos;&apos; either by using the usual Split Basic builtin function if the line delimiter is known
+&apos;&apos;&apos; or with the SF_String.SplitLines method
+&apos;&apos;&apos; For large files, using the ReadAll method wastes memory resources.
+&apos;&apos;&apos; Other techniques should be used to input a file, such as reading a file line-by-line
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The read lines. The string may be empty.
+&apos;&apos;&apos; Note that the Line property in incremented only by 1
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
+&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
+&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; a = myFile.ReadAll()
+
+Dim sRead As String &apos; Return value
+Const cstThisSub = &quot;TextStream.ReadAll&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sRead = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
+ If _InputStream.isEOF() Then GoTo CatchEOF
+ End If
+
+Try:
+ sRead = _InputStream.readString(Array(), False)
+ _LineNumber = _LineNumber + 1
+
+Finally:
+ ReadAll = sRead
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchEOF:
+ SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_TextStream.ReadAll
+
+REM -----------------------------------------------------------------------------
+Public Function ReadLine() As String
+&apos;&apos;&apos; Returns the next line in the text stream as a string. Line breaks are removed.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The read line. The string may be empty.
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
+&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
+&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; a = myFile.ReadLine()
+
+Dim sRead As String &apos; Return value
+Dim iRead As Integer &apos; Length of line break
+Const cstThisSub = &quot;TextStream.ReadLine&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sRead = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
+ If AtEndOfStream Then GoTo CatchEOF
+ End If
+
+Try:
+ &apos; When the text file ends with a line break,
+ &apos; XTextInputStream.readLine() returns the line break together with the last line
+ &apos; Hence the workaround to force a blank line at the end
+ If _ForceBlankLine Then
+ sRead = &quot;&quot;
+ _ForceBlankLine = False
+ Else
+ sRead = _InputStream.readLine()
+ &apos; The isEOF() is set immediately after having read the last line
+ If _InputStream.isEOF() And Len(sRead) &gt; 0 Then
+ iRead = 0
+ If SF_String.EndsWith(sRead, SF_String.sfCRLF) Then
+ iRead = 2
+ ElseIf SF_String.EndsWith(sRead, SF_String.sfLF) Or SF_String.EndsWith(sRead, SF_String.sfCR) Then
+ iRead = 1
+ End If
+ If iRead &gt; 0 Then
+ sRead = Left(sRead, Len(sRead) - iRead)
+ _ForceBlankLine = True &apos; Provision for a last empty line at the next read loop
+ End If
+ End If
+ End If
+ _LineNumber = _LineNumber + 1
+
+Finally:
+ ReadLine = sRead
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchEOF:
+ SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_TextStream.ReadLine
+
+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
+
+Dim bSet As Boolean &apos; Return value
+Const cstThisSub = &quot;TextStream.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSet = 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:
+ bSet = True
+ Select Case UCase(PropertyName)
+ Case &quot;NEWLINE&quot;
+ If Not SF_Utils._Validate(Value, &quot;Value&quot;, V_STRING) Then GoTo Catch
+ NewLine = Value
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ SetProperty = bSet
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_TextStream.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Sub SkipLine()
+&apos;&apos;&apos; Skips the next line when reading a TextStream file.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
+&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
+&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myFile.SkipLine()
+
+Dim sRead As String &apos; Read buffer
+Const cstThisSub = &quot;TextStream.SkipLine&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
+ If Not _ForceBlankLine Then &apos; The file ends with a newline =&gt; return one empty line more
+ If _InputStream.isEOF() Then GoTo CatchEOF
+ End If
+ End If
+
+Try:
+ sRead = ReadLine()
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+CatchEOF:
+ SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_TextStream.SkipLine
+
+REM -----------------------------------------------------------------------------
+Public Sub WriteBlankLines(Optional ByVal Lines As Variant)
+&apos;&apos;&apos; Writes a number of empty lines in the output stream
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Lines: the number of lines to write
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
+&apos;&apos;&apos; FILEOPENMODEERROR File opened in read mode
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myFile.WriteBlankLines(10)
+Dim i As Long
+Const cstThisSub = &quot;TextStream.WriteBlankLines&quot;
+Const cstSubArgs = &quot;Lines&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsFileOpen(&quot;WRITE&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Lines, &quot;Lines&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ For i = 1 To Lines
+ _OutputStream.writeString(_NewLine)
+ Next i
+ _LineNumber = _LineNumber + Lines
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_TextStream.WriteBlankLines
+
+REM -----------------------------------------------------------------------------
+Public Sub WriteLine(Optional ByVal Line As Variant)
+&apos;&apos;&apos; Writes the given line to the output stream. A newline is inserted if relevant
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Line: the line to write, may be empty
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
+&apos;&apos;&apos; FILEOPENMODEERROR File opened in in read mode
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myFile.WriteLine(&quot;Next line&quot;)
+Dim i As Long
+Const cstThisSub = &quot;TextStream.WriteLine&quot;
+Const cstSubArgs = &quot;Line&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsFileOpen(&quot;WRITE&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Line, &quot;Line&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ _OutputStream.writeString(Iif(_LineNumber &gt; 0, _NewLine, &quot;&quot;) &amp; Line)
+ _LineNumber = _LineNumber + 1
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_TextStream.WriteLine
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos;&apos;&apos; Opens file and setup input and/or output streams (ForAppending requires both)
+
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+ &apos; Default newline related to current operating system
+ _NewLine = SF_String.sfNEWLINE
+
+ Set oSfa = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
+
+ &apos; Setup input and/or output streams based on READ/WRITE/APPEND IO modes
+ Select Case _IOMode
+ Case SF_FileSystem.ForReading
+ Set _FileHandler = oSfa.openFileRead(_FileName)
+ Set _InputStream = CreateUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
+ _InputStream.setInputStream(_FileHandler)
+ Case SF_FileSystem.ForWriting
+ &apos; Output file is deleted beforehand
+ If _FileExists Then oSfa.kill(_FileName)
+ Set _FileHandler = oSfa.openFileWrite(_FileName)
+ Set _OutputStream = CreateUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
+ _OutputStream.setOutputStream(_FileHandler)
+ Case SF_FileSystem.ForAppending
+ Set _FileHandler = oSfa.openFileReadWrite(_FileName)
+ Set _InputStream = CreateUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
+ Set _OutputStream = CreateUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
+ _InputStream.setInputStream(_FileHandler)
+ &apos; Position at end of file: Skip and count existing lines
+ _LineNumber = 0
+ Do While Not _InputStream.isEOF()
+ _InputStream.readLine()
+ _LineNumber = _LineNumber + 1
+ Loop
+ _OutputStream.setOutputStream(_FileHandler)
+ End Select
+
+ If _Encoding = &quot;&quot; Then _Encoding = &quot;UTF-8&quot;
+ If Not IsNull(_InputStream) Then _InputStream.setEncoding(_Encoding)
+ If Not IsNull(_OutputStream) Then _OutputStream.setEncoding(_Encoding)
+
+End Sub &apos; ScriptForge.SF_TextStream._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _IsFileOpen(Optional ByVal psMode As String) As Boolean
+&apos;&apos;&apos; Checks if file is open with the right mode (READ or WRITE)
+&apos;&apos;&apos; Raises an exception if the file is not open at all or not in the right mode
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMode: READ or WRITE or zero-length string
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
+&apos;&apos;&apos; FILEOPENMODEERROR File opened in incompatible mode
+
+ _IsFileOpen = False
+ If IsMissing(psMode) Then psMode = &quot;&quot;
+ If IsNull(_InputStream) And IsNull(_OutputStream) Then GoTo CatchNotOpen
+ Select Case psMode
+ Case &quot;READ&quot;
+ If IsNull(_InputStream) Then GoTo CatchOpenMode
+ If _IOMode &lt;&gt; SF_FileSystem.ForReading Then GoTo CatchOpenMode
+ Case &quot;WRITE&quot;
+ If IsNull(_OutputStream) Then GoTo CatchOpenMode
+ If _IOMode = SF_FileSystem.ForReading Then GoTo CatchOpenMode
+ Case Else
+ End Select
+ _IsFileOpen = True
+
+Finally:
+ Exit Function
+CatchNotOpen:
+ SF_Exception.RaiseFatal(FILENOTOPENERROR, FileName)
+ GoTo Finally
+CatchOpenMode:
+ SF_Exception.RaiseFatal(FILEOPENMODEERROR, FileName, IOMode)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_TextStream._IsFileOpen
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String)
+&apos;&apos;&apos; Return the value of the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+
+Dim cstThisSub As String
+Dim cstSubArgs As String
+
+ cstThisSub = &quot;TextStream.get&quot; &amp; psProperty
+ cstSubArgs = &quot;&quot;
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AtEndOfStream&quot;)
+ Select Case _IOMode
+ Case SF_FileSystem.ForReading
+ If IsNull(_InputStream) Then _PropertyGet = True Else _PropertyGet = CBool(_InputStream.isEOF() And Not _ForceBlankLine)
+ Case Else : _PropertyGet = True
+ End Select
+ Case UCase(&quot;Encoding&quot;)
+ _PropertyGet = _Encoding
+ Case UCase(&quot;FileName&quot;)
+ _PropertyGet = SF_FileSystem._ConvertFromUrl(_FileName) &apos; Depends on FileNaming
+ Case UCase(&quot;IOMode&quot;)
+ With SF_FileSystem
+ Select Case _IOMode
+ Case .ForReading : _PropertyGet = &quot;READ&quot;
+ Case .ForWriting : _PropertyGet = &quot;WRITE&quot;
+ Case .ForAppending : _PropertyGet = &quot;APPEND&quot;
+ Case Else : _PropertyGet = &quot;&quot;
+ End Select
+ End With
+ Case UCase(&quot;Line&quot;)
+ _PropertyGet = _LineNumber
+ Case UCase(&quot;NewLine&quot;)
+ _PropertyGet = _NewLine
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_TextStream._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the TextStream instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[TextStream]: File name, IOMode, LineNumber&quot;
+
+ _Repr = &quot;[TextStream]: &quot; &amp; FileName &amp; &quot;,&quot; &amp; IOMode &amp; &quot;,&quot; &amp; CStr(Line)
+
+End Function &apos; ScriptForge.SF_TextStream._Repr
+
+REM ============================================ END OF SCRIPTFORGE.SF_TextStream
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Timer.xba b/wizards/source/scriptforge/SF_Timer.xba
new file mode 100644
index 000000000..2b3286e04
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Timer.xba
@@ -0,0 +1,466 @@
+<?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_Timer" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_Timer
+&apos;&apos;&apos; ========
+&apos;&apos;&apos; Class for management of scripts execution performance
+&apos;&apos;&apos; A Timer measures durations. It can be suspended, resumed, restarted
+&apos;&apos;&apos; Duration properties are expressed in seconds with a precision of 3 decimal digits
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim myTimer As Variant
+&apos;&apos;&apos; myTimer = CreateScriptService(&quot;Timer&quot;)
+&apos;&apos;&apos; myTimer = CreateScriptService(&quot;Timer&quot;, True) &apos; =&gt; To start timer immediately
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_timer.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be &quot;TIMER&quot;
+Private ServiceName As String
+Private _TimerStatus As Integer &apos; inactive, started, suspended or stopped
+Private _StartTime As Double &apos; Moment when timer started, restarted
+Private _EndTime As Double &apos; Moment when timer stopped
+Private _SuspendTime As Double &apos; Moment when timer suspended
+Private _SuspendDuration As Double &apos; Duration of suspended status as a difference of times
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const STATUSINACTIVE = 0
+Private Const STATUSSTARTED = 1
+Private Const STATUSSUSPENDED = 2
+Private Const STATUSSTOPPED = 3
+
+Private Const DSECOND As Double = 1 / (24 * 60 * 60) &apos; Duration of 1 second as compared to 1.0 = 1 day
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;TIMER&quot;
+ ServiceName = &quot;ScriptForge.Timer&quot;
+ _TimerStatus = STATUSINACTIVE
+ _StartTime = 0
+ _EndTime = 0
+ _SuspendTime = 0
+ _SuspendDuration = 0
+End Sub &apos; ScriptForge.SF_Timer Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; ScriptForge.SF_Timer Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Timer Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Public Function Duration() As Double
+&apos;&apos;&apos; Returns the actual (out of suspensions) time elapsed since start or between start and stop
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A Double expressing the duration in seconds
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myTimer.Duration returns 1.234 (1 sec, 234 ms)
+
+ Duration = _PropertyGet(&quot;Duration&quot;)
+
+End Function &apos; ScriptForge.SF_Timer.Duration
+
+REM -----------------------------------------------------------------------------
+Property Get IsStarted() As Boolean
+&apos;&apos;&apos; Returns True if timer is started or suspended
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myTimer.IsStarted
+
+ IsStarted = _PropertyGet(&quot;IsStarted&quot;)
+
+End Property &apos; ScriptForge.SF_Timer.IsStarted
+
+REM -----------------------------------------------------------------------------
+Property Get IsSuspended() As Boolean
+&apos;&apos;&apos; Returns True if timer is started and suspended
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myTimer.IsSuspended
+
+ IsSuspended = _PropertyGet(&quot;IsSuspended&quot;)
+
+End Property &apos; ScriptForge.SF_Timer.IsSuspended
+
+REM -----------------------------------------------------------------------------
+Public Function SuspendDuration() As Double
+&apos;&apos;&apos; Returns the actual time elapsed while suspended since start or between start and stop
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A Double expressing the duration in seconds
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myTimer.SuspendDuration returns 1.234 (1 sec, 234 ms)
+
+ SuspendDuration = _PropertyGet(&quot;SuspendDuration&quot;)
+
+End Function &apos; ScriptForge.SF_Timer.SuspendDuration
+
+REM -----------------------------------------------------------------------------
+Public Function TotalDuration() As Double
+&apos;&apos;&apos; Returns the actual time elapsed (including suspensions) since start or between start and stop
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A Double expressing the duration in seconds
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myTimer.TotalDuration returns 1.234 (1 sec, 234 ms)
+
+ TotalDuration = _PropertyGet(&quot;TotalDuration&quot;)
+
+End Function &apos; ScriptForge.SF_Timer.TotalDuration
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Continue() As Boolean
+&apos;&apos;&apos; Halt suspension of a running timer
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful, False if the timer is not suspended
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myTimer.Continue()
+
+Const cstThisSub = &quot;Timer.Continue&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ Continue = False
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If _TimerStatus = STATUSSUSPENDED Then
+ _TimerStatus = STATUSSTARTED
+ _SuspendDuration = _SuspendDuration + _Now() - _SuspendTime
+ _SuspendTime = 0
+ Continue = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Timer.Continue
+
+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
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myTimer.GetProperty(&quot;Duration&quot;)
+
+Const cstThisSub = &quot;Timer.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Timer.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list or methods of the Timer class as an array
+
+ Methods = Array( _
+ &quot;Continue&quot; _
+ , &quot;Restart&quot; _
+ , &quot;Start&quot; _
+ , &quot;Suspend&quot; _
+ , &quot;Terminate&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Timer.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;Duration&quot; _
+ , &quot;IsStarted&quot; _
+ , &quot;IsSuspended&quot; _
+ , &quot;SuspendDuration&quot; _
+ , &quot;TotalDuration&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Timer.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Restart() As Boolean
+&apos;&apos;&apos; Terminate the timer and restart a new clean timer
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful, False if the timer is inactive
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myTimer.Restart()
+
+Const cstThisSub = &quot;Timer.Restart&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ Restart = False
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If _TimerStatus &lt;&gt; STATUSINACTIVE Then
+ If _TimerStatus &lt;&gt; STATUSSTOPPED Then Terminate()
+ Start()
+ Restart = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Timer.Restart
+
+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;Timer.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; ScriptForge.SF_Timer.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Start() As Boolean
+&apos;&apos;&apos; Start a new clean timer
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful, False if the timer is already started
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myTimer.Start()
+
+Const cstThisSub = &quot;Timer.Start&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ Start = False
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If _TimerStatus = STATUSINACTIVE Or _TimerStatus = STATUSSTOPPED Then
+ _TimerStatus = STATUSSTARTED
+ _StartTime = _Now()
+ _EndTime = 0
+ _SuspendTime = 0
+ _SuspendDuration = 0
+ Start = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Timer.Start
+
+REM -----------------------------------------------------------------------------
+Public Function Suspend() As Boolean
+&apos;&apos;&apos; Suspend a running timer
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful, False if the timer is not started or already suspended
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myTimer.Suspend()
+
+Const cstThisSub = &quot;Timer.Suspend&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ Suspend = False
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If _TimerStatus = STATUSSTARTED Then
+ _TimerStatus = STATUSSUSPENDED
+ _SuspendTime = _Now()
+ Suspend = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Timer.Suspend
+
+REM -----------------------------------------------------------------------------
+Public Function Terminate() As Boolean
+&apos;&apos;&apos; Terminate a running timer
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful, False if the timer is neither started nor suspended
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myTimer.Terminate()
+
+Const cstThisSub = &quot;Timer.Terminate&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ Terminate = False
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED Then
+ If _TimerSTatus = STATUSSUSPENDED Then Continue()
+ _TimerStatus = STATUSSTOPPED
+ _EndTime = _Now()
+ Terminate = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Timer.Terminate
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _Now() As Double
+&apos;&apos;&apos; Returns the current date and time
+&apos;&apos;&apos; Uses the Calc NOW() function to get a higher precision than the usual Basic Now() function
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The actual time as a number
+&apos;&apos;&apos; The integer part represents the date, the decimal part represents the time
+
+ _Now = SF_Session.ExecuteCalcFunction(&quot;NOW&quot;)
+
+End Function &apos; ScriptForge.SF_Timer._Now
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String)
+&apos;&apos;&apos; Return the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+
+Dim dDuration As Double &apos; Computed duration
+Dim cstThisSub As String
+Dim cstSubArgs As String
+
+ cstThisSub = &quot;Timer.get&quot; &amp; psProperty
+ cstSubArgs = &quot;&quot;
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Duration&quot;)
+ Select Case _TimerStatus
+ Case STATUSINACTIVE : dDuration = 0.0
+ Case STATUSSTARTED
+ dDuration = _Now() - _StartTime - _SuspendDuration
+ Case STATUSSUSPENDED
+ dDuration = _SuspendTime - _StartTime - _SuspendDuration
+ Case STATUSSTOPPED
+ dDuration = _EndTime - _StartTime - _SuspendDuration
+ End Select
+ _PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
+ Case UCase(&quot;IsStarted&quot;)
+ _PropertyGet = CBool( _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED )
+ Case UCase(&quot;IsSuspended&quot;)
+ _PropertyGet = CBool( _TimerStatus = STATUSSUSPENDED )
+ Case UCase(&quot;SuspendDuration&quot;)
+ Select Case _TimerStatus
+ Case STATUSINACTIVE : dDuration = 0.0
+ Case STATUSSTARTED, STATUSSTOPPED
+ dDuration = _SuspendDuration
+ Case STATUSSUSPENDED
+ dDuration = _Now() - _SuspendTime + _SuspendDuration
+ End Select
+ _PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
+ Case UCase(&quot;TotalDuration&quot;)
+ Select Case _TimerStatus
+ Case STATUSINACTIVE : dDuration = 0.0
+ Case STATUSSTARTED, STATUSSUSPENDED
+ dDuration = _Now() - _StartTime
+ Case STATUSSTOPPED
+ dDuration = _EndTime - _StartTime
+ End Select
+ _PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Timer._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Timer instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Timer] Duration:xxx.yyy
+
+Const cstTimer = &quot;[Timer] Duration: &quot;
+Const cstMaxLength = 50 &apos; Maximum length for items
+
+ _Repr = cstTimer &amp; Replace(SF_Utils._Repr(Duration), &quot;.&quot;, &quot;&quot;&quot;&quot;)
+
+End Function &apos; ScriptForge.SF_Timer._Repr
+
+REM ============================================ END OF SCRIPTFORGE.SF_TIMER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_UI.xba b/wizards/source/scriptforge/SF_UI.xba
new file mode 100644
index 000000000..c8a7f9a8f
--- /dev/null
+++ b/wizards/source/scriptforge/SF_UI.xba
@@ -0,0 +1,1350 @@
+<?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_UI" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_UI
+&apos;&apos;&apos; =====
+&apos;&apos;&apos; Singleton class module for the identification and the manipulation of the
+&apos;&apos;&apos; different windows composing the whole LibreOffice application:
+&apos;&apos;&apos; - Windows selection
+&apos;&apos;&apos; - Windows moving and resizing
+&apos;&apos;&apos; - Statusbar settings
+&apos;&apos;&apos; - Creation of new windows
+&apos;&apos;&apos; - Access to the underlying &quot;documents&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; WindowName: how to designate a window. It can be either
+&apos;&apos;&apos; a full FileName given in the notation indicated by the current value of SF_FileSystem.FileNaming
+&apos;&apos;&apos; or the last component of the full FileName or even only its BaseName
+&apos;&apos;&apos; or the title of the window
+&apos;&apos;&apos; or, for new documents, something like &quot;Untitled 1&quot;
+&apos;&apos;&apos; or one of the special windows &quot;BASICIDE&quot; and &quot;WELCOMESCREEN&quot;
+&apos;&apos;&apos; The window search is case-sensitive
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim ui As Variant
+&apos;&apos;&apos; ui = CreateScriptService(&quot;UI&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_ui.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Const DOCUMENTERROR = &quot;DOCUMENTERROR&quot; &apos; Requested document was not found
+Const DOCUMENTCREATIONERROR = &quot;DOCUMENTCREATIONERROR&quot; &apos; Incoherent arguments, new document could not be created
+Const DOCUMENTOPENERROR = &quot;DOCUMENTOPENERROR&quot; &apos; Document could not be opened, check the arguments
+Const BASEDOCUMENTOPENERROR = &quot;BASEDOCUMENTOPENERROR&quot; &apos; Id. for Base document
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Calc datasource does not exist
+
+REM ============================================================= PRIVATE MEMBERS
+
+Type Window
+ Component As Object &apos; com.sun.star.lang.XComponent
+ Frame As Object &apos; com.sun.star.comp.framework.Frame
+ WindowName As String &apos; Object Name
+ WindowTitle As String &apos; Only mean to identify new documents
+ WindowFileName As String &apos; URL of file name
+ DocumentType As String &apos; Writer, Calc, ...
+End Type
+
+&apos; The progress/status bar of the active window
+&apos;Private oStatusBar As Object &apos; com.sun.star.task.XStatusIndicator
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos; Special windows
+Const BASICIDE = &quot;BASICIDE&quot;
+Const WELCOMESCREEN = &quot;WELCOMESCREEN&quot;
+
+&apos; Document types (only if not 1 of the special windows)
+Const BASEDOCUMENT = &quot;Base&quot;
+Const CALCDOCUMENT = &quot;Calc&quot;
+Const DRAWDOCUMENT = &quot;Draw&quot;
+Const IMPRESSDOCUMENT = &quot;Impress&quot;
+Const MATHDOCUMENT = &quot;Math&quot;
+Const WRITERDOCUMENT = &quot;Writer&quot;
+
+&apos; Window subtypes - Not supported yet
+Const BASETABLE = &quot;BASETABLE&quot;
+Const BASEQUERY = &quot;BASEQUERY&quot;
+Const BASEREPORT = &quot;BASEREPORT&quot;
+Const BASEDIAGRAM = &quot;BASEDIAGRAM&quot;
+
+&apos; Macro execution modes
+Const cstMACROEXECNORMAL = 0 &apos; Default, execution depends on user configuration and choice
+Const cstMACROEXECNEVER = 1 &apos; Macros are not executed
+Const cstMACROEXECALWAYS = 2 &apos; Macros are always executed
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_UI Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Public Function ActiveWindow() As String
+&apos;&apos;&apos; Returns a valid WindowName for the currently active window
+&apos;&apos;&apos; When &quot;&quot; is returned, the window could not be identified
+
+Dim vWindow As Window &apos; A component
+Dim oComp As Object &apos; com.sun.star.lang.XComponent
+
+ Set oComp = StarDesktop.CurrentComponent
+ If Not IsNull(oComp) Then
+ vWindow = SF_UI._IdentifyWindow(oComp)
+ With vWindow
+ If Len(.WindowFileName) &gt; 0 Then
+ ActiveWindow = SF_FileSystem._ConvertFromUrl(.WindowFileName)
+ ElseIf Len(.WindowName) &gt; 0 Then
+ ActiveWindow = .WindowName
+ ElseIf Len(.WindowTitle) &gt; 0 Then
+ ActiveWindow = .WindowTitle
+ Else
+ ActiveWindow = &quot;&quot;
+ End If
+ End With
+ End If
+
+End Function &apos; ScriptForge.SF_UI.ActiveWindow
+
+REM -----------------------------------------------------------------------------
+Property Get Height() As Long
+&apos;&apos;&apos; Returns the height of the active window
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+ Set oPosSize = SF_UI._PosSize()
+ If Not IsNull(oPosSize) Then Height = oPosSize.Height Else Height = -1
+End Property &apos; ScriptForge.SF_UI.Height
+
+REM -----------------------------------------------------------------------------
+Property Get MACROEXECALWAYS As Integer
+&apos;&apos;&apos; Macros are always executed
+ MACROEXECALWAYS = cstMACROEXECALWAYS
+End Property &apos; ScriptForge.SF_UI.MACROEXECALWAYS
+
+REM -----------------------------------------------------------------------------
+Property Get MACROEXECNEVER As Integer
+&apos;&apos;&apos; Macros are not executed
+ MACROEXECNEVER = cstMACROEXECNEVER
+End Property &apos; ScriptForge.SF_UI.MACROEXECNEVER
+
+REM -----------------------------------------------------------------------------
+Property Get MACROEXECNORMAL As Integer
+&apos;&apos;&apos; Default, execution depends on user configuration and choice
+ MACROEXECNORMAL = cstMACROEXECNORMAL
+End Property &apos; ScriptForge.SF_UI.MACROEXECNORMAL
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_UI&quot;
+End Property &apos; ScriptForge.SF_UI.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.UI&quot;
+End Property &apos; ScriptForge.SF_UI.ServiceName
+
+REM -----------------------------------------------------------------------------
+Property Get Width() As Long
+&apos;&apos;&apos; Returns the width of the active window
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+ Set oPosSize = SF_UI._PosSize()
+ If Not IsNull(oPosSize) Then Width = oPosSize.Width Else Width = -1
+End Property &apos; ScriptForge.SF_UI.Width
+
+REM -----------------------------------------------------------------------------
+Property Get X() As Long
+&apos;&apos;&apos; Returns the X coordinate of the active window
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+ Set oPosSize = SF_UI._PosSize()
+ If Not IsNull(oPosSize) Then X = oPosSize.X Else X = -1
+End Property &apos; ScriptForge.SF_UI.X
+
+REM -----------------------------------------------------------------------------
+Property Get Y() As Long
+&apos;&apos;&apos; Returns the Y coordinate of the active window
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+ Set oPosSize = SF_UI._PosSize()
+ If Not IsNull(oPosSize) Then Y = oPosSize.Y Else Y = -1
+End Property &apos; ScriptForge.SF_UI.Y
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate(Optional ByVal WindowName As Variant) As Boolean
+&apos;&apos;&apos; Make the specified window active
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; WindowName: see definitions
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the given window is found and can be activated
+&apos;&apos;&apos; There is no change in the actual user interface if no window matches the selection
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; ui.Activate(&quot;C:\Me\My file.odt&quot;)
+
+Dim bActivate As Boolean &apos; Return value
+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 oContainer As Object &apos; com.sun.star.awt.XWindow
+Const cstThisSub = &quot;UI.Activate&quot;
+Const cstSubArgs = &quot;WindowName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bActivate = False
+
+Check:
+ If IsMissing(WindowName) Or IsEmpty(WindowName) Then WindowName = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(WindowName, &quot;WindowName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oEnum = StarDesktop.Components().createEnumeration
+ Do While oEnum.hasMoreElements
+ Set oComp = oEnum.nextElement
+ vWindow = SF_UI._IdentifyWindow(oComp)
+ With vWindow
+ &apos; Does the current window match the arguments ?
+ If (Len(.WindowFileName) &gt; 0 And .WindowFileName = SF_FileSystem._ConvertToUrl(WindowName)) _
+ Or (Len(.WindowName) &gt; 0 And .WindowName = WindowName) _
+ Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = WindowName) Then
+ Set oContainer = vWindow.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
+ Exit Do
+ End If
+ End With
+ Loop
+
+Finally:
+ Activate = bActivate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.Activate
+
+REM -----------------------------------------------------------------------------
+Public Function CreateBaseDocument(Optional ByVal FileName As Variant _
+ , Optional ByVal EmbeddedDatabase As Variant _
+ , Optional ByVal RegistrationName As Variant _
+ , Optional ByVal CalcFileName As Variant _
+ ) As Object
+&apos;&apos;&apos; Create a new LibreOffice Base document embedding an empty database of the given type
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to create. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; If the file already exists, it is overwritten without warning
+&apos;&apos;&apos; EmbeddedDatabase: either &quot;HSQLDB&quot; (default) or &quot;FIREBIRD&quot; or &quot;CALC&quot;
+&apos;&apos;&apos; RegistrationName: the name used to store the new database in the databases register
+&apos;&apos;&apos; If &quot;&quot; (default), no registration takes place
+&apos;&apos;&apos; If the name already exists it is overwritten without warning
+&apos;&apos;&apos; CalcFileName: only when EmbedddedDatabase = &quot;CALC&quot;, the name of the file containing the tables as Calc sheets
+&apos;&apos;&apos; The name of the file must be given in SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; The file must exist
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SFDocuments.SF_Document object or one of its subclasses
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; UNKNOWNFILEERROR Calc datasource does not exist
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myBase As Object, myCalcBase As Object
+&apos;&apos;&apos; Set myBase = ui.CreateBaseDocument(&quot;C:\Databases\MyBaseFile.odb&quot;, &quot;FIREBIRD&quot;)
+&apos;&apos;&apos; Set myCalcBase = ui.CreateBaseDocument(&quot;C:\Databases\MyCalcBaseFile.odb&quot;, &quot;CALC&quot;, , &quot;C:\Databases\MyCalcFile.ods&quot;)
+
+Dim oCreate As Variant &apos; Return value
+Dim oDBContext As Object &apos; com.sun.star.sdb.DatabaseContext
+Dim oDatabase As Object &apos; com.sun.star.comp.dba.ODatabaseSource
+Dim oComp As Object &apos; Loaded component com.sun.star.lang.XComponent
+Dim sFileName As String &apos; Alias of FileName
+Dim FSO As Object &apos; Alias for FileSystem service
+Const cstDocType = &quot;private:factory/s&quot;
+Const cstThisSub = &quot;UI.CreateBaseDocument&quot;
+Const cstSubArgs = &quot;FileName, [EmbeddedDatabase=&quot;&quot;HSQLDB&quot;&quot;|&quot;&quot;FIREBIRD&quot;&quot;|&quot;&quot;CALC&quot;&quot;], [RegistrationName=&quot;&quot;&quot;&quot;], [CalcFileName]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oCreate = Nothing
+ Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+
+Check:
+ If IsMissing(EmbeddedDatabase) Or IsEmpty(EmbeddedDatabase) Then EmbeddedDatabase = &quot;HSQLDB&quot;
+ If IsMissing(RegistrationName) Or IsEmpty(RegistrationName) Then RegistrationName = &quot;&quot;
+ If IsMissing(CalcFileName) Or IsEmpty(CalcFileName) Then CalcFileName = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(EmbeddedDatabase, &quot;EmbeddedDatabase&quot;, V_STRING, Array(&quot;CALC&quot;, &quot;HSQLDB&quot;, &quot;FIREBIRD&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(RegistrationName, &quot;RegistrationName&quot;, V_STRING) Then GoTo Finally
+ If UCase(EmbeddedDatabase) = &quot;CALC&quot; Then
+ If Not SF_Utils._ValidateFile(CalcFileName, &quot;CalcFileName&quot;) Then GoTo Finally
+ If Not FSO.FileExists(CalcFileName) Then GoTo CatchNotExists
+ End If
+ End If
+
+Try:
+ Set oDBContext = SF_Utils._GetUNOService(&quot;DatabaseContext&quot;)
+ With oDBContext
+ Set oDatabase = .createInstance()
+ &apos; Build the url link to the database
+ Select Case UCase(EmbeddedDatabase)
+ Case &quot;HSQLDB&quot;, &quot;FIREBIRD&quot;
+ oDatabase.URL = &quot;sdbc:embedded:&quot; &amp; LCase(EmbeddedDatabase)
+ Case &quot;CALC&quot;
+ oDatabase.URL = &quot;sdbc:calc:&quot; &amp; FSO._ConvertToUrl(CalcFileName)
+ End Select
+ &apos; Create empty Base document
+ sFileName = FSO._ConvertToUrl(FileName)
+ &apos; An existing file is overwritten without warning
+ If FSO.FileExists(FileName) Then FSO.DeleteFile(FileName)
+ If FSO.FileExists(FileName &amp; &quot;.lck&quot;) Then FSO.DeleteFile(FileName &amp; &quot;.lck&quot;)
+ oDatabase.DatabaseDocument.storeAsURL(sFileName, Array(SF_Utils._MakePropertyValue(&quot;Overwrite&quot;, True)))
+ &apos; Register database if requested
+ If Len(RegistrationName) &gt; 0 Then
+ If .hasRegisteredDatabase(RegistrationName) Then
+ .changeDatabaseLocation(RegistrationName, sFileName)
+ Else
+ .registerDatabaseLocation(RegistrationName, sFileName)
+ End If
+ End If
+ End With
+
+ Set oCreate = OpenBaseDocument(FileName)
+
+Finally:
+ Set CreateBaseDocument = oCreate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;CalcFileName&quot;, CalcFileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.CreateBaseDocument
+
+REM -----------------------------------------------------------------------------
+Public Function CreateDocument(Optional ByVal DocumentType As Variant _
+ , Optional ByVal TemplateFile As Variant _
+ , Optional ByVal Hidden As Variant _
+ ) As Object
+&apos;&apos;&apos; Create a new LibreOffice document of a given type or based on a given template
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DocumentType: &quot;Calc&quot;, &quot;Writer&quot;, etc. If absent, a TemplateFile must be given
+&apos;&apos;&apos; TemplateFile: the full FileName of the template to build the new document on
+&apos;&apos;&apos; If the file does not exist, the argument is ignored
+&apos;&apos;&apos; The &quot;FileSystem&quot; service provides the TemplatesFolder and UserTemplatesFolder
+&apos;&apos;&apos; properties to help to build the argument
+&apos;&apos;&apos; Hidden: if True, open in the background (default = False)
+&apos;&apos;&apos; To use with caution: activation or closure can only happen programmatically
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SFDocuments.SF_Document object or one of its subclasses
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTCREATIONERROR Wrong arguments
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myDoc1 As Object, myDoc2 As Object, FSO As Object
+&apos;&apos;&apos; Set myDoc1 = ui.CreateDocument(&quot;Calc&quot;)
+&apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+&apos;&apos;&apos; Set myDoc2 = ui.CreateDocument(, FSO.BuildPath(FSO.TemplatesFolder, &quot;personal/CV.ott&quot;))
+
+Dim oCreate As Variant &apos; Return value
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim bTemplateExists As Boolean &apos; True if TemplateFile is valid
+Dim sNew As String &apos; File url
+Dim oComp As Object &apos; Loaded component com.sun.star.lang.XComponent
+Const cstDocType = &quot;private:factory/s&quot;
+Const cstThisSub = &quot;UI.CreateDocument&quot;
+Const cstSubArgs = &quot;[DocumentType=&quot;&quot;&quot;&quot;], [TemplateFile=&quot;&quot;&quot;&quot;], [Hidden=False]&quot;
+
+&apos;&gt;&gt;&gt; If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oCreate = Nothing
+
+Check:
+ If IsMissing(DocumentType) Or IsEmpty(DocumentType) Then DocumentType = &quot;&quot;
+ If IsMissing(TemplateFile) Or IsEmpty(TemplateFile) Then TemplateFile = &quot;&quot;
+ If IsMissing(Hidden) Or IsEmpty(Hidden) Then Hidden = False
+
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(DocumentType, &quot;DocumentType&quot;, V_STRING _
+ , Array(&quot;&quot;, BASEDOCUMENT, CALCDOCUMENT, DRAWDOCUMENT _
+ , IMPRESSDOCUMENT, MATHDOCUMENT, WRITERDOCUMENT)) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(TemplateFile, &quot;TemplateFile&quot;, , True) Then GoTo Finally
+ If Not SF_Utils._Validate(Hidden, &quot;Hidden&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+ If Len(DocumentType) + Len(TemplateFile) = 0 Then GoTo CatchError
+ If Len(TemplateFile) &gt; 0 Then bTemplateExists = SF_FileSystem.FileExists(TemplateFile) Else bTemplateExists = False
+ If Len(DocumentType) = 0 Then
+ If Not bTemplateExists Then GoTo CatchError
+ End If
+
+Try:
+ If bTemplateExists Then sNew = SF_FileSystem._ConvertToUrl(TemplateFile) Else sNew = cstDocType &amp; LCase(DocumentType)
+ vProperties = Array( _
+ SF_Utils._MakePropertyValue(&quot;AsTemplate&quot;, bTemplateExists) _
+ , SF_Utils._MakePropertyValue(&quot;Hidden&quot;, Hidden) _
+ )
+ Set oComp = StarDesktop.loadComponentFromURL(sNew, &quot;_blank&quot;, 0, vProperties)
+ If Not IsNull(oComp) Then Set oCreate = CreateScriptService(&quot;SFDocuments.Document&quot;, oComp)
+
+Finally:
+ Set CreateDocument = oCreate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ SF_Exception.RaiseFatal(DOCUMENTCREATIONERROR, &quot;DocumentType&quot;, DocumentType, &quot;TemplateFile&quot;, TemplateFile)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.CreateDocument
+
+REM -----------------------------------------------------------------------------
+Public Function Documents() As Variant
+&apos;&apos;&apos; Returns the list of the currently open documents. Special windows are ignored.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based 1D array of filenames (in SF_FileSystem.FileNaming notation)
+&apos;&apos;&apos; or of window titles for unsaved documents
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim vDocs As Variant, sDoc As String
+&apos;&apos;&apos; vDocs = ui.Documents()
+&apos;&apos;&apos; For each sDoc In vDocs
+&apos;&apos;&apos; ...
+
+Dim vDocuments As Variant &apos; Return value
+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
+Const cstThisSub = &quot;UI.Documents&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vDocuments = Array()
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ Set oEnum = StarDesktop.Components().createEnumeration
+ Do While oEnum.hasMoreElements
+ Set oComp = oEnum.nextElement
+ vWindow = SF_UI._IdentifyWindow(oComp)
+ With vWindow
+ If Len(.WindowFileName) &gt; 0 Then
+ vDocuments = SF_Array.Append(vDocuments, SF_FileSystem._ConvertFromUrl(.WindowFileName))
+ ElseIf Len(.WindowTitle) &gt; 0 Then
+ vDocuments = SF_Array.Append(vDocuments, .WindowTitle)
+ End If
+ End With
+ Loop
+
+Finally:
+ Documents = vDocuments
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.Documents
+
+REM -----------------------------------------------------------------------------
+Public Function GetDocument(Optional ByVal WindowName As Variant) As Variant
+&apos;&apos;&apos; Returns a SFDocuments.Document object referring to the active window or the given window
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; WindowName: when a string, see definitions. If absent the active window is considered.
+&apos;&apos;&apos; when an object, must be a UNO object of types
+&apos;&apos;&apos; com.sun.star.lang.XComponent or com.sun.star.comp.dba.ODatabaseDocument
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTERROR The targeted window could not be found
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim oDoc As Object
+&apos;&apos;&apos; Set oDoc = ui.GetDocument &apos; or Set oDoc = ui.GetDocument(ThisComponent)
+&apos;&apos;&apos; oDoc.Save()
+
+Dim oDocument As Object &apos; Return value
+Const cstThisSub = &quot;UI.GetDocument&quot;
+Const cstSubArgs = &quot;[WindowName]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oDocument = Nothing
+
+Check:
+ If IsMissing(WindowName) Or IsEmpty(WindowName) Then WindowName = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(WindowName, &quot;WindowName&quot;, Array(V_STRING, V_OBJECT)) Then GoTo Finally
+ If VarType(WindowName) = V_STRING Then
+ If Not SF_Utils._ValidateFile(WindowName, &quot;WindowName&quot;, , True) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ Set oDocument = SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, WindowName)
+ If IsNull(oDocument) Then GoTo CatchDeliver
+
+Finally:
+ Set GetDocument = oDocument
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchDeliver:
+ SF_Exception.RaiseFatal(DOCUMENTERROR, &quot;WindowName&quot;, WindowName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.GetDocument
+
+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;UI.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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 &quot;ACTIVEWINDOW&quot; : GetProperty = ActiveWindow()
+ Case &quot;HEIGHT&quot; : GetProperty = SF_UI.Height
+ Case &quot;WIDTH&quot; : GetProperty = SF_UI.Width
+ Case &quot;X&quot; : GetProperty = SF_UI.X
+ Case &quot;Y&quot; : GetProperty = SF_UI.Y
+
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Sub Maximize(Optional ByVal WindowName As Variant)
+&apos;&apos;&apos; Maximizes the active window or the given window
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; WindowName: see definitions. If absent the active window is considered
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; ui.Maximize
+&apos;&apos;&apos; ...
+
+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 oContainer As Object &apos; com.sun.star.awt.XWindow
+Dim bFound As Boolean &apos; True if window found
+Const cstThisSub = &quot;UI.Maximize&quot;
+Const cstSubArgs = &quot;[WindowName]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(WindowName) Or IsEmpty(WindowName) Then WindowName = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(WindowName, &quot;WindowName&quot;, , True) Then GoTo Finally
+ End If
+
+Try:
+ bFound = False
+ If Len(WindowName) &gt; 0 Then
+ Set oEnum = StarDesktop.Components().createEnumeration
+ Do While oEnum.hasMoreElements And Not bFound
+ Set oComp = oEnum.nextElement
+ vWindow = SF_UI._IdentifyWindow(oComp)
+ With vWindow
+ &apos; Does the current window match the arguments ?
+ If (Len(.WindowFileName) &gt; 0 And .WindowFileName = SF_FileSystem.ConvertToUrl(WindowName)) _
+ Or (Len(.WindowName) &gt; 0 And .WindowName = WindowName) _
+ Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = WindowName) Then bFound = True
+ End With
+ Loop
+ Else
+ vWindow = SF_UI._IdentifyWindow(StarDesktop.CurrentComponent)
+ bFound = True
+ End If
+
+ If bFound Then
+ Set oContainer = vWindow.Frame.ContainerWindow
+ oContainer.IsMaximized = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_UI.Maximize
+
+REM -----------------------------------------------------------------------------
+Public Sub Minimize(Optional ByVal WindowName As Variant)
+&apos;&apos;&apos; Minimizes the current window or the given window
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; WindowName: see definitions. If absent the current window is considered
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; ui.Minimize(&quot;myFile.ods&quot;)
+&apos;&apos;&apos; ...
+
+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 oContainer As Object &apos; com.sun.star.awt.XWindow
+Dim bFound As Boolean &apos; True if window found
+Const cstThisSub = &quot;UI.Minimize&quot;
+Const cstSubArgs = &quot;[WindowName]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(WindowName) Or IsEmpty(WindowName) Then WindowName = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(WindowName, &quot;WindowName&quot;, , True) Then GoTo Finally
+ End If
+
+Try:
+ bFound = False
+ If Len(WindowName) &gt; 0 Then
+ Set oEnum = StarDesktop.Components().createEnumeration
+ Do While oEnum.hasMoreElements And Not bFound
+ Set oComp = oEnum.nextElement
+ vWindow = SF_UI._IdentifyWindow(oComp)
+ With vWindow
+ &apos; Does the current window match the arguments ?
+ If (Len(.WindowFileName) &gt; 0 And .WindowFileName = SF_FileSystem.ConvertToUrl(WindowName)) _
+ Or (Len(.WindowName) &gt; 0 And .WindowName = WindowName) _
+ Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = WindowName) Then bFound = True
+ End With
+ Loop
+ Else
+ vWindow = SF_UI._IdentifyWindow(StarDesktop.CurrentComponent)
+ bFound = True
+ End If
+
+ If bFound Then
+ Set oContainer = vWindow.Frame.ContainerWindow
+ oContainer.IsMinimized = True
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_UI.Minimize
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the UI service as an array
+
+ Methods = Array(&quot;Activate&quot; _
+ , &quot;CreateBaseDocument&quot; _
+ , &quot;CreateDocument&quot; _
+ , &quot;Documents&quot; _
+ , &quot;GetDocument&quot; _
+ , &quot;Maximize&quot; _
+ , &quot;Minimize&quot; _
+ , &quot;OpenBaseDocument&quot; _
+ , &quot;OpenDocument&quot; _
+ , &quot;Resize&quot; _
+ , &quot;RunCommand&quot; _
+ , &quot;SetStatusbar&quot; _
+ , &quot;ShowProgressBar&quot; _
+ , &quot;WindowExists&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_UI.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function OpenBaseDocument(Optional ByVal FileName As Variant _
+ , Optional ByVal RegistrationName As Variant _
+ , Optional ByVal MacroExecution As Variant _
+ ) As Object
+&apos;&apos;&apos; Open an existing LibreOffice Base document and return a SFDocuments.Document object
+&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; MacroExecution: one of the MACROEXECxxx constants
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SFDocuments.SF_Base object
+&apos;&apos;&apos; Null if the opening failed, including when due to a user decision
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; BASEDOCUMENTOPENERROR Wrong arguments
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim mBasec As Object, FSO As Object
+&apos;&apos;&apos; Set myBase = ui.OpenBaseDocument(&quot;C:\Temp\myDB.odb&quot;, MacroExecution := ui.MACROEXECNEVER)
+
+Dim oOpen As Variant &apos; Return value
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim oDBContext As Object &apos; com.sun.star.sdb.DatabaseContext
+Dim oComp As Object &apos; Loaded component com.sun.star.lang.XComponent
+Dim sFile As String &apos; Alias for FileName
+Dim iMacro As Integer &apos; Alias for MacroExecution
+Const cstThisSub = &quot;UI.OpenBaseDocument&quot;
+Const cstSubArgs = &quot;[FileName=&quot;&quot;&quot;&quot;], [RegistrationName=&quot;&quot;&quot;&quot;], [MacroExecution=0|1|2]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oOpen = Nothing
+
+Check:
+ If IsMissing(FileName) Or IsEmpty(FileName) Then FileName = &quot;&quot;
+ If IsMissing(RegistrationName) Or IsEmpty(RegistrationName) Then RegistrationName = &quot;&quot;
+ If IsMissing(MacroExecution) Or IsEmpty(MacroExecution) Then MacroExecution = MACROEXECNORMAL
+
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, , True) Then GoTo Finally
+ If Not SF_Utils._Validate(RegistrationName, &quot;RegistrationName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(MacroExecution, &quot;MacroExecution&quot;, V_NUMERIC _
+ , Array(MACROEXECNORMAL, MACROEXECNEVER, MACROEXECALWAYS)) 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 = SF_Utils._GetUNOService(&quot;DatabaseContext&quot;)
+ If Not oDBContext.hasRegisteredDatabase(RegistrationName) Then GoTo CatchError
+ FileName = SF_FileSystem._ConvertFromUrl(oDBContext.getDatabaseLocation(RegistrationName))
+ End If
+ If Not SF_FileSystem.FileExists(FileName) Then GoTo CatchError
+
+Try:
+ With com.sun.star.document.MacroExecMode
+ Select Case MacroExecution
+ Case 0 : iMacro = .USE_CONFIG
+ Case 1 : iMacro = .NEVER_EXECUTE
+ Case 2 : iMacro = .ALWAYS_EXECUTE_NO_WARN
+ End Select
+ End With
+
+ vProperties = Array(SF_Utils._MakePropertyValue(&quot;MacroExecutionMode&quot;, iMacro))
+
+ sFile = SF_FileSystem._ConvertToUrl(FileName)
+ Set oComp = StarDesktop.loadComponentFromURL(sFile, &quot;_blank&quot;, 0, vProperties)
+ If Not IsNull(oComp) Then Set oOpen = CreateScriptService(&quot;SFDocuments.Document&quot;, oComp)
+
+Finally:
+ Set OpenBaseDocument = oOpen
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ SF_Exception.RaiseFatal(BASEDOCUMENTOPENERROR, &quot;FileName&quot;, FileName, &quot;RegistrationName&quot;, RegistrationName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.OpenBaseDocument
+
+REM -----------------------------------------------------------------------------
+Public Function OpenDocument(Optional ByVal FileName As Variant _
+ , Optional ByVal Password As Variant _
+ , Optional ByVal ReadOnly As Variant _
+ , Optional ByVal Hidden As Variant _
+ , Optional ByVal MacroExecution As Variant _
+ , Optional ByVal FilterName As Variant _
+ , Optional ByVal FilterOptions As Variant _
+ ) As Object
+&apos;&apos;&apos; Open an existing LibreOffice document with the given options
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; Password: To use when the document is protected
+&apos;&apos;&apos; If wrong or absent while the document is protected, the user will be prompted to enter a password
+&apos;&apos;&apos; ReadOnly: Default = False
+&apos;&apos;&apos; Hidden: if True, open in the background (default = False)
+&apos;&apos;&apos; To use with caution: activation or closure can only happen programmatically
+&apos;&apos;&apos; MacroExecution: one of the MACROEXECxxx constants
+&apos;&apos;&apos; FilterName: the name of a filter that should be used for loading 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; A SFDocuments.SF_Document object or one of its subclasses
+&apos;&apos;&apos; Null if the opening failed, including when due to a user decision
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTOPENERROR Wrong arguments
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myDoc As Object, FSO As Object
+&apos;&apos;&apos; Set myDoc = ui.OpenDocument(&quot;C:\Temp\myFile.odt&quot;, MacroExecution := ui.MACROEXECNEVER)
+
+Dim oOpen As Variant &apos; Return value
+Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim oComp As Object &apos; Loaded component com.sun.star.lang.XComponent
+Dim sFile As String &apos; Alias for FileName
+Dim iMacro As Integer &apos; Alias for MacroExecution
+Const cstThisSub = &quot;UI.OpenDocument&quot;
+Const cstSubArgs = &quot;FileName, [Password=&quot;&quot;&quot;&quot;], [ReadOnly=False], [Hidden=False], [MacroExecution=0|1|2], [FilterName=&quot;&quot;&quot;&quot;], [FilterOptions=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oOpen = Nothing
+
+Check:
+ If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
+ If IsMissing(ReadOnly) Or IsEmpty(ReadOnly) Then ReadOnly = False
+ If IsMissing(Hidden) Or IsEmpty(Hidden) Then Hidden = False
+ If IsMissing(MacroExecution) Or IsEmpty(MacroExecution) Then MacroExecution = MACROEXECNORMAL
+ If IsMissing(FilterName) Or IsEmpty(FilterName) Then FilterName = &quot;&quot;
+ If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = &quot;&quot;
+
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(ReadOnly, &quot;ReadOnly&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Hidden, &quot;Hidden&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(MacroExecution, &quot;MacroExecution&quot;, V_NUMERIC _
+ , Array(MACROEXECNORMAL, MACROEXECNEVER, MACROEXECALWAYS)) 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 the existence of FileName and FilterName
+ If Not SF_FileSystem.FileExists(FileName) Then GoTo CatchError
+ If Len(FilterName) &gt; 0 Then
+ Set oFilterFactory = SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
+ If Not oFilterFactory.hasByName(FilterName) Then GoTo CatchError
+ End If
+
+Try:
+ With com.sun.star.document.MacroExecMode
+ Select Case MacroExecution
+ Case 0 : iMacro = .USE_CONFIG
+ Case 1 : iMacro = .NEVER_EXECUTE
+ Case 2 : iMacro = .ALWAYS_EXECUTE_NO_WARN
+ End Select
+ End With
+
+ vProperties = Array( _
+ SF_Utils._MakePropertyValue(&quot;ReadOnly&quot;, ReadOnly) _
+ , SF_Utils._MakePropertyValue(&quot;Hidden&quot;, Hidden) _
+ , SF_Utils._MakePropertyValue(&quot;MacroExecutionMode&quot;, iMacro) _
+ , SF_Utils._MakePropertyValue(&quot;FilterName&quot;, FilterName) _
+ , 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 = SF_Array.Append(vProperties, SF_Utils._MakePropertyValue(&quot;Password&quot;, Password))
+ End If
+
+ sFile = SF_FileSystem._ConvertToUrl(FileName)
+ Set oComp = StarDesktop.loadComponentFromURL(sFile, &quot;_blank&quot;, 0, vProperties)
+ If Not IsNull(oComp) Then Set oOpen = CreateScriptService(&quot;SFDocuments.Document&quot;, oComp)
+
+Finally:
+ Set OpenDocument = oOpen
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ SF_Exception.RaiseFatal(DOCUMENTOPENERROR, &quot;FileName&quot;, FileName, &quot;Password&quot;, Password, &quot;FilterName&quot;, FilterName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.OpenDocument
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer class as an array
+
+ Properties = Array( _
+ &quot;ActiveWindow&quot; _
+ , &quot;Height&quot; _
+ , &quot;Width&quot; _
+ , &quot;X&quot; _
+ , &quot;Y&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_UI.Properties
+
+REM -----------------------------------------------------------------------------
+Public Sub Resize(Optional ByVal Left As Variant _
+ , Optional ByVal Top As Variant _
+ , Optional ByVal Width As Variant _
+ , Optional ByVal Height As Variant _
+ )
+&apos;&apos;&apos; Resizes and/or moves the active window. Negative arguments are ignored.
+&apos;&apos;&apos; If the window was minimized or without arguments, it is restored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Left, Top: Distances from top and left edges of the screen
+&apos;&apos;&apos; Width, Height: Dimensions of the window
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; ui.Resize(10,,500) &apos; Top and Height are unchanged
+&apos;&apos;&apos; ...
+
+Dim vWindow As Window &apos; A single component
+Dim oContainer As Object &apos; com.sun.star.awt.XWindow
+Dim iPosSize As Integer &apos; Computes which of the 4 arguments should be considered
+Const cstThisSub = &quot;UI.Resize&quot;
+Const cstSubArgs = &quot;[Left], [Top], [Width], [Height]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Left) Or IsEmpty(Left) Then Left = -1
+ If IsMissing(Top) Or IsEmpty(Top) Then Top = -1
+ If IsMissing(Width) Or IsEmpty(Width) Then Width = -1
+ If IsMissing(Height) Or IsEmpty(Height) Then Height = -1
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Left, &quot;Left&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(Top, &quot;Top&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(Width, &quot;Width&quot;, V_NUMERIC) Then GoTo Finally
+ If Not SF_Utils._Validate(Height, &quot;Height&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ vWindow = SF_UI._IdentifyWindow(StarDesktop.CurrentComponent)
+ If Not IsNull(vWindow.Frame) Then
+ Set oContainer = vWindow.Frame.ContainerWindow
+ iPosSize = 0
+ If Left &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.X
+ If Top &gt;= 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.Y
+ If Width &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.WIDTH
+ If Height &gt; 0 Then iPosSize = iPosSize + com.sun.star.awt.PosSize.HEIGHT
+ With oContainer
+ .IsMaximized = False
+ .IsMinimized = False
+ .setPosSize(Left, Top, Width, Height, iPosSize)
+ End With
+ End If
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_UI.Resize
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant _
+ , ParamArray Args As Variant _
+ )
+&apos;&apos;&apos; Run on the current window the given menu command. The command is executed with or without arguments
+&apos;&apos;&apos; A few typical commands:
+&apos;&apos;&apos; About, Delete, Edit, Undo, Copy, Paste, ...
+&apos;&apos;&apos; Dozens can be found on next page: https://wiki.documentfoundation.org/Development/DispatchCommands
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Command: Case-sensitive. The command itself is not checked.
+&apos;&apos;&apos; If the command does not contain the &quot;.uno:&quot; prefix, it is added.
+&apos;&apos;&apos; If nothing happens, then the command is probably wrong
+&apos;&apos;&apos; Args: Pairs of arguments name (string), value (any)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; ui.RunCommand(&quot;BasicIDEAppear&quot;, _
+&apos;&apos;&apos; &quot;Document&quot;, &quot;LibreOffice Macros &amp; Dialogs&quot;, _
+&apos;&apos;&apos; &quot;LibName&quot;, &quot;ScriptForge&quot;, _
+&apos;&apos;&apos; &quot;Name&quot;, &quot;SF_Session&quot;, _
+&apos;&apos;&apos; &quot;Line&quot;, 600)
+
+Dim oDispatch &apos; com.sun.star.frame.DispatchHelper
+Dim vProps As Variant &apos; Array of PropertyValues
+Dim vValue As Variant &apos; A single value argument
+Dim sCommand As String &apos; Alias of Command
+Dim i As Long
+Const cstPrefix = &quot;.uno:&quot;
+
+Const cstThisSub = &quot;UI.RunCommand&quot;
+Const cstSubArgs = &quot;Command, [arg0Name, arg0Value], [arg1Name, arg1Value], ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._ValidateArray(Args, &quot;Args&quot;, 1) Then GoTo Finally
+ For i = 0 To UBound(Args) - 1 Step 2
+ If Not SF_Utils._Validate(Args(i), &quot;Arg&quot; &amp; CStr(i/2) &amp; &quot;Name&quot;, V_STRING) Then GoTo Finally
+ Next i
+ End If
+
+Try:
+ &apos; Build array of property values
+ vProps = Array()
+ For i = 0 To UBound(Args) - 1 Step 2
+ If IsEmpty(Args(i + 1)) Then vValue = Null Else vValue = Args(i + 1)
+ vProps = SF_Array.Append(vProps, SF_Utils._MakePropertyValue(Args(i), vValue))
+ Next i
+ Set oDispatch = SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
+ If SF_String.StartsWith(Command, cstPrefix) Then sCommand = Command Else sCommand = cstPrefix &amp; Command
+ oDispatch.executeDispatch(StarDesktop.ActiveFrame, sCommand, &quot;&quot;, 0, vProps)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_UI.RunCommand
+
+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;UI.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; ScriptForge.SF_UI.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Sub SetStatusbar(Optional ByVal Text As Variant _
+ , Optional ByVal Percentage As Variant _
+ )
+&apos;&apos;&apos; Display a text and a progressbar in the status bar of the active window
+&apos;&apos;&apos; Any subsequent calls in the same macro run refer to the same status bar of the same window,
+&apos;&apos;&apos; even if the window is not active anymore
+&apos;&apos;&apos; A call without arguments resets the status bar to its normal state.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Text: the optional text to be displayed before the progress bar
+&apos;&apos;&apos; Percentage: the optional degree of progress between 0 and 100
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim i As Integer
+&apos;&apos;&apos; For i = 0 To 100
+&apos;&apos;&apos; ui.SetStatusbar(&quot;Progress ...&quot;, i)
+&apos;&apos;&apos; Wait 50
+&apos;&apos;&apos; Next i
+&apos;&apos;&apos; ui.SetStatusbar
+
+Dim oComp As Object
+Dim oControl As Object
+Dim oStatusbar As Object
+Const cstThisSub = &quot;UI.SetStatusbar&quot;
+Const cstSubArgs = &quot;[Text], [Percentage]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Text) Or IsEmpty(Text) Then Text = &quot;&quot;
+ If IsMissing(Percentage) Or IsEmpty(Percentage) Then Percentage = -1
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Text, &quot;Text&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Percentage, &quot;Percentage&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ Set oStatusbar = _SF_.Statusbar
+ With oStatusbar
+ If IsNull(oStatusbar) Then &apos; Initial call
+ Set oComp = StarDesktop.CurrentComponent
+ If Not IsNull(oComp) Then
+ Set oControl = Nothing
+ If SF_Session.HasUnoProperty(oComp, &quot;CurrentController&quot;) Then Set oControl = oComp.CurrentController
+ If Not IsNull(oControl) Then
+ If SF_Session.HasUnoMethod(oControl, &quot;getStatusIndicator&quot;) Then oStatusbar = oControl.getStatusIndicator()
+ End If
+ End If
+ If Not IsNull(oStatusbar) Then
+ .start(&quot;&quot;, 100)
+ End If
+ End If
+ If Not IsNull(oStatusbar) Then
+ If Len(Text) = 0 And Percentage = -1 Then
+ .end()
+ Set oStatusbar = Nothing
+ Else
+ If Len(Text) &gt; 0 Then .setText(Text)
+ If Percentage &gt;= 0 And Percentage &lt;= 100 Then .setValue(Percentage)
+ End If
+ End If
+ End With
+
+Finally:
+ Set _SF_.Statusbar = oStatusbar
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_UI.SetStatusbar
+
+REM -----------------------------------------------------------------------------
+Public Sub ShowProgressBar(Optional Title As Variant _
+ , Optional ByVal Text As Variant _
+ , Optional ByVal Percentage As Variant _
+ , Optional ByRef _Context As Variant _
+ )
+&apos;&apos;&apos; Display a non-modal dialog box. Specify its title, an explicatory text and the progress on a progressbar
+&apos;&apos;&apos; A call without arguments erases the progress bar dialog.
+&apos;&apos;&apos; The box will anyway vanish at the end of the macro run.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Title: the title appearing on top of the dialog box (Default = &quot;ScriptForge&quot;)
+&apos;&apos;&apos; Text: the optional text to be displayed above the progress bar (default = zero-length string)
+&apos;&apos;&apos; Percentage: the degree of progress between 0 and 100. Default = 0
+&apos;&apos;&apos; _Context: from Python, the XComponentXontext (FOR INTERNAL USE ONLY)
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim i As Integer
+&apos;&apos;&apos; For i = 0 To 100
+&apos;&apos;&apos; ui.ShowProgressBar(, &quot;Progress ... &quot; &amp; i &amp; &quot;/100&quot;, i)
+&apos;&apos;&apos; Wait 50
+&apos;&apos;&apos; Next i
+&apos;&apos;&apos; ui.ShowProgressBar
+
+Dim bFirstCall As Boolean &apos; True at first invocation of method
+Dim oDialog As Object &apos; SFDialogs.Dialog object
+Dim oFixedText As Object &apos; SFDialogs.DialogControl object
+Dim oProgressBar As Object &apos; SFDialogs.DialogControl object
+Dim sTitle As String &apos; Alias of Title
+Const cstThisSub = &quot;UI.ShowProgressBar&quot;
+Const cstSubArgs = &quot;[Title], [Text], [Percentage]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Title) Or IsEmpty(Title) Then Title = &quot;&quot;
+ If IsMissing(Text) Or IsEmpty(Text) Then Text = &quot;&quot;
+ If IsMissing(Percentage) Or IsEmpty(Percentage) Then Percentage = -1
+ If IsMissing(_Context) Or IsEmpty(_Context) Then _Context = Nothing
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Title, &quot;Title&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Text, &quot;Text&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Percentage, &quot;Percentage&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ With _SF_
+ Set oDialog = .ProgressBarDialog
+ Set oFixedText = .ProgressBarText
+ Set oProgressBar = .ProgressBarBar
+ End With
+ With oDialog
+ bFirstCall = ( IsNull(oDialog) )
+ If Not bFirstCall Then bFirstCall = Not ._IsStillAlive(False) &apos; False to not raise an error
+ If bFirstCall Then Set oDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, &quot;GlobalScope&quot;, &quot;ScriptForge&quot;, &quot;dlgProgress&quot;, _Context)
+
+ If Not IsNull(oDialog) Then
+ If Len(Title) = 0 And Len(Text) = 0 And Percentage = -1 Then
+ Set oDialog = .Dispose()
+ Else
+ .Caption = Iif(Len(Title) &gt; 0, Title, &quot;ScriptForge&quot;)
+ If bFirstCall Then
+ Set oFixedText = .Controls(&quot;ProgressText&quot;)
+ Set oProgressBar = .Controls(&quot;ProgressBar&quot;)
+ .Execute(Modal := False)
+ End If
+ If Len(Text) &gt; 0 Then oFixedText.Caption = Text
+ oProgressBar.Value = Iif(Percentage &gt;= 0 And Percentage &lt;= 100, Percentage, 0)
+ End If
+ End If
+ End With
+
+Finally:
+ With _SF_
+ Set .ProgressBarDialog = oDialog
+ Set .ProgressBarText = oFixedText
+ Set .ProgressBarBar = oProgressBar
+ End With
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; ScriptForge.SF_UI.ShowProgressBar
+
+REM -----------------------------------------------------------------------------
+Public Function WindowExists(Optional ByVal WindowName As Variant) As Boolean
+&apos;&apos;&apos; Returns True if the specified window exists
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; WindowName: see definitions
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the given window is found
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; ui.WindowExists(&quot;C:\Me\My file.odt&quot;)
+
+Dim bWindowExists As Boolean &apos; Return value
+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 oContainer As Object &apos; com.sun.star.awt.XWindow
+Const cstThisSub = &quot;UI.WindowExists&quot;
+Const cstSubArgs = &quot;WindowName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bWindowExists = False
+
+Check:
+ If IsMissing(WindowName) Or IsEmpty(WindowName) Then WindowName = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(WindowName, &quot;WindowName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oEnum = StarDesktop.Components().createEnumeration
+ Do While oEnum.hasMoreElements
+ Set oComp = oEnum.nextElement
+ vWindow = SF_UI._IdentifyWindow(oComp)
+ With vWindow
+ &apos; Does the current window match the arguments ?
+ If (Len(.WindowFileName) &gt; 0 And .WindowFileName = SF_FileSystem.ConvertToUrl(WindowName)) _
+ Or (Len(.WindowName) &gt; 0 And .WindowName = WindowName) _
+ Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = WindowName) Then
+ bWindowExists = True
+ Exit Do
+ End If
+ End With
+ Loop
+
+Finally:
+ WindowExists = bWindowExists
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI.WindowExists
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Sub _CloseProgressBar(Optional ByRef poEvent As Object)
+&apos;&apos;&apos; Triggered by the Close button in the dlgProgress dialog
+&apos;&apos;&apos; to simply close the dialog
+
+ ShowProgressBar() &apos; Without arguments =&gt; close the dialog
+
+End Sub &apos; ScriptForge.SF_UI._CloseProgressBar
+
+REM -----------------------------------------------------------------------------
+Public Function _IdentifyWindow(ByRef poComponent As Object) As Object
+&apos;&apos;&apos; Return a Window object (definition on top of module) based on component given as argument
+&apos;&apos;&apos; Is a shortcut to explore the most relevant properties or objects bound to a UNO component
+
+Dim oWindow As Window &apos; Return value
+Dim sImplementation As String &apos; Component&apos;s implementationname
+Dim sIdentifier As String &apos; Component&apos;s identifier
+Dim vArg As Variant &apos; One single item of the Args UNO property
+Dim FSO As Object &apos; Alias for SF_FileSystem
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set _IdentifyWindow = Nothing
+ sImplementation = &quot;&quot; : sIdentifier = &quot;&quot;
+
+ Set FSO = SF_FileSystem
+ With oWindow
+ Set .Frame = Nothing
+ Set .Component = Nothing
+ .WindowName = &quot;&quot;
+ .WindowTitle = &quot;&quot;
+ .WindowFileName = &quot;&quot;
+ .DocumentType = &quot;&quot;
+ If IsNull(poComponent) Then GoTo Finally
+ If SF_Session.HasUnoProperty(poComponent, &quot;ImplementationName&quot;) Then sImplementation = poComponent.ImplementationName
+ If SF_Session.HasUnoProperty(poComponent, &quot;Identifier&quot;) Then sIdentifier = poComponent.Identifier
+ Set .Component = poComponent
+ Select Case sImplementation
+ Case &quot;com.sun.star.comp.basic.BasicIDE&quot;
+ .WindowName = BASICIDE
+ Case &quot;com.sun.star.comp.dba.ODatabaseDocument&quot; &apos; No identifier
+ .WindowFileName = SF_Utils._GetPropertyValue(poComponent.Args, &quot;URL&quot;)
+ If Len(.WindowFileName) &gt; 0 Then .WindowName = FSO.GetName(FSO._ConvertFromUrl(.WindowFileName))
+ .DocumentType = BASEDOCUMENT
+ Case &quot;org.openoffice.comp.dbu.ODatasourceBrowser&quot;
+ Case &quot;org.openoffice.comp.dbu.OTableDesign&quot;, &quot;org.openoffice.comp.dbu.OQueryDesign&quot; &apos; Table or Query in Edit mode
+ Case &quot;org.openoffice.comp.dbu.ORelationDesign&quot;
+ Case &quot;com.sun.star.comp.sfx2.BackingComp&quot; &apos; Welcome screen
+ Set .Frame = poComponent.Frame
+ .WindowName = WELCOMESCREEN
+ Case Else
+ If Len(sIdentifier) &gt; 0 Then
+ &apos; Do not use URL : it contains the TemplateFile when new documents are created from a template
+ .WindowFileName = poComponent.Location
+ If Len(.WindowFileName) &gt; 0 Then .WindowName = FSO.GetName(FSO._ConvertFromUrl(.WindowFileName))
+ If SF_Session.HasUnoProperty(poComponent, &quot;Title&quot;) Then .WindowTitle = poComponent.Title
+ Select Case sIdentifier
+ Case &quot;com.sun.star.sdb.FormDesign&quot; &apos; Form
+ Case &quot;com.sun.star.sdb.TextReportDesign&quot; &apos; Report
+ Case &quot;com.sun.star.text.TextDocument&quot; &apos; Writer
+ .DocumentType = WRITERDOCUMENT
+ Case &quot;com.sun.star.sheet.SpreadsheetDocument&quot; &apos; Calc
+ .DocumentType = CALCDOCUMENT
+ Case &quot;com.sun.star.presentation.PresentationDocument&quot; &apos; Impress
+ .DocumentType = IMPRESSDOCUMENT
+ Case &quot;com.sun.star.drawing.DrawingDocument&quot; &apos; Draw
+ .DocumentType = DRAWDOCUMENT
+ Case &quot;com.sun.star.formula.FormulaProperties&quot; &apos; Math
+ .DocumentType = MATHDOCUMENT
+ Case Else
+ End Select
+ End If
+ End Select
+ If IsNull(.Frame) Then
+ If Not IsNull(poComponent.CurrentController) Then Set .Frame = poComponent.CurrentController.Frame
+ End If
+ End With
+
+Finally:
+ Set _IdentifyWindow = oWindow
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_UI._IdentifyWindow
+
+REM -----------------------------------------------------------------------------
+Public Function _PosSize() As Object
+&apos;&apos;&apos; Returns the PosSize structure of the active window
+
+Dim vWindow As Window &apos; A single component
+Dim oContainer As Object &apos; com.sun.star.awt.XWindow
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+
+ Set oPosSize = Nothing
+
+Try:
+ vWindow = SF_UI._IdentifyWindow(StarDesktop.CurrentComponent)
+ If Not IsNull(vWindow.Frame) Then
+ Set oContainer = vWindow.Frame.ContainerWindow
+ Set oPosSize = oContainer.getPosSize()
+ End If
+
+Finally:
+ Set _PosSize = oPosSize
+ Exit Function
+End Function &apos; ScriptForge.SF_UI._PosSize
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the UI instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[UI]&quot;
+
+ _Repr = &quot;[UI]&quot;
+
+End Function &apos; ScriptForge.SF_UI._Repr
+
+REM ============================================ END OF SCRIPTFORGE.SF_UI
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Utils.xba b/wizards/source/scriptforge/SF_Utils.xba
new file mode 100644
index 000000000..91b703c46
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Utils.xba
@@ -0,0 +1,1113 @@
+<?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_Utils" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Explicit
+Option Private Module
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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_Utils
+&apos;&apos;&apos; ========
+&apos;&apos;&apos; FOR INTERNAL USE ONLY
+&apos;&apos;&apos; Groups all private functions used by the official modules
+&apos;&apos;&apos; Declares the Global variable _SF_
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ===================================================================== GLOBALS
+
+Global _SF_ As Variant &apos; SF_Root (Basic) object)
+
+&apos;&apos;&apos; ScriptForge version
+Const SF_Version = &quot;7.4&quot;
+
+&apos;&apos;&apos; Standard symbolic names for VarTypes
+&apos; V_EMPTY = 0
+&apos; V_NULL = 1
+&apos; V_INTEGER = 2
+&apos; V_LONG = 3
+&apos; V_SINGLE = 4
+&apos; V_DOUBLE = 5
+&apos; V_CURRENCY = 6
+&apos; V_DATE = 7
+&apos; V_STRING = 8
+&apos;&apos;&apos; Additional symbolic names for VarTypes
+Global Const V_OBJECT = 9
+Global Const V_BOOLEAN = 11
+Global Const V_VARIANT = 12
+Global Const V_BYTE = 17
+Global Const V_USHORT = 18
+Global Const V_ULONG = 19
+Global Const V_BIGINT = 35
+Global Const V_DECIMAL = 37
+Global Const V_ARRAY = 8192
+&apos;&apos;&apos; Fictive VarTypes
+Global Const V_NUMERIC = 99 &apos; Synonym of any numeric value [returned by _VarTypeExt()]
+Global Const V_NOTHING = 101 &apos; Object categories [returned by _VarTypeObj()] Null object
+Global Const V_UNOOBJECT = 102 &apos; Uno object or Uno structure
+Global Const V_SFOBJECT = 103 &apos; ScriptForge object: has ObjectType and ServiceName properties
+Global Const V_BASICOBJECT = 104 &apos; User Basic object
+
+Type _ObjectDescriptor &apos; Returned by the _VarTypeObj() method
+ iVarType As Integer &apos; One of the V_NOTHING, V_xxxOBJECT constants
+ sObjectType As String &apos; Either &quot;&quot; or &quot;com.sun.star...&quot; or a ScriptForge object type (ex. &quot;SF_SESSION&quot; or &quot;DICTIONARY&quot;)
+ sServiceName As String &apos; Either &quot;&quot; or the service name of a ScriptForge object type (ex. &quot;ScriptForge.Exception&quot;-
+End Type
+
+REM ================================================================== EXCEPTIONS
+
+Const MISSINGARGERROR = &quot;MISSINGARGERROR&quot; &apos; A mandatory argument is missing
+Const ARGUMENTERROR = &quot;ARGUMENTERROR&quot; &apos; An argument does not pass the _Validate() validation
+Const ARRAYERROR = &quot;ARRAYERROR&quot; &apos; An argument does not pass the _ValidateArray() validation
+Const FILEERROR = &quot;FILEERROR&quot; &apos; An argument does not pass the _ValidateFile() validation
+
+REM =========================================pvA==================== PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function _CDateToIso(pvDate As Variant) As Variant
+&apos;&apos;&apos; Returns a string representation of the given Basic date
+&apos;&apos;&apos; Dates as strings are essential in property values, where Basic dates are evil
+
+Dim sIsoDate As Variant &apos; Return value
+
+ If VarType(pvDate) = V_DATE Then
+ If Year(pvDate) &lt; 1900 Then &apos; Time only
+ sIsoDate = Right(&quot;0&quot; &amp; Hour(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvDate), 2)
+ ElseIf Hour(pvDate) + Minute(pvDate) + Second(pvDate) = 0 Then &apos; Date only
+ sIsoDate = Year(pvDate) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvDate), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvDate), 2)
+ Else
+ sIsoDate = Year(pvDate) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvDate), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvDate), 2) _
+ &amp; &quot; &quot; &amp; Right(&quot;0&quot; &amp; Hour(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvDate), 2) _
+ &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvDate), 2)
+ End If
+ Else
+ sIsoDate = pvDate
+ End If
+
+ _CDateToIso = sIsoDate
+
+End Function &apos; ScriptForge.SF_Utils._CDateToIso
+
+REM -----------------------------------------------------------------------------
+Public Function _CDateToUnoDate(pvDate As Variant) As Variant
+&apos;&apos;&apos; Returns a UNO com.sun.star.util.DateTime/Date/Time object depending on the given date
+&apos;&apos;&apos; by using the appropriate CDateToUnoDateXxx builtin function
+&apos;&apos;&apos; UNO dates are essential in property values, where Basic dates are evil
+
+Dim vUnoDate As Variant &apos; Return value
+
+ If VarType(pvDate) = V_DATE Then
+ If Year(pvDate) &lt; 1900 Then
+ vUnoDate = CDateToUnoTime(pvDate)
+ ElseIf Hour(pvDate) + Minute(pvDate) + Second(pvDate) = 0 Then
+ vUnoDate = CDateToUnoDate(pvDate)
+ Else
+ vUnoDate = CDateToUnoDateTime(pvDate)
+ End If
+ Else
+ vUnoDate = pvDate
+ End If
+
+ _CDateToUnoDate = vUnoDate
+
+End Function &apos; ScriptForge.SF_Utils._CDateToUnoDate
+
+REM -----------------------------------------------------------------------------
+Public Function _CPropertyValue(ByRef pvValue As Variant) As Variant
+&apos;&apos;&apos; Set a value of a correct type in a com.sun.star.beans.PropertyValue
+&apos;&apos;&apos; Date BASIC variables give error. Change them to UNO types
+&apos;&apos;&apos; Empty arrays should be replaced by Null
+
+Dim vValue As Variant &apos; Return value
+
+ If VarType(pvValue) = V_DATE Then
+ vValue = SF_Utils._CDateToUnoDate(pvValue)
+ ElseIf IsArray(pvValue) Then
+ If UBound(pvValue, 1) &lt; LBound(pvValue, 1) Then vValue = Null Else vValue = pvValue
+ Else
+ vValue = pvValue
+ End If
+ _CPropertyValue() = vValue
+
+End Function &apos; ScriptForge.SF_Utils._CPropertyValue
+
+REM -----------------------------------------------------------------------------
+Public Function _CStrToDate(ByRef pvStr As String) As Date
+&apos;&apos;&apos; Attempt to convert the input string to a Date variable with the CDate builtin function
+&apos;&apos;&apos; If not successful, returns conventionally -1 (29/12/1899)
+&apos;&apos;&apos; Date patterns: YYYY-MM-DD, HH:MM:DD and YYYY-MM-DD HH:MM:DD
+
+Dim dDate As Date &apos; Return value
+Const cstNoDate = -1
+
+ dDate = cstNoDate
+Try:
+ On Local Error Resume Next
+ dDate = CDate(pvStr)
+
+Finally:
+ _CStrToDate = dDate
+ Exit Function
+End Function &apos; ScriptForge.SF_Utils._CStrToDate
+
+REM -----------------------------------------------------------------------------
+Public Function _EnterFunction(ByVal psSub As String, Optional ByVal psArgs As String)
+&apos;&apos;&apos; Called on top of each public function
+&apos;&apos;&apos; Used to trace routine in/outs (debug mode)
+&apos;&apos;&apos; and to allow the explicit mention of the user call which caused an error
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psSub = the called Sub/Function/Property, usually something like &quot;service.sub&quot;
+&apos;&apos;&apos; Return: True when psSub is called from a user script
+&apos;&apos;&apos; Used to bypass the validation of the arguments when unnecessary
+
+ If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot() &apos; First use of ScriptForge during current LibO session
+ If IsMissing(psArgs) Then psArgs = &quot;&quot;
+ With _SF_
+ If .StackLevel = 0 Then
+ .MainFunction = psSub
+ .MainFunctionArgs = psArgs
+ _EnterFunction = True
+ Else
+ _EnterFunction = False
+ End If
+ .StackLevel = .StackLevel + 1
+ If .DebugMode Then ._AddToConsole(&quot;==&gt; &quot; &amp; psSub &amp; &quot;(&quot; &amp; .StackLevel &amp; &quot;)&quot;)
+ End With
+
+End Function &apos; ScriptForge.SF_Utils._EnterFunction
+
+REM -----------------------------------------------------------------------------
+Public Function _ErrorHandling(Optional ByVal pbErrorHandler As Boolean) As Boolean
+&apos;&apos;&apos; Error handling is normally ON and can be set OFF for debugging purposes
+&apos;&apos;&apos; Each user visible routine starts with a call to this function to enable/disable
+&apos;&apos;&apos; standard handling of internal errors
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbErrorHandler = if present, set its value
+&apos;&apos;&apos; Return: the current value of the error handler
+
+ If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot() &apos; First use of ScriptForge during current LibO session
+ If Not IsMissing(pbErrorHandler) Then _SF_.ErrorHandler = pbErrorHandler
+ _ErrorHandling = _SF_.ErrorHandler
+
+End Function &apos; ScriptForge.SF_Utils._ErrorHandling
+
+REM -----------------------------------------------------------------------------
+Public Sub _ExitFunction(ByVal psSub As String)
+&apos;&apos;&apos; Called in the Finally block of each public function
+&apos;&apos;&apos; Manage ScriptForge internal aborts
+&apos;&apos;&apos; Resets MainFunction (root) when exiting the method called by a user script
+&apos;&apos;&apos; Used to trace routine in/outs (debug mode)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psSub = the called Sub/Function/Property, usually something like &quot;service.sub&quot;
+
+ If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot() &apos; Useful only when current module has been recompiled
+ With _SF_
+ If Err &gt; 0 Then
+ SF_Exception.RaiseAbort(psSub)
+ End If
+ If .StackLevel = 1 Then
+ .MainFunction = &quot;&quot;
+ .MainFunctionArgs = &quot;&quot;
+ End If
+ If .DebugMode Then ._AddToConsole(&quot;&lt;== &quot; &amp; psSub &amp; &quot;(&quot; &amp; .StackLevel &amp; &quot;)&quot;)
+ If .StackLevel &gt; 0 Then .StackLevel = .StackLevel - 1
+ End With
+
+End Sub &apos; ScriptForge.SF_Utils._ExitFunction
+
+REM -----------------------------------------------------------------------------
+Public Sub _ExportScriptForgePOTFile(ByVal FileName As String)
+&apos;&apos;&apos; Export the ScriptForge POT file related to its own user interface
+&apos;&apos;&apos; Should be called only before issuing new ScriptForge releases only
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: the resulting file. If it exists, is overwritten without warning
+
+Dim sHeader As String &apos; The specific header to insert
+
+ sHeader = &quot;&quot; _
+ &amp; &quot;*********************************************************************\n&quot; _
+ &amp; &quot;*** The ScriptForge library and its associated libraries ***\n&quot; _
+ &amp; &quot;*** are part of the LibreOffice project. ***\n&quot; _
+ &amp; &quot;*********************************************************************\n&quot; _
+ &amp; &quot;\n&quot; _
+ &amp; &quot;ScriptForge Release &quot; &amp; SF_Version &amp; &quot;\n&quot; _
+ &amp; &quot;-----------------------&quot;
+
+Try:
+ With _SF_
+ If Not IsNull(.LocalizedInterface) Then .LocalizedInterface.Dispose()
+ ._LoadLocalizedInterface(psMode := &quot;ADDTEXT&quot;) &apos; Force reload of labels from the code
+ .LocalizedInterface.ExportToPOTFile(FileName, Header := sHeader)
+ End With
+
+Finally:
+ Exit Sub
+End Sub &apos; ScriptForge.SF_Utils._ExportScriptForgePOTFile
+
+REM -----------------------------------------------------------------------------
+Public Function _GetPropertyValue(ByRef pvArgs As Variant, ByVal psName As String) As Variant
+&apos;&apos;&apos; Returns the Value corresponding to the given name
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; pvArgs: a zero_based array of PropertyValues
+&apos;&apos;&apos; psName: the comparison is not case-sensitive
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Zero-length string if not found
+
+Dim vValue As Variant &apos; Return value
+Dim i As Long
+
+ vValue = &quot;&quot;
+ If IsArray(pvArgs) Then
+ For i = LBound(pvArgs) To UBound(pvArgs)
+ If UCase(psName) = UCase(pvArgs(i).Name) Then
+ vValue = pvArgs(i).Value
+ Exit For
+ End If
+ Next i
+ End If
+ _GetPropertyValue = vValue
+
+End Function &apos; ScriptForge.SF_Utils._GetPropertyValue
+
+REM -----------------------------------------------------------------------------
+Public Function _GetRegistryKeyContent(ByVal psKeyName as string _
+ , Optional pbForUpdate as Boolean _
+ ) As Variant
+&apos;&apos;&apos; Implement a ConfigurationProvider service
+&apos;&apos;&apos; Derived from the Tools library
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psKeyName: the name of the node in the configuration tree
+&apos;&apos;&apos; pbForUpdate: default = False
+
+Dim oConfigProvider as Object &apos; com.sun.star.configuration.ConfigurationProvider
+Dim vNodePath(0) as New com.sun.star.beans.PropertyValue
+Dim sConfig As String &apos; One of next 2 constants
+Const cstConfig = &quot;com.sun.star.configuration.ConfigurationAccess&quot;
+Const cstConfigUpdate = &quot;com.sun.star.configuration.ConfigurationUpdateAccess&quot;
+
+ Set oConfigProvider = _GetUNOService(&quot;ConfigurationProvider&quot;)
+ vNodePath(0).Name = &quot;nodepath&quot;
+ vNodePath(0).Value = psKeyName
+
+ If IsMissing(pbForUpdate) Then pbForUpdate = False
+ If pbForUpdate Then sConfig = cstConfigUpdate Else sConfig = cstConfig
+
+ Set _GetRegistryKeyContent = oConfigProvider.createInstanceWithArguments(sConfig, vNodePath())
+
+End Function &apos; ScriptForge.SF_Utils._GetRegistryKeyContent
+
+REM -----------------------------------------------------------------------------
+Private Function _GetSetting(ByVal psPreference As String, psProperty As String) As Variant
+&apos;&apos;&apos; Find in the configuration a specific setting based on its location in the
+&apos;&apos;&apos; settings registry
+
+Dim oConfigProvider As Object &apos; com.sun.star.configuration.ConfigurationProvider
+Dim vNodePath As Variant &apos; Array of com.sun.star.beans.PropertyValue
+
+ &apos; Derived from the Tools library
+ Set oConfigProvider = createUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
+ vNodePath = Array(SF_Utils._MakePropertyValue(&quot;nodepath&quot;, psPreference))
+
+ _GetSetting = oConfigProvider.createInstanceWithArguments( _
+ &quot;com.sun.star.configuration.ConfigurationAccess&quot;, vNodePath()).getByName(psProperty)
+
+End Function &apos; ScriptForge.SF_Utils._GetSetting
+
+REM -----------------------------------------------------------------------------
+Public Function _GetUNOService(ByVal psService As String _
+ , Optional ByVal pvArg As Variant _
+ ) As Object
+&apos;&apos;&apos; Create a UNO service
+&apos;&apos;&apos; Each service is called only once
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psService: shortcut to service
+&apos;&apos;&apos; pvArg: some services might require an argument
+
+Dim sLocale As String &apos; fr-BE f.i.
+Dim oDefaultContext As Object
+
+ Set _GetUNOService = Nothing
+ With _SF_
+ Select Case psService
+ Case &quot;BrowseNodeFactory&quot;
+ Set oDefaultContext = GetDefaultContext()
+ If Not IsNull(oDefaultContext) Then Set _GetUNOService = oDefaultContext.getValueByName(&quot;/singletons/com.sun.star.script.browse.theBrowseNodeFactory&quot;)
+ Case &quot;CalendarImpl&quot;
+ If IsEmpty(.CalendarImpl) Or IsNull(.CalendarImpl) Then
+ Set .CalendarImpl = CreateUnoService(&quot;com.sun.star.i18n.CalendarImpl&quot;)
+ End If
+ Set _GetUNOService = .CalendarImpl
+ Case &quot;CharacterClass&quot;
+ If IsEmpty(.CharacterClass) Or IsNull(.CharacterClass) Then
+ Set .CharacterClass = CreateUnoService(&quot;com.sun.star.i18n.CharacterClassification&quot;)
+ End If
+ Set _GetUNOService = .CharacterClass
+ Case &quot;ConfigurationProvider&quot;
+ If IsEmpty(.ConfigurationProvider) Or IsNull(.ConfigurationProvider) Then
+ Set .ConfigurationProvider = CreateUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
+ End If
+ Set _GetUNOService = .ConfigurationProvider
+ Case &quot;CoreReflection&quot;
+ If IsEmpty(.CoreReflection) Or IsNull(.CoreReflection) Then
+ Set .CoreReflection = CreateUnoService(&quot;com.sun.star.reflection.CoreReflection&quot;)
+ End If
+ Set _GetUNOService = .CoreReflection
+ Case &quot;DatabaseContext&quot;
+ If IsEmpty(.DatabaseContext) Or IsNull(.DatabaseContext) Then
+ Set .DatabaseContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+ End If
+ Set _GetUNOService = .DatabaseContext
+ Case &quot;DispatchHelper&quot;
+ If IsEmpty(.DispatchHelper) Or IsNull(.DispatchHelper) Then
+ Set .DispatchHelper = CreateUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;)
+ End If
+ Set _GetUNOService = .DispatchHelper
+ Case &quot;FileAccess&quot;
+ If IsEmpty(.FileAccess) Or IsNull(.FileAccess) Then
+ Set .FileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ End If
+ Set _GetUNOService = .FileAccess
+ Case &quot;FilePicker&quot;
+ If IsEmpty(.FilePicker) Or IsNull(.FilePicker) Then
+ Set .FilePicker = CreateUnoService(&quot;com.sun.star.ui.dialogs.FilePicker&quot;)
+ End If
+ Set _GetUNOService = .FilePicker
+ Case &quot;FilterFactory&quot;
+ If IsEmpty(.FilterFactory) Or IsNull(.FilterFactory) Then
+ Set .FilterFactory = CreateUnoService(&quot;com.sun.star.document.FilterFactory&quot;)
+ End If
+ Set _GetUNOService = .FilterFactory
+ Case &quot;FolderPicker&quot;
+ If IsEmpty(.FolderPicker) Or IsNull(.FolderPicker) Then
+ Set .FolderPicker = CreateUnoService(&quot;com.sun.star.ui.dialogs.FolderPicker&quot;)
+ End If
+ Set _GetUNOService = .FolderPicker
+ Case &quot;FormatLocale&quot;
+ If IsEmpty(.FormatLocale) Or IsNull(.FormatLocale) Then
+ .FormatLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
+ &apos; 1st and 2nd chance
+ sLocale = SF_Utils._GetSetting(&quot;org.openoffice.Setup/L10N&quot;, &quot;ooSetupSystemLocale&quot;)
+ If Len(sLocale) = 0 Then sLocale = SF_Utils._GetSetting(&quot;org.openoffice.System/L10N&quot;, &quot;UILocale&quot;)
+ .FormatLocale.Language = Split(sLocale, &quot;-&quot;)(0) &apos; Language is most often 2 chars long, but not always
+ .FormatLocale.Country = Right(sLocale, 2)
+ End If
+ Set _GetUNOService = .FormatLocale
+ Case &quot;FunctionAccess&quot;
+ If IsEmpty(.FunctionAccess) Or IsNull(.FunctionAccess) Then
+ Set .FunctionAccess = CreateUnoService(&quot;com.sun.star.sheet.FunctionAccess&quot;)
+ End If
+ Set _GetUNOService = .FunctionAccess
+ Case &quot;GraphicExportFilter&quot;
+ If IsEmpty(.GraphicExportFilter) Or IsNull(.GraphicExportFilter) Then
+ Set .GraphicExportFilter = CreateUnoService(&quot;com.sun.star.drawing.GraphicExportFilter&quot;)
+ End If
+ Set _GetUNOService = .GraphicExportFilter
+ Case &quot;Introspection&quot;
+ If IsEmpty(.Introspection) Or IsNull(.Introspection) Then
+ Set .Introspection = CreateUnoService(&quot;com.sun.star.beans.Introspection&quot;)
+ End If
+ Set _GetUNOService = .Introspection
+ Case &quot;LocaleData&quot;
+ If IsEmpty(.LocaleData) Or IsNull(.LocaleData) Then
+ Set .LocaleData = CreateUnoService(&quot;com.sun.star.i18n.LocaleData&quot;)
+ End If
+ Set _GetUNOService = .LocaleData
+ Case &quot;MacroExpander&quot;
+ Set oDefaultContext = GetDefaultContext()
+ If Not IsNull(oDefaultContext) Then Set _GetUNOService = oDefaultContext.getValueByName(&quot;/singletons/com.sun.star.util.theMacroExpander&quot;)
+ Case &quot;MailService&quot;
+ If IsEmpty(.MailService) Or IsNull(.MailService) Then
+ If GetGuiType = 1 Then &apos; Windows
+ Set .MailService = CreateUnoService(&quot;com.sun.star.system.SimpleSystemMail&quot;)
+ Else
+ Set .MailService = CreateUnoService(&quot;com.sun.star.system.SimpleCommandMail&quot;)
+ End If
+ End If
+ Set _GetUNOService = .MailService
+ Case &quot;Number2Text&quot;
+ If IsEmpty(.Number2Text) Or IsNull(.Number2Text) Then
+ Set .Number2Text = CreateUnoService(&quot;com.sun.star.linguistic2.NumberText&quot;)
+ End If
+ Set _GetUNOService = .Number2Text
+ Case &quot;OfficeLocale&quot;
+ If IsEmpty(.OfficeLocale) Or IsNull(.OfficeLocale) Then
+ .OfficeLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
+ &apos; 1st and 2nd chance
+ sLocale = SF_Utils._GetSetting(&quot;org.openoffice.Setup/L10N&quot;, &quot;ooLocale&quot;)
+ If Len(sLocale) = 0 Then sLocale = SF_Utils._GetSetting(&quot;org.openoffice.System/L10N&quot;, &quot;UILocale&quot;)
+ .OfficeLocale.Language = Split(sLocale, &quot;-&quot;)(0) &apos; Language is most often 2 chars long, but not always
+ .OfficeLocale.Country = Right(sLocale, 2)
+ End If
+ Set _GetUNOService = .OfficeLocale
+ Case &quot;PackageInformationProvider&quot;
+ If IsEmpty(.PackageProvider) Or IsNull(.PackageProvider) Then
+ Set .PackageProvider = GetDefaultContext.getByName(&quot;/singletons/com.sun.star.deployment.PackageInformationProvider&quot;)
+ End If
+ Set _GetUNOService = .PackageProvider
+ Case &quot;PathSettings&quot;
+ If IsEmpty(.PathSettings) Or IsNull(.PathSettings) Then
+ Set .PathSettings = CreateUnoService(&quot;com.sun.star.util.PathSettings&quot;)
+ End If
+ Set _GetUNOService = .PathSettings
+ Case &quot;PathSubstitution&quot;
+ If IsEmpty(.PathSubstitution) Or IsNull(.PathSubstitution) Then
+ Set .PathSubstitution = CreateUnoService(&quot;com.sun.star.util.PathSubstitution&quot;)
+ End If
+ Set _GetUNOService = .PathSubstitution
+ Case &quot;PrinterServer&quot;
+ If IsEmpty(.PrinterServer) Or IsNull(.PrinterServer) Then
+ Set .PrinterServer = CreateUnoService(&quot;com.sun.star.awt.PrinterServer&quot;)
+ End If
+ Set _GetUNOService = .PrinterServer
+ Case &quot;ScriptProvider&quot;
+ If IsMissing(pvArg) Then pvArg = SF_Session.SCRIPTISAPPLICATION
+ Select Case LCase(pvArg)
+ Case SF_Session.SCRIPTISEMBEDDED &apos; Document
+ If Not IsNull(ThisComponent) Then Set _GetUNOService = ThisComponent.getScriptProvider()
+ Case Else
+ If IsEmpty(.ScriptProvider) Or IsNull(.ScriptProvider) Then
+ Set .ScriptProvider = _
+ CreateUnoService(&quot;com.sun.star.script.provider.MasterScriptProviderFactory&quot;).createScriptProvider(&quot;&quot;)
+ End If
+ Set _GetUNOService = .ScriptProvider
+ End Select
+ Case &quot;SearchOptions&quot;
+ If IsEmpty(.SearchOptions) Or IsNull(.SearchOptions) Then
+ Set .SearchOptions = New com.sun.star.util.SearchOptions
+ With .SearchOptions
+ .algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
+ .searchFlag = 0
+ End With
+ End If
+ Set _GetUNOService = .SearchOptions
+ Case &quot;SystemLocale&quot;, &quot;Locale&quot;
+ If IsEmpty(.SystemLocale) Or IsNull(.SystemLocale) Then
+ .SystemLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
+ sLocale = SF_Utils._GetSetting(&quot;org.openoffice.System/L10N&quot;, &quot;SystemLocale&quot;)
+ .SystemLocale.Language = Split(sLocale, &quot;-&quot;)(0) &apos; Language is most often 2 chars long, but not always
+ .SystemLocale.Country = Right(sLocale, 2)
+ End If
+ Set _GetUNOService = .SystemLocale
+ Case &quot;SystemShellExecute&quot;
+ If IsEmpty(.SystemShellExecute) Or IsNull(.SystemShellExecute) Then
+ Set .SystemShellExecute = CreateUnoService(&quot;com.sun.star.system.SystemShellExecute&quot;)
+ End If
+ Set _GetUNOService = .SystemShellExecute
+ Case &quot;TextSearch&quot;
+ If IsEmpty(.TextSearch) Or IsNull(.TextSearch) Then
+ Set .TextSearch = CreateUnoService(&quot;com.sun.star.util.TextSearch&quot;)
+ End If
+ Set _GetUNOService = .TextSearch
+ Case &quot;Toolkit&quot;
+ If IsEmpty(.Toolkit) Or IsNull(.Toolkit) Then
+ Set .Toolkit = CreateUnoService(&quot;com.sun.star.awt.Toolkit&quot;)
+ End If
+ Set _GetUNOService = .Toolkit
+ Case &quot;URLTransformer&quot;
+ If IsEmpty(.URLTransformer) Or IsNull(.URLTransformer) Then
+ Set .URLTransformer = CreateUnoService(&quot;com.sun.star.util.URLTransformer&quot;)
+ End If
+ Set _GetUNOService = .URLTransformer
+ Case Else
+ End Select
+ End With
+
+End Function &apos; ScriptForge.SF_Utils._GetUNOService
+
+REM -----------------------------------------------------------------------------
+Public Sub _InitializeRoot(Optional ByVal pbForce As Boolean)
+&apos;&apos;&apos; Initialize _SF_ as SF_Root basic object
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbForce = True forces the reinit (default = False)
+
+ If IsMissing(pbForce) Then pbForce = False
+ If pbForce Then Set _SF_ = Nothing
+ If IsEmpty(_SF_) Or IsNull(_SF_) Then
+ Set _SF_ = New SF_Root
+ Set _SF_.[Me] = _SF_
+ End If
+
+End Sub &apos; ScriptForge.SF_Utils._InitializeRoot
+
+REM -----------------------------------------------------------------------------
+Public Function _MakePropertyValue(ByVal psName As String _
+ , ByRef pvValue As Variant _
+ ) As com.sun.star.beans.PropertyValue
+&apos;&apos;&apos; Create and return a new com.sun.star.beans.PropertyValue
+
+Dim oPropertyValue As New com.sun.star.beans.PropertyValue
+
+ With oPropertyValue
+ .Name = psName
+ .Value = SF_Utils._CPropertyValue(pvValue)
+ End With
+ _MakePropertyValue() = oPropertyValue
+
+End Function &apos; ScriptForge.SF_Utils._MakePropertyValue
+
+REM -----------------------------------------------------------------------------
+Public Function _Repr(ByVal pvArg As Variant, Optional ByVal plMax As Long) As String
+&apos;&apos;&apos; Convert pvArg into a readable string (truncated if length &gt; plMax)
+&apos;&apos;&apos; Args
+&apos;&apos;&apos; pvArg: may be of any type
+&apos;&apos;&apos; plMax: maximum length of the resulting string (default = 32K)
+
+Dim sArg As String &apos; Return value
+Dim oObject As Object &apos; Alias of argument to avoid &quot;Object variable not set&quot;
+Dim oObjectDesc As Object &apos; Object descriptor
+Dim sLength As String &apos; String length as a string
+Dim i As Long
+Const cstBasicObject = &quot;com.sun.star.script.NativeObjectWrapper&quot;
+
+Const cstMaxLength = 2^15 - 1 &apos; 32767
+Const cstByteLength = 25
+Const cstEtc = &quot; … &quot;
+
+ If IsMissing(plMax) Then plMax = cstMaxLength
+ If plMax = 0 Then plMax = cstMaxLength
+ If IsArray(pvArg) Then
+ sArg = SF_Array._Repr(pvArg)
+ Else
+ Select Case VarType(pvArg)
+ Case V_EMPTY : sArg = &quot;[EMPTY]&quot;
+ Case V_NULL : sArg = &quot;[NULL]&quot;
+ Case V_OBJECT
+ Set oObjectDesc = SF_Utils._VarTypeObj(pvArg)
+ With oObjectDesc
+ Select Case .iVarType
+ Case V_NOTHING : sArg = &quot;[NOTHING]&quot;
+ Case V_OBJECT, V_BASICOBJECT
+ sArg = &quot;[OBJECT]&quot;
+ Case V_UNOOBJECT : sArg = &quot;[&quot; &amp; .sObjectType &amp; &quot;]&quot;
+ Case V_SFOBJECT
+ If Left(.sObjectType, 3) = &quot;SF_&quot; Then &apos; Standard module
+ sArg = &quot;[&quot; &amp; .sObjectType &amp; &quot;]&quot;
+ Else &apos; Class module must have a _Repr() method
+ Set oObject = pvArg
+ sArg = oObject._Repr()
+ End If
+ End Select
+ End With
+ Case V_VARIANT : sArg = &quot;[VARIANT]&quot;
+ Case V_STRING
+ sArg = SF_String._Repr(pvArg)
+ Case V_BOOLEAN : sArg = Iif(pvArg, &quot;[TRUE]&quot;, &quot;[FALSE]&quot;)
+ Case V_BYTE : sArg = Right(&quot;00&quot; &amp; Hex(pvArg), 2)
+ Case V_SINGLE, V_DOUBLE, V_CURRENCY
+ sArg = Format(pvArg)
+ If InStr(1, sArg, &quot;E&quot;, 1) = 0 Then sArg = Format(pvArg, &quot;##0.0##&quot;)
+ sArg = Replace(sArg, &quot;,&quot;, &quot;.&quot;) &apos;Force decimal point
+ Case V_BIGINT : sArg = CStr(CLng(pvArg))
+ Case V_DATE : sArg = _CDateToIso(pvArg)
+ Case Else : sArg = CStr(pvArg)
+ End Select
+ End If
+ If Len(sArg) &gt; plMax Then
+ sLength = &quot;(&quot; &amp; Len(sArg) &amp; &quot;)&quot;
+ sArg = Left(sArg, plMax - Len(cstEtc) - Len(slength)) &amp; cstEtc &amp; sLength
+ End If
+ _Repr = sArg
+
+End Function &apos; ScriptForge.SF_Utils._Repr
+
+REM -----------------------------------------------------------------------------
+Private Function _ReprValues(Optional ByVal pvArgs As Variant _
+ , Optional ByVal plMax As Long _
+ ) As String
+&apos;&apos;&apos; Convert an array of values to a comma-separated list of readable strings
+
+Dim sValues As String &apos; Return value
+Dim sValue As String &apos; A single value
+Dim vValue As Variant &apos; A single item in the argument
+Dim i As Long &apos; Items counter
+Const cstMax = 20 &apos; Maximum length of single string
+Const cstContinue = &quot;…&quot; &apos; Unicode continuation char U+2026
+
+ _ReprValues = &quot;&quot;
+ If IsMissing(pvArgs) Then Exit Function
+ If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
+ sValues = &quot;&quot;
+ For i = 0 To UBound(pvArgs)
+ vValue = pvArgs(i)
+ If i &lt; plMax Then
+ If VarType(vValue) = V_STRING Then sValue = &quot;&quot;&quot;&quot; &amp; vValue &amp; &quot;&quot;&quot;&quot; Else sValue = SF_Utils._Repr(vValue, cstMax)
+ If Len(sValues) = 0 Then sValues = sValue Else sValues = sValues &amp; &quot;, &quot; &amp; sValue
+ ElseIf i &lt; UBound(pvArgs) Then
+ sValues = sValues &amp; &quot;, &quot; &amp; cstContinue
+ Exit For
+ End If
+ Next i
+ _ReprValues = sValues
+
+End Function &apos; ScriptForge.SF_Utils._ReprValues
+
+REM -----------------------------------------------------------------------------
+Public Function _SetPropertyValue(ByVal pvPropertyValue As Variant _
+ , ByVal psName As String _
+ , ByRef pvValue As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return the 1st argument (passed by reference), which is an array of property values
+&apos;&apos;&apos; If the property psName exists, update it with pvValue, otherwise create it on top of the returned array
+
+Dim oPropertyValue As New com.sun.star.beans.PropertyValue
+Dim lIndex As Long &apos; Found entry
+Dim vValue As Variant &apos; Alias of pvValue
+Dim vProperties As Variant &apos; Alias of pvPropertyValue
+Dim i As Long
+
+ lIndex = -1
+ vProperties = pvPropertyValue
+ For i = 0 To UBound(vProperties)
+ If vProperties(i).Name = psName Then
+ lIndex = i
+ Exit For
+ End If
+ Next i
+ If lIndex &lt; 0 Then &apos; Not found
+ lIndex = UBound(vProperties) + 1
+ ReDim Preserve vProperties(0 To lIndex)
+ Set oPropertyValue = SF_Utils._MakePropertyValue(psName, pvValue)
+ vProperties(lIndex) = oPropertyValue
+ vProperties = vProperties
+ Else &apos; psName exists already in array of property values
+ vProperties(lIndex).Value = SF_Utils._CPropertyValue(pvValue)
+ End If
+
+ _SetPropertyValue = vProperties
+
+End Function &apos; ScriptForge.SF_Utils._SetPropertyValue
+
+REM -----------------------------------------------------------------------------
+Private Function _TypeNames(Optional ByVal pvArgs As Variant) As String
+&apos;&apos;&apos; Converts the array of VarTypes to a comma-separated list of TypeNames
+
+Dim sTypes As String &apos; Return value
+Dim sType As String &apos; A single type
+Dim iType As Integer &apos; A single item of the argument
+
+ _TypeNames = &quot;&quot;
+ If IsMissing(pvArgs) Then Exit Function
+ If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
+ sTypes = &quot;&quot;
+ For Each iType In pvArgs
+ Select Case iType
+ Case V_EMPTY : sType = &quot;Empty&quot;
+ Case V_NULL : sType = &quot;Null&quot;
+ Case V_INTEGER : sType = &quot;Integer&quot;
+ Case V_LONG : sType = &quot;Long&quot;
+ Case V_SINGLE : sType = &quot;Single&quot;
+ Case V_DOUBLE : sType = &quot;Double&quot;
+ Case V_CURRENCY : sType = &quot;Currency&quot;
+ Case V_DATE : sType = &quot;Date&quot;
+ Case V_STRING : sType = &quot;String&quot;
+ Case V_OBJECT : sType = &quot;Object&quot;
+ Case V_BOOLEAN : sType = &quot;Boolean&quot;
+ Case V_VARIANT : sType = &quot;Variant&quot;
+ Case V_DECIMAL : sType = &quot;Decimal&quot;
+ Case &gt;= V_ARRAY : sType = &quot;Array&quot;
+ Case V_NUMERIC : sType = &quot;Numeric&quot;
+ End Select
+ If Len(sTypes) = 0 Then sTypes = sType Else sTypes = sTypes &amp; &quot;, &quot; &amp; sType
+ Next iType
+ _TypeNames = sTypes
+
+End Function &apos; ScriptForge.SF_Utils._TypeNames
+
+REM -----------------------------------------------------------------------------
+Public Function _Validate(Optional ByRef pvArgument As Variant _
+ , ByVal psName As String _
+ , Optional ByVal pvTypes As Variant _
+ , Optional ByVal pvValues As Variant _
+ , Optional ByVal pvRegex As Variant _
+ , Optional ByVal pvObjectType As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Validate the arguments set by user scripts
+&apos;&apos;&apos; The arguments of the function define the validation rules
+&apos;&apos;&apos; This function ignores arrays. Use _ValidateArray instead
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArgument: the argument to (in)validate
+&apos;&apos;&apos; psName: the documented name of the argument (can be inserted in an error message)
+&apos;&apos;&apos; pvTypes: array of allowed VarTypes
+&apos;&apos;&apos; pvValues: array of allowed values
+&apos;&apos;&apos; pvRegex: regular expression to comply with
+&apos;&apos;&apos; pvObjectType: mandatory Basic class
+&apos;&apos;&apos; Return: True if validation OK
+&apos;&apos;&apos; Otherwise an error is raised
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARGUMENTERROR
+
+Dim iVarType As Integer &apos; Extended VarType of argument
+Dim bValid As Boolean &apos; Returned value
+Dim oObjectDescriptor As Object &apos; _ObjectDescriptor type
+Const cstMaxLength = 256 &apos; Maximum length of readable value
+Const cstMaxValues = 10 &apos; Maximum number of allowed items to list in an error message
+
+ &apos; To avoid useless recursions, keep main function, only increase stack depth
+ _SF_.StackLevel = _SF_.StackLevel + 1
+ On Local Error GoTo Finally &apos; Do never interrupt
+
+Try:
+ bValid = True
+ If IsMissing(pvArgument) Then GoTo CatchMissing
+ If IsMissing(pvRegex) Or IsEmpty(pvRegex) Then pvRegex = &quot;&quot;
+ If IsMissing(pvObjectType) Or IsEmpty(pvObjectType) Then pvObjectType = &quot;&quot;
+ iVarType = SF_Utils._VarTypeExt(pvArgument)
+
+ &apos; Arrays NEVER pass validation
+ If iVarType &gt;= V_ARRAY Then
+ bValid = False
+ Else
+ &apos; Check existence of argument
+ bValid = iVarType &lt;&gt; V_NULL And iVarType &lt;&gt; V_EMPTY
+ &apos; Check if argument&apos;s VarType is valid
+ If bValid And Not IsMissing(pvTypes) Then
+ If Not IsArray(pvTypes) Then bValid = ( pvTypes = iVarType ) Else bValid = SF_Array.Contains(pvTypes, iVarType)
+ End If
+ &apos; Check if argument&apos;s value is valid
+ If bValid And Not IsMissing(pvValues) Then
+ If Not IsArray(pvValues) Then pvValues = Array(pvValues)
+ bValid = SF_Array.Contains(pvValues, pvArgument, CaseSensitive := False)
+ End If
+ &apos; Check regular expression
+ If bValid And Len(pvRegex) &gt; 0 And iVarType = V_STRING Then
+ If Len(pvArgument) &gt; 0 Then bValid = SF_String.IsRegex(pvArgument, pvRegex, CaseSensitive := False)
+ End If
+ &apos; Check instance types
+ If bValid And Len(pvObjectType) &gt; 0 And iVarType = V_OBJECT Then
+ &apos;Set oArgument = pvArgument
+ Set oObjectDescriptor = SF_Utils._VarTypeObj(pvArgument)
+ bValid = ( oObjectDescriptor.iVarType = V_SFOBJECT )
+ If bValid Then bValid = ( oObjectDescriptor.sObjectType = pvObjectType )
+ End If
+ End If
+
+ If Not bValid Then
+ &apos;&apos;&apos; Library: ScriptForge
+ &apos;&apos;&apos; Service: Array
+ &apos;&apos;&apos; Method: Contains
+ &apos;&apos;&apos; Arguments: Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;]
+ &apos;&apos;&apos; A serious error has been detected on argument SortOrder
+ &apos;&apos;&apos; Rules: SortOrder is of type String
+ &apos;&apos;&apos; SortOrder must contain one of next values: &quot;ASC&quot;, &quot;DESC&quot;, &quot;&quot;
+ &apos;&apos;&apos; Actual value: &quot;Ascending&quot;
+ SF_Exception.RaiseFatal(ARGUMENTERROR _
+ , SF_Utils._Repr(pvArgument, cstMaxLength), psName, SF_Utils._TypeNames(pvTypes) _
+ , SF_Utils._ReprValues(pvValues, cstMaxValues), pvRegex, pvObjectType _
+ )
+ End If
+
+Finally:
+ _Validate = bValid
+ _SF_.StackLevel = _SF_.StackLevel - 1
+ Exit Function
+CatchMissing:
+ bValid = False
+ SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Utils._Validate
+
+REM -----------------------------------------------------------------------------
+Public Function _ValidateArray(Optional ByRef pvArray As Variant _
+ , ByVal psName As String _
+ , Optional ByVal piDimensions As Integer _
+ , Optional ByVal piType As Integer _
+ , Optional ByVal pbNotNull As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Validate the (array) arguments set by user scripts
+&apos;&apos;&apos; The arguments of the function define the validation rules
+&apos;&apos;&apos; This function ignores non-arrays. Use _Validate instead
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArray: the argument to (in)validate
+&apos;&apos;&apos; psName: the documented name of the array (can be inserted in an error message)
+&apos;&apos;&apos; piDimensions: the # of dimensions the array must have. 0 = Any (default)
+&apos;&apos;&apos; piType: (default = -1, i.e. not applicable)
+&apos;&apos;&apos; For 2D arrays, the 1st column is checked
+&apos;&apos;&apos; 0 =&gt; all items must be any out of next types: string, date or numeric,
+&apos;&apos;&apos; but homogeneously: all strings or all dates or all numeric
+&apos;&apos;&apos; V_STRING or V_DATE or V_NUMERIC =&gt; that specific type is required
+&apos;&apos;&apos; pbNotNull: piType must be &gt;=0, otherwise ignored
+&apos;&apos;&apos; If True: Empty, Null items are rejected
+&apos;&apos;&apos; Return: True if validation OK
+&apos;&apos;&apos; Otherwise an error is raised
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARRAYERROR
+
+Dim iVarType As Integer &apos; VarType of argument
+Dim vItem As Variant &apos; Array item
+Dim iItemType As Integer &apos; VarType of individual items of argument
+Dim iDims As Integer &apos; Number of dimensions of the argument
+Dim bValid As Boolean &apos; Returned value
+Dim iArrayType As Integer &apos; Static array type
+Dim iFirstItemType As Integer &apos; Type of 1st non-null/empty item
+Dim sType As String &apos; Allowed item types as a string
+Dim i As Long
+Const cstMaxLength = 256 &apos; Maximum length of readable value
+
+ &apos; To avoid useless recursions, keep main function, only increase stack depth
+
+ _SF_.StackLevel = _SF_.StackLevel + 1
+ On Local Error GoTo Finally &apos; Do never interrupt
+
+Try:
+ bValid = True
+ If IsMissing(pvArray) Then GoTo CatchMissing
+ If IsMissing(piDimensions) Then piDimensions = 0
+ If IsMissing(piType) Then piType = -1
+ If IsMissing(pbNotNull) Then pbNotNull = False
+ iVarType = VarType(pvArray)
+
+ &apos; Scalars NEVER pass validation
+ If iVarType &lt; V_ARRAY Then
+ bValid = False
+ Else
+ &apos; Check dimensions
+ iDims = SF_Array.CountDims(pvArray)
+ If iDims &gt; 2 Then bValid = False &apos; Only 1D and 2D arrays
+ If bValid And piDimensions &gt; 0 Then
+ bValid = ( iDims = piDimensions Or (iDims = 0 And piDimensions = 1) ) &apos; Allow empty vectors
+ End If
+ &apos; Check VarType and Empty/Null status of the array items
+ If bValid And iDims = 1 And piType &gt;= 0 Then
+ iArrayType = SF_Array._StaticType(pvArray)
+ If (piType = 0 And iArrayType &gt; 0) Or (piType &gt; 0 And iArrayType = piType) Then
+ &apos; If static array of the right VarType ..., OK
+ Else
+ &apos; Go through array and check individual items
+ iFirstItemType = -1
+ For i = LBound(pvArray, 1) To UBound(pvArray, 1)
+ If iDims = 1 Then vItem = pvArray(i) Else vItem = pvArray(i, LBound(pvArray, 2))
+ iItemType = SF_Utils._VarTypeExt(vItem)
+ If iItemType &gt; V_NULL Then &apos; Exclude Empty and Null
+ &apos; Initialization at first non-null item
+ If iFirstItemType &lt; 0 Then
+ iFirstItemType = iItemType
+ If piType &gt; 0 Then bValid = ( iFirstItemType = piType ) Else bValid = SF_Array.Contains(Array(V_STRING, V_DATE, V_NUMERIC), iFirstItemType)
+ Else
+ bValid = (iItemType = iFirstItemType)
+ End If
+ Else
+ bValid = Not pbNotNull
+ End If
+ If Not bValid Then Exit For
+ Next i
+ End If
+ End If
+ End If
+
+ If Not bValid Then
+ &apos;&apos;&apos; Library: ScriptForge
+ &apos;&apos;&apos; Service: Array
+ &apos;&apos;&apos; Method: Contains
+ &apos;&apos;&apos; Arguments: Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;|&quot;ASC&quot;|&quot;DESC&quot;]
+ &apos;&apos;&apos; An error was detected on argument Array_1D
+ &apos;&apos;&apos; Rules: Array_1D is of type Array
+ &apos;&apos;&apos; Array_1D must have maximum 1 dimension
+ &apos;&apos;&apos; Array_1D must have all elements of the same type: either String, Date or Numeric
+ &apos;&apos;&apos; Actual value: (0:2, 0:3)
+ sType = &quot;&quot;
+ If piType = 0 Then
+ sType = &quot;String, Date, Numeric&quot;
+ ElseIf piType &gt; 0 Then
+ sType = SF_Utils._TypeNames(piType)
+ End If
+ SF_Exception.RaiseFatal(ARRAYERROR _
+ , SF_Utils._Repr(pvArray, cstMaxLength), psName, piDimensions, sType, pbNotNull)
+ End If
+
+Finally:
+ _ValidateArray = bValid
+ _SF_.StackLevel = _SF_.StackLevel - 1
+ Exit Function
+CatchMissing:
+ bValid = False
+ SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Utils._ValidateArray
+
+REM -----------------------------------------------------------------------------
+Public Function _ValidateFile(Optional ByRef pvArgument As Variant _
+ , ByVal psName As String _
+ , Optional ByVal pbWildCards As Boolean _
+ , Optional ByVal pbSpace As Boolean _
+ )
+&apos;&apos;&apos; Validate the argument as a valid FileName
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArgument: the argument to (in)validate
+&apos;&apos;&apos; pbWildCards: if True, wildcard characters are accepted in the last component of the 1st argument
+&apos;&apos;&apos; pbSpace: if True, the argument may be an empty string. Default = False
+&apos;&apos;&apos; Return: True if validation OK
+&apos;&apos;&apos; Otherwise an error is raised
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ARGUMENTERROR
+
+Dim iVarType As Integer &apos; VarType of argument
+Dim sFile As String &apos; Alias for argument
+Dim bValid As Boolean &apos; Returned value
+Dim sFileNaming As String &apos; Alias of SF_FileSystem.FileNaming
+Dim oArgument As Variant &apos; Workaround &quot;Object variable not set&quot; error on 1st executable statement
+Const cstMaxLength = 256 &apos; Maximum length of readable value
+
+ &apos; To avoid useless recursions, keep main function, only increase stack depth
+
+ _SF_.StackLevel = _SF_.StackLevel + 1
+ On Local Error GoTo Finally &apos; Do never interrupt
+
+Try:
+ bValid = True
+ If IsMissing(pvArgument) Then GoTo CatchMissing
+ If IsMissing(pbWildCards) Then pbWildCards = False
+ If IsMissing(pbSpace) Then pbSpace = False
+ iVarType = VarType(pvArgument)
+
+ &apos; Arrays NEVER pass validation
+ If iVarType &gt;= V_ARRAY Then
+ bValid = False
+ Else
+ &apos; Argument must be a string containing a valid file name
+ bValid = ( iVarType = V_STRING )
+ If bValid Then
+ bValid = ( Len(pvArgument) &gt; 0 Or pbSpace )
+ If bValid And Len(pvArgument) &gt; 0 Then
+ &apos; Wildcards are replaced by arbitrary alpha characters
+ If pbWildCards Then
+ sFile = Replace(Replace(pvArgument, &quot;?&quot;, &quot;Z&quot;), &quot;*&quot;, &quot;A&quot;)
+ Else
+ sFile = pvArgument
+ bValid = ( InStr(sFile, &quot;?&quot;) + InStr(sFile, &quot;*&quot;) = 0 )
+ End If
+ &apos; Check file format without wildcards
+ If bValid Then
+ With SF_FileSystem
+ sFileNaming = .FileNaming
+ Select Case sFileNaming
+ Case &quot;ANY&quot; : bValid = SF_String.IsUrl(ConvertToUrl(sFile))
+ Case &quot;URL&quot; : bValid = SF_String.IsUrl(sFile)
+ Case &quot;SYS&quot; : bValid = SF_String.IsFileName(sFile)
+ End Select
+ End With
+ End If
+ &apos; Check that wildcards are only present in last component
+ If bValid And pbWildCards Then
+ sFile = SF_FileSystem.GetParentFolderName(pvArgument)
+ bValid = ( InStr(sFile, &quot;*&quot;) + InStr(sFile, &quot;?&quot;) + InStr(sFile,&quot;%3F&quot;) = 0 ) &apos; ConvertToUrl replaces ? by %3F
+ End If
+ End If
+ End If
+ End If
+
+ If Not bValid Then
+ &apos;&apos;&apos; Library: ScriptForge
+ &apos;&apos;&apos; Service: FileSystem
+ &apos;&apos;&apos; Method: CopyFile
+ &apos;&apos;&apos; Arguments: Source, Destination
+ &apos;&apos;&apos; A serious error has been detected on argument Source
+ &apos;&apos;&apos; Rules: Source is of type String
+ &apos;&apos;&apos; Source must be a valid file name expressed in operating system notation
+ &apos;&apos;&apos; Source may contain one or more wildcard characters in its last component
+ &apos;&apos;&apos; Actual value: /home/jean-*/SomeFile.odt
+ SF_Exception.RaiseFatal(FILEERROR _
+ , SF_Utils._Repr(pvArgument, cstMaxLength), psName, pbWildCards)
+ End If
+
+Finally:
+ _ValidateFile = bValid
+ _SF_.StackLevel = _SF_.StackLevel - 1
+ Exit Function
+CatchMissing:
+ bValid = False
+ SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Utils._ValidateFile
+
+REM -----------------------------------------------------------------------------
+Public Function _VarTypeExt(ByRef pvValue As Variant) As Integer
+&apos;&apos;&apos; Return the VarType of the argument but all numeric types are aggregated into V_NUMERIC
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvValue: value to examine
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; The extended VarType
+
+Dim iType As Integer &apos; VarType of argument
+
+ iType = VarType(pvValue)
+ Select Case iType
+ Case V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE, V_CURRENCY, V_BIGINT, V_DECIMAL
+ _VarTypeExt = V_NUMERIC
+ Case Else : _VarTypeExt = iType
+ End Select
+
+End Function &apos; ScriptForge.SF_Utils._VarTypeExt
+
+REM -----------------------------------------------------------------------------
+Public Function _VarTypeObj(ByRef pvValue As Variant) As Object
+&apos;&apos;&apos; Inspect the argument that is supposed to be an Object
+&apos;&apos;&apos; Return the internal type of object as one of the values
+&apos;&apos;&apos; V_NOTHING Null object
+&apos;&apos;&apos; V_UNOOBJECT Uno object or Uno structure
+&apos;&apos;&apos; V_SFOBJECT ScriptForge object: has ObjectType and ServiceName properties
+&apos;&apos;&apos; V_BASICOBJECT User Basic object
+&apos;&apos;&apos; coupled with object type as a string (&quot;com.sun.star...&quot; or &quot;SF_...&quot; or &quot;... ScriptForge class ...&quot;)
+&apos;&apos;&apos; When the argument is not an Object, return the usual VarType() of the argument
+
+Dim oObjDesc As _ObjectDescriptor &apos; Return value
+Dim oValue As Object &apos; Alias of pvValue used to avoid &quot;Object variable not set&quot; error
+Dim sObjType As String &apos; The type of object is first derived as a string
+Dim oReflection As Object &apos; com.sun.star.reflection.CoreReflection
+Dim vClass As Variant &apos; com.sun.star.reflection.XIdlClass
+Dim bUno As Boolean &apos; True when object recognized as UNO object
+
+Const cstBasicClass = &quot;com.sun.star.script.NativeObjectWrapper&quot; &apos; Way to recognize Basic objects
+
+ On Local Error Resume Next &apos; Object type is established by trial and error
+
+Try:
+ With oObjDesc
+ .iVarType = VarType(pvValue)
+ .sObjectType = &quot;&quot;
+ .sServiceName = &quot;&quot;
+ bUno = False
+ If .iVarType = V_OBJECT Then
+ If IsNull(pvValue) Then
+ .iVarType = V_NOTHING
+ Else
+ Set oValue = pvValue
+ &apos; Try UNO type with usual ImplementationName property
+ .sObjectType = oValue.getImplementationName()
+ If .sObjectType = &quot;&quot; Then
+ &apos; Try UNO type with alternative CoreReflection trick
+ Set oReflection = SF_Utils._GetUNOService(&quot;CoreReflection&quot;)
+ vClass = oReflection.getType(oValue)
+ If vClass.TypeClass &gt;= com.sun.star.uno.TypeClass.STRUCT Then
+ .sObjectType = vClass.Name
+ bUno = True
+ End If
+ Else
+ bUno = True
+ End If
+ &apos; Identify Basic objects
+ If .sObjectType = cstBasicClass Then
+ bUno = False
+ &apos; Try if the Basic object has an ObjectType property
+ .sObjectType = oValue.ObjectType
+ .sServiceName = oValue.ServiceName
+ End If
+ &apos; Derive the return value from the object type
+ Select Case True
+ Case Len(.sObjectType) = 0 &apos; Do nothing (return V_OBJECT)
+ Case .sObjectType = cstBasicClass : .iVarType = V_BASICOBJECT
+ Case bUno : .iVarType = V_UNOOBJECT
+ Case Else : .iVarType = V_SFOBJECT
+ End Select
+ End If
+ End If
+ End With
+
+Finally:
+ Set _VarTypeObj = oObjDesc
+ Exit Function
+End Function &apos; ScriptForge.SF_Utils._VarTypeObj
+
+REM ================================================= END OF SCRIPTFORGE.SF_UTILS
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/_CodingConventions.xba b/wizards/source/scriptforge/_CodingConventions.xba
new file mode 100644
index 000000000..71fb42c77
--- /dev/null
+++ b/wizards/source/scriptforge/_CodingConventions.xba
@@ -0,0 +1,100 @@
+<?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="_CodingConventions" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+&apos;&apos;&apos;
+&apos; Conventions used in the coding of the *ScriptForge* library
+&apos; -----------------------------------------------------------
+&apos;&apos;&apos;
+&apos; Library and Modules
+&apos; ===================
+&apos; * Module names are all prefixed with &quot;SF_&quot;.
+&apos; * The *Option Explicit* statement is mandatory in every module.
+&apos; * The *Option Private Module* statement is recommended in internal modules.
+&apos; * A standard header presenting the module/class is mandatory
+&apos; * An end of file (eof) comment line is mandatory
+&apos; * Every module lists the constants that are related to it and documented as return values, arguments, etc.
+&apos; They are defined as *Global Const*.
+&apos; The scope of global constants being limited to one single library, their invocation from user scripts shall be qualified.
+&apos; * The Basic reserved words are *Proper-Cased*.
+&apos;&apos;&apos;
+&apos; Functions and Subroutines
+&apos; =========================
+&apos; * LibreOffice ignores the Private/Public attribute in Functions or Subs declarations.
+&apos; Nevertheless the attribute must be present.
+&apos; Rules to recognize their scope are:
+&apos; * Public + name starts with a letter
+&apos; The Sub/Function belongs to the official ScriptForge API.
+&apos; As such it may be called from any user script.
+&apos; * Public + name starts with an underscore &quot;_&quot;
+&apos; The Sub/Function may be called only from within the ScriptForge library.
+&apos; As such it MUST NOT be called from another library or from a user script,
+&apos; as there is no guarantee about the arguments, the semantic or even the existence of that piece of code in a later release.
+&apos; * Private - The Sub/Function name must start with an underscore &quot;_&quot;.
+&apos; The Sub/Function may be called only from the module in which it is located.
+&apos; * Functions and Subroutines belonging to the API (= &quot;standard&quot; functions/Subs) are defined in their module in alphabetical order.
+&apos; For class modules, all the properties precede the methods which precede the events.
+&apos; * Functions and Subroutines not belonging to the API are defined in their module in alphabetical order below the standard ones.
+&apos; * The return value of a function is always declared explicitly.
+&apos; * The parameters are always declared explicitly even if they&apos;re variants.
+&apos; * The Function and Sub declarations start at the 1st column of the line.
+&apos; * The End Function/Sub statement is followed by a comment reminding the name of the containing library.module and of the function or sub.
+&apos; If the Function/Sub is declared for the first time or modified in a release &gt; initial public release, the actual release number is mentioned as well.
+&apos;&apos;&apos;
+&apos; Variable declarations
+&apos; =====================
+&apos; * Variable names use only alpha characters, the underscore and digits (no accented characters).
+&apos; Exceptionally, names of private variables may be embraced with `[` and `]` if `Option Compatible` is present.
+&apos; * The Global, Dim and Const statements always start in the first column of the line.
+&apos; * The type (*Dim ... As ...*, *Function ... As ...*) is always declared explicitly, even if the type is Variant.
+&apos; * Variables are *Proper-Cased*. They are always preceded by a lower-case letter indicating their type.
+&apos; With next exception: variables i, j, k, l, m and n must be declared as integers or longs.
+&apos; &gt; b Boolean
+&apos; &gt; d Date
+&apos; &gt; v Variant
+&apos; &gt; o Object
+&apos; &gt; i Integer
+&apos; &gt; l Long
+&apos; &gt; s String
+&apos; Example:
+&apos; Dim sValue As String
+&apos; * Parameters are preceded by the letter *p* which itself precedes the single *typing letter*.
+&apos; In official methods, to match their published documentation, the *p* and the *typing letter* may be omitted. Like in:
+&apos; Private Function MyFunction(psValue As String) As Variant
+&apos; Public Function MyOfficialFunction(Value As String) As Variant
+&apos; * Global variables in the ScriptForge library are ALL preceded by an underscore &quot;_&quot; as NONE of them should be invoked from outside the library.
+&apos; * Constant values with a local scope are *Proper-Cased* and preceded by the letters *cst*.
+&apos; * Constants with a global scope are *UPPER-CASED*.
+&apos; Example:
+&apos; Global Const ACONSTANT = &quot;This is a global constant&quot;
+&apos; Function MyFunction(pocControl As Object, piValue) As Variant
+&apos; Dim iValue As Integer
+&apos; Const cstMyConstant = 3
+&apos;&apos;&apos;
+&apos; Indentation
+&apos; ===========
+&apos; Code shall be indented with TAB characters.
+&apos;&apos;&apos;
+&apos; Goto/Gosub
+&apos; ==========
+&apos; The *GoSub* … *Return* statement is forbidden.
+&apos; The *GoTo* statement is forbidden.
+&apos; However *GoTo* is highly recommended for *error* and *exception* handling.
+&apos;&apos;&apos;
+&apos; Comments (english only)
+&apos; ========
+&apos; * Every public routine should be documented with a python-like &quot;docstring&quot;:
+&apos; 1. Role of Sub/Function
+&apos; 2. List of arguments, mandatory/optional, role
+&apos; 3. Returned value(s) type and meaning
+&apos; 4. Examples when useful
+&apos; 5. Eventual specific exception codes
+&apos; * The &quot;docstring&quot; comments shall be marked by a triple (single) quote character at the beginning of the line
+&apos; * Meaningful variables shall be declared one per line. Comment on same line.
+&apos; * Comments about a code block should be left indented.
+&apos; If it concerns only the next line, no indent required (may also be put at the end of the line).
+&apos;&apos;&apos;
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/_ModuleModel.xba b/wizards/source/scriptforge/_ModuleModel.xba
new file mode 100644
index 000000000..135eced58
--- /dev/null
+++ b/wizards/source/scriptforge/_ModuleModel.xba
@@ -0,0 +1,221 @@
+<?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="_ModuleModel" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+&apos;Option Private Module
+
+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; ModuleModel (aka SF_Model)
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; Illustration of how the ScriptForge modules are structured
+&apos;&apos;&apos; Copy and paste this code in an empty Basic module to start a new service
+&apos;&apos;&apos; Comment in, comment out, erase what you want, but at the end respect the overall structure
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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
+
+&apos;&apos;&apos; FAKENEWSERROR
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object &apos; Should be initialized immediately after the New statement
+ &apos; Dim obj As Object : Set obj = New SF_Model
+ &apos; Set obj.[Me] = obj
+Private [_Parent] As Object &apos; To keep trace of the instance having created a sub-instance
+ &apos; Set obj._Parent = [Me]
+Private ObjectType As String &apos; Must be UNIQUE
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const SOMECONSTANT = 1
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;MODEL&quot;
+End Sub &apos; ScriptForge.SF_Model Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; ScriptForge.SF_Model Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_Model Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get MyProperty() As Boolean
+&apos;&apos;&apos; Returns True or False
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myModel.MyProperty
+
+ MyProperty = _PropertyGet(&quot;MyProperty&quot;)
+
+End Property &apos; ScriptForge.SF_Model.MyProperty
+
+REM ===================================================================== METHODS
+
+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;Model.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Model.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;MyFunction&quot; _
+ , &quot;etc&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Model.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function MyFunction(Optional ByVal Arg1 As Variant _
+ , Optional ByVal Arg2 As Variant _
+ ) As Variant
+&apos;&apos;&apos; Fictive function that concatenates Arg1 Arg2 times
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Arg1 String Text
+&apos;&apos;&apos; Arg2 Numeric Number of times (default = 2)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new string
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FAKENEWSERROR
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; MyFunction(&quot;value1&quot;) returns &quot;value1value1&quot;
+
+Dim sOutput As String &apos; Output buffer
+Dim i As Integer
+Const cstThisSub = &quot;Model.myFunction&quot;
+Const cstSubArgs = &quot;Arg1, [Arg2=2]&quot;
+
+ &apos; _ErrorHandling returns False when, for debugging, the standard error handling is preferred
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ myFunction = &quot;&quot;
+
+Check:
+ If IsMissing(Arg2) Then Arg2 = 2
+ &apos; _EnterFunction returns True when current method is invoked from a user script
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ &apos; Check Arg1 is a string and Arg2 is a number.
+ &apos; Validation rules for scalars and arrays are described in SF_Utils
+ If Not SF_Utils._Validate(Arg1, &quot;Arg1&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Arg2, &quot;Arg2&quot;, V_NUMERIC) Then GoTo Finally
+ &apos; Fatal error ?
+ If Arg2 &lt; 0 Then GoTo CatchFake
+ End If
+
+Try:
+ sOutput = &quot;&quot;
+ For i = 0 To Arg2
+ sOutput = sOutput &amp; Arg1
+ Next i
+ myFunction = sOutput
+
+Finally:
+ &apos; _ExitFunction manages internal (On Local) errors
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchFake:
+ SF_Exception.RaiseFatal(&quot;FAKENEWSERROR&quot;, cstThisSub)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Model.myFunction
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Model class as an array
+
+ Properties = Array( _
+ &quot;MyProperty&quot; _
+ , &quot;etc&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_Model.Properties
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+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 cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SF_Model.get&quot; &amp; psProperty
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case psProperty
+ Case &quot;MyProperty&quot;
+ _PropertyGet = TBD
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; ScriptForge.SF_Model._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[MODEL]: A readable string&quot;
+
+ _Repr = &quot;[MODEL]: A readable string&quot;
+
+End Function &apos; ScriptForge.SF_Model._Repr
+
+REM ============================================ END OF SCRIPTFORGE.SF_MODEL
+</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/__License.xba b/wizards/source/scriptforge/__License.xba
new file mode 100644
index 000000000..a81752525
--- /dev/null
+++ b/wizards/source/scriptforge/__License.xba
@@ -0,0 +1,25 @@
+<?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-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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/scriptforge/dialog.xlb b/wizards/source/scriptforge/dialog.xlb
new file mode 100644
index 000000000..7b54d071c
--- /dev/null
+++ b/wizards/source/scriptforge/dialog.xlb
@@ -0,0 +1,6 @@
+<?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="ScriptForge" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="dlgConsole"/>
+ <library:element library:name="dlgProgress"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/scriptforge/dlgConsole.xdl b/wizards/source/scriptforge/dlgConsole.xdl
new file mode 100644
index 000000000..64009f571
--- /dev/null
+++ b/wizards/source/scriptforge/dlgConsole.xdl
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="dlgConsole" dlg:left="114" dlg:top="32" dlg:width="321" dlg:height="239" dlg:closeable="true" dlg:moveable="true" dlg:title="ScriptForge">
+ <dlg:styles>
+ <dlg:style dlg:style-id="0" dlg:font-name="Courier New" dlg:font-stylename="Regular" dlg:font-family="modern"/>
+ </dlg:styles>
+ <dlg:bulletinboard>
+ <dlg:textfield dlg:style-id="0" dlg:id="ConsoleLines" dlg:tab-index="0" dlg:left="4" dlg:top="2" dlg:width="312" dlg:height="225" dlg:hscroll="true" dlg:vscroll="true" dlg:multiline="true" dlg:readonly="true"/>
+ <dlg:button dlg:id="CloseNonModalButton" dlg:tab-index="2" dlg:left="265" dlg:top="228" dlg:width="50" dlg:height="10" dlg:default="true" dlg:image-src="private:graphicrepository/cmd/sc_cancel.png">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ScriptForge.SF_Exception._CloseConsole?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="CloseModalButton" dlg:tab-index="1" dlg:left="265" dlg:top="228" dlg:width="50" dlg:height="10" dlg:default="true" dlg:button-type="ok" dlg:image-src="private:graphicrepository/cmd/sc_cancel.png"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/scriptforge/dlgProgress.xdl b/wizards/source/scriptforge/dlgProgress.xdl
new file mode 100644
index 000000000..9d5f2776d
--- /dev/null
+++ b/wizards/source/scriptforge/dlgProgress.xdl
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="dlgProgress" dlg:left="180" dlg:top="90" dlg:width="275" dlg:height="37" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="ProgressText" dlg:tab-index="1" dlg:left="16" dlg:top="7" dlg:width="245" dlg:height="8" dlg:value="ProgressText" dlg:tabstop="true"/>
+ <dlg:progressmeter dlg:id="ProgressBar" dlg:tab-index="0" dlg:left="16" dlg:top="18" dlg:width="190" dlg:height="10" dlg:value="50"/>
+ <dlg:button dlg:id="CloseButton" dlg:tab-index="2" dlg:left="210" dlg:top="18" dlg:width="50" dlg:height="10" dlg:image-src="private:graphicrepository/cmd/sc_cancel.png">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ScriptForge.SF_UI._CloseProgressBar?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/scriptforge/po/ScriptForge.pot b/wizards/source/scriptforge/po/ScriptForge.pot
new file mode 100644
index 000000000..248d800c0
--- /dev/null
+++ b/wizards/source/scriptforge/po/ScriptForge.pot
@@ -0,0 +1,975 @@
+#
+# This pristine POT file has been generated by LibreOffice/ScriptForge
+# Full documentation is available on https://help.libreoffice.org/
+#
+# *********************************************************************
+# *** The ScriptForge library and its associated libraries ***
+# *** are part of the LibreOffice project. ***
+# *********************************************************************
+#
+# ScriptForge Release 7.4
+# -----------------------
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
+"POT-Creation-Date: 2022-05-04 18:07:20\n"
+"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
+"Language: en_US\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: LibreOffice - ScriptForge\n"
+"X-Accelerator-Marker: ~\n"
+
+#. Title in error message box
+#. %1: an error number
+#, kde-format
+msgctxt "ERRORNUMBER"
+msgid "Error %1"
+msgstr ""
+
+#. Error message box
+#. %1: a line number
+#, kde-format
+msgctxt "ERRORLOCATION"
+msgid "Location : %1"
+msgstr ""
+
+#. Logfile record
+#, kde-format
+msgctxt "LONGERRORDESC"
+msgid "Error %1 - Location = %2 - Description = %3"
+msgstr ""
+
+#. Any blocking error message
+msgctxt "STOPEXECUTION"
+msgid "THE EXECUTION IS CANCELLED."
+msgstr ""
+
+#. Any blocking error message
+#. %1: a method name
+#, kde-format
+msgctxt "NEEDMOREHELP"
+msgid "Do you want to receive more information about the '%1' method ?"
+msgstr ""
+
+#. SF_Exception.RaiseAbort error message
+msgctxt "INTERNALERROR"
+msgid ""
+"The ScriptForge library has crashed. The reason is unknown.\n"
+"Maybe a bug that could be reported on\n"
+" https://bugs.documentfoundation.org/\n"
+"\n"
+"More details : \n"
+"\n"
+""
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: probably ScriptForge
+#. %2: service or module name
+#. %3: property or method name where the error occurred
+#, kde-format
+msgctxt "VALIDATESOURCE"
+msgid ""
+"Library : %1\n"
+"Service : %2\n"
+"Method : %3"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: list of arguments of the method
+#, kde-format
+msgctxt "VALIDATEARGS"
+msgid "Arguments: %1"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEERROR"
+msgid "A serious error has been detected in your code on argument : « %1 »."
+msgstr ""
+
+#. SF_Utils.Validate error message
+msgctxt "VALIDATIONRULES"
+msgid " Validation rules :"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: Comma separated list of allowed types
+#, kde-format
+msgctxt "VALIDATETYPES"
+msgid " « %1 » must have next type (or one of next types) : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: Comma separated list of allowed values
+#, kde-format
+msgctxt "VALIDATEVALUES"
+msgid " « %1 » must contain one of next values : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: A regular expression
+#, kde-format
+msgctxt "VALIDATEREGEX"
+msgid " « %1 » must match next regular expression : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: The name of a Basic class
+#, kde-format
+msgctxt "VALIDATECLASS"
+msgid " « %1 » must be a Basic object of class : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: The value of the argument as a string
+#, kde-format
+msgctxt "VALIDATEACTUAL"
+msgid "The actual value of « %1 » is : '%2'"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEMISSING"
+msgid "The « %1 » argument is mandatory, yet it is missing."
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEARRAY"
+msgid " « %1 » must be an array."
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. %2: Number of dimensions of the array
+#, kde-format
+msgctxt "VALIDATEDIMS"
+msgid " « %1 » must have exactly %2 dimension(s)."
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. %2: Either one single type or 'String, Date, Numeric'
+#, kde-format
+msgctxt "VALIDATEALLTYPES"
+msgid " « %1 » must have all elements of the same type : %2"
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. NULL and EMPTY should not be translated
+#, kde-format
+msgctxt "VALIDATENOTNULL"
+msgid " « %1 » must not contain any NULL or EMPTY elements."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. 'String' should not be translated
+#, kde-format
+msgctxt "VALIDATEFILE"
+msgid " « %1 » must be of type String."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEFILESYS"
+msgid ""
+" « %1 » must be a valid file or folder name expressed in the "
+"operating system native notation."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. 'URL' should not be translated
+#, kde-format
+msgctxt "VALIDATEFILEURL"
+msgid ""
+" « %1 » must be a valid file or folder name expressed in the "
+"portable URL notation."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEFILEANY"
+msgid " « %1 » must be a valid file or folder name."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. '(?, *)' is to be left as is
+#, kde-format
+msgctxt "VALIDATEWILDCARD"
+msgid ""
+" « %1 » may contain one or more wildcard characters (?, *) in "
+"its last path component only."
+msgstr ""
+
+#. SF_Array.RangeInit error message
+#. %1, %2, %3: Numeric values
+#. 'From', 'UpTo', 'ByStep' should not be translated
+#, kde-format
+msgctxt "ARRAYSEQUENCE"
+msgid ""
+"The respective values of 'From', 'UpTo' and 'ByStep' are incoherent.\n"
+"\n"
+" « From » = %1\n"
+" « UpTo » = %2\n"
+" « ByStep » = %3"
+msgstr ""
+
+#. SF_Array.AppendColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_2D' should not be translated
+#, kde-format
+msgctxt "ARRAYINSERT"
+msgid ""
+"The array and the vector to insert have incompatible sizes.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+msgstr ""
+
+#. SF_Array.ExtractColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_2D' should not be translated
+#, kde-format
+msgctxt "ARRAYINDEX1"
+msgid ""
+"The given index does not fit within the bounds of the array.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+msgstr ""
+
+#. SF_Array.ExtractColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_1D', 'From' and 'UpTo' should not be translated
+#, kde-format
+msgctxt "ARRAYINDEX2"
+msgid ""
+"The given slice limits do not fit within the bounds of the array.\n"
+"\n"
+" « Array_1D » = %1\n"
+" « From » = %2\n"
+" « UpTo » = %3"
+msgstr ""
+
+#. SF_Array.ImportFromCSVFile error message
+#. %1: a file name
+#. %2: numeric
+#. %3: a long string
+#, kde-format
+msgctxt "CSVPARSING"
+msgid ""
+"The given file could not be parsed as a valid CSV file.\n"
+"\n"
+" « File name » = %1\n"
+" Line number = %2\n"
+" Content = %3"
+msgstr ""
+
+#. SF_Dictionary Add/ReplaceKey error message
+#. %1: An identifier%2: a (potentially long) string
+#, kde-format
+msgctxt "DUPLICATEKEY"
+msgid ""
+"The insertion of a new key into a dictionary failed because the key "
+"already exists.\n"
+"Note that the comparison between keys is NOT case-sensitive.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Dictionary Remove/ReplaceKey/ReplaceItem error message
+#. %1: An identifier%2: a (potentially long) string
+#, kde-format
+msgctxt "UNKNOWNKEY"
+msgid ""
+"The requested key does not exist in the dictionary.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Dictionary Add/ReplaceKey error message
+#.
+msgctxt "INVALIDKEY"
+msgid ""
+"The insertion or the update of an entry into a dictionary failed "
+"because the given key contains only spaces."
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "UNKNOWNFILE"
+msgid ""
+"The given file could not be found on your system.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A folder name
+#, kde-format
+msgctxt "UNKNOWNFOLDER"
+msgid ""
+"The given folder could not be found on your system.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "NOTAFILE"
+msgid ""
+"« %1 » contains the name of an existing folder, not that of a file.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A folder name
+#, kde-format
+msgctxt "NOTAFOLDER"
+msgid ""
+"« %1 » contains the name of an existing file, not that of a folder.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/... error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "OVERWRITE"
+msgid ""
+"You tried to create a new file which already exists. Overwriting it "
+"has been rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "READONLY"
+msgid ""
+"Copying or moving a file to a destination which has its read-only "
+"attribute set, or deleting such a file or folder is forbidden.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file or folder name with wildcards
+#, kde-format
+msgctxt "NOFILEMATCH"
+msgid ""
+"When « %1 » contains wildcards. at least one file or folder must "
+"match the given filter. Otherwise the operation is rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem CreateFolder error message
+#. %1: An identifier
+#. %2: A file or folder name
+#, kde-format
+msgctxt "FOLDERCREATION"
+msgid ""
+"« %1 » contains the name of an existing file or an existing folder. "
+"The operation is rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Services.CreateScriptService error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A Basic library name
+#. %4: A service (1 word) name
+#, kde-format
+msgctxt "UNKNOWNSERVICE"
+msgid ""
+"No service named '%4' has been registered for the library '%3'.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Services.CreateScriptService error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A Basic library name
+#, kde-format
+msgctxt "SERVICESNOTLOADED"
+msgid ""
+"The library '%3' and its services could not been loaded.\n"
+"The reason is unknown.\n"
+"However, checking the '%3.SF_Services.RegisterScriptServices()' "
+"function and its return value can be a good starting point.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Session.ExecuteCalcFunction error message
+#. 'Calc' should not be translated
+#, kde-format
+msgctxt "CALCFUNC"
+msgid ""
+"The Calc '%1' function encountered an error. Either the given "
+"function does not exist or its arguments are invalid."
+msgstr ""
+
+#. SF_Session._GetScript error message
+#. %1: 'Basic' or 'Python'
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#. %5: A string
+#, kde-format
+msgctxt "NOSCRIPT"
+msgid ""
+"The requested %1 script could not be located in the given libraries "
+"and modules.\n"
+"« %2 » = %3\n"
+"« %4 » = %5"
+msgstr ""
+
+#. SF_Session.ExecuteBasicScript error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A (long) string
+#, kde-format
+msgctxt "SCRIPTEXEC"
+msgid ""
+"An exception occurred during the execution of the Basic script.\n"
+"Cause: %3\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Session.SendMail error message
+#. %1 = a mail address
+#, kde-format
+msgctxt "WRONGEMAIL"
+msgid ""
+"One of the email addresses has been found invalid.\n"
+"Invalid mail = « %1 »"
+msgstr ""
+
+#. SF_Session.SendMail error message
+msgctxt "SENDMAIL"
+msgid ""
+"The message could not be sent due to a system error.\n"
+"A possible cause is that LibreOffice could not find any mail client."
+msgstr ""
+
+#. SF_TextStream._IsFileOpen error message
+#. %1: A file name
+#, kde-format
+msgctxt "FILENOTOPEN"
+msgid ""
+"The requested file operation could not be executed because the file "
+"was closed previously.\n"
+"\n"
+"File name = '%1'"
+msgstr ""
+
+#. SF_TextStream._IsFileOpen error message
+#. %1: A file name
+#. %2: READ, WRITE or APPEND
+#, kde-format
+msgctxt "FILEOPENMODE"
+msgid ""
+"The requested file operation could not be executed because it is "
+"incompatible with the mode in which the file was opened.\n"
+"\n"
+"File name = '%1'\n"
+"Open mode = %2"
+msgstr ""
+
+#. SF_TextStream.ReadLine/ReadAll/SkipLine error message
+#. %1: A file name
+#, kde-format
+msgctxt "ENDOFFILE"
+msgid ""
+"The requested file read operation could not be completed because an "
+"unexpected end-of-file was encountered.\n"
+"\n"
+"File name = '%1'"
+msgstr ""
+
+#. SF_UI.GetDocument error message
+#. %1: An identifier
+#. %2: A string
+#, kde-format
+msgctxt "DOCUMENT"
+msgid ""
+"The requested document could not be found.\n"
+"\n"
+"%1 = '%2'"
+msgstr ""
+
+#. SF_UI.GetDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#, kde-format
+msgctxt "DOCUMENTCREATION"
+msgid ""
+"The creation of a new document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the document type is unknown, or no template file was given,\n"
+"or the given template file was not found on your system.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+msgstr ""
+
+#. SF_UI.OpenDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#. %5: An identifier
+#. %6: A string
+#, kde-format
+msgctxt "DOCUMENTOPEN"
+msgid ""
+"The opening of the document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the file does not exist, or the password is wrong, or the "
+"given filter is invalid.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'\n"
+"%5 = '%6'"
+msgstr ""
+
+#. SF_UI.OpenDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#, kde-format
+msgctxt "BASEDOCUMENTOPEN"
+msgid ""
+"The opening of the Base document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the file does not exist, or the file is not registered under "
+"the given name.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+msgstr ""
+
+#. SF_Document._IsStillAlive error message
+#. %1: A file name
+#, kde-format
+msgctxt "DOCUMENTDEAD"
+msgid ""
+"The requested action could not be executed because the document was "
+"closed inadvertently.\n"
+"\n"
+"The concerned document is '%1'"
+msgstr ""
+
+#. SF_Document.SaveAs error message
+#. %1: An identifier
+#. %2: A file name
+#.
+#, kde-format
+msgctxt "DOCUMENTSAVE"
+msgid ""
+"The document could not be saved.\n"
+"Either the document has been opened read-only, or the destination "
+"file has a read-only attribute set, or the file where to save to is "
+"undefined.\n"
+"\n"
+"%1 = '%2'"
+msgstr ""
+
+#. SF_Document.SaveAs error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#. %5: An identifier
+#. %6: A string
+#, kde-format
+msgctxt "DOCUMENTSAVEAS"
+msgid ""
+"The document could not be saved.\n"
+"Either the document must not be overwritten, or the destination file "
+"has a read-only attribute set, or the given filter is invalid.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4\n"
+"%5 = '%6'"
+msgstr ""
+
+#. SF_Document any update
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "DOCUMENTREADONLY"
+msgid ""
+"You tried to edit a document which is not modifiable. The document "
+"has not been changed.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Base GetDatabase
+#. %1: An identifier
+#. %2: A user name
+#. %3: An identifier
+#. %4: A password
+#. %5: A file name
+#, kde-format
+msgctxt "DBCONNECT"
+msgid ""
+"The database related to the actual Base document could not be "
+"retrieved.\n"
+"Check the connection/login parameters.\n"
+"\n"
+"« %1 » = '%2'\n"
+"« %3 » = '%4'\n"
+"« Document » = %5"
+msgstr ""
+
+#. SF_Calc _ParseAddress (sheet)
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "CALCADDRESS1"
+msgid ""
+"The given address does not correspond with a valid sheet name.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+
+#. SF_Calc _ParseAddress (range)
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "CALCADDRESS2"
+msgid ""
+"The given address does not correspond with a valid range of cells.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+
+#. SF_Calc InsertSheet
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "DUPLICATESHEET"
+msgid ""
+"There exists already in the document a sheet with the same name.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+
+#. SF_Calc Offset
+#. %1: An identifier
+#. %2: A Calc reference
+#. %3: An identifier
+#. %4: A number
+#. %5: An identifier
+#. %6: A number
+#. %7: An identifier
+#. %8: A number
+#. %9: An identifier
+#. %10: A number
+#. %11: An identifier
+#. %12: A file name
+#, kde-format
+msgctxt "OFFSETADDRESS"
+msgid ""
+"The computed range falls beyond the sheet boundaries or is "
+"meaningless.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8\n"
+"« %9 » = %10\n"
+"« %11 » = %12"
+msgstr ""
+
+#. SF_Calc CreateChart
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#. %5: An identifier
+#. %6: A file name
+#, kde-format
+msgctxt "DUPLICATECHART"
+msgid ""
+"A chart with the same name exists already in the sheet.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+""
+msgstr ""
+
+#. SF_Calc.ExportRangeToFile error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#.
+#, kde-format
+msgctxt "RANGEEXPORT"
+msgid ""
+"The given range could not be exported.\n"
+"Either the destination file must not be overwritten, or it has a "
+"read-only attribute set.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4"
+msgstr ""
+
+#. SF_Chart.ExportToFile error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#.
+#, kde-format
+msgctxt "CHARTEXPORT"
+msgid ""
+"The chart could not be exported.\n"
+"Either the destination file must not be overwritten, or it has a "
+"read-only attribute set.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4"
+msgstr ""
+
+#. SF_Dialog._IsStillAlive error message
+#. %1: An identifier%2: A file name
+#, kde-format
+msgctxt "FORMDEAD"
+msgid ""
+"The requested action could not be executed because the form is not "
+"open or the document was closed inadvertently.\n"
+"\n"
+"The concerned form is '%1' in document '%2'."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A sheet name
+#. %3: A file name
+#, kde-format
+msgctxt "CALCFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the Calc sheet. The given "
+"index is off-limits.\n"
+"\n"
+"The concerned Calc document is '%3'.\n"
+"\n"
+"The name of the sheet = '%2'\n"
+"The index = %1."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A file name
+#, kde-format
+msgctxt "WRITERFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the Writer document. The "
+"given index is off-limits.\n"
+"\n"
+"The concerned Writer document is '%2'.\n"
+"\n"
+"The index = %1."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A string
+#. %3: A file name
+#, kde-format
+msgctxt "BASEFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the form document '%2'. The "
+"given index is off-limits.\n"
+"\n"
+"The concerned Base document is '%3'.\n"
+"\n"
+"The index = %1."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A form name
+#. %2: A form name
+#, kde-format
+msgctxt "SUBFORMNOTFOUND"
+msgid ""
+"The requested subform could not be found below the given main form.\n"
+"\n"
+"The main form = '%2'.\n"
+"The subform = '%1'."
+msgstr ""
+
+#. SF_FormControl property setting
+#. %1: An identifier
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#, kde-format
+msgctxt "FORMCONTROLTYPE"
+msgid ""
+"The control '%1' in form '%2' is of type '%3'.\n"
+"The property or method '%4' is not applicable on that type of form "
+"controls."
+msgstr ""
+
+#. SF_Dialog creation
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#. %5: An identifier
+#. %6: A string
+#. %7: An identifier
+#. %8: A string
+#, kde-format
+msgctxt "DIALOGNOTFOUND"
+msgid ""
+"The requested dialog could not be located in the given container or "
+"library.\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8"
+msgstr ""
+
+#. SF_Dialog._IsStillAlive error message
+#. %1: An identifier
+#, kde-format
+msgctxt "DIALOGDEAD"
+msgid ""
+"The requested action could not be executed because the dialog was "
+"closed inadvertently.\n"
+"\n"
+"The concerned dialog is '%1'."
+msgstr ""
+
+#. SF_DialogControl property setting
+#. %1: An identifier
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#, kde-format
+msgctxt "CONTROLTYPE"
+msgid ""
+"The control '%1' in dialog '%2' is of type '%3'.\n"
+"The property or method '%4' is not applicable on that type of dialog "
+"controls."
+msgstr ""
+
+#. SF_DialogControl add line in textbox
+#. %1: An identifier
+#. %2: An identifier
+#, kde-format
+msgctxt "TEXTFIELD"
+msgid ""
+"The control '%1' in dialog '%2' is not a multiline text field.\n"
+"The requested method could not be executed."
+msgstr ""
+
+#. SF_Database when running update SQL statement
+#. %1: The concerned method
+#, kde-format
+msgctxt "DBREADONLY"
+msgid ""
+"The database has been opened in read-only mode.\n"
+"The '%1' method must not be executed in this context."
+msgstr ""
+
+#. SF_Database can't interpret SQL statement
+#. %1: The statement
+#, kde-format
+msgctxt "SQLSYNTAX"
+msgid ""
+"An SQL statement could not be interpreted or executed by the "
+"database system.\n"
+"Check its syntax, table and/or field names, ...\n"
+"\n"
+"SQL Statement : « %1 »"
+msgstr ""
+
+#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
+msgctxt "PYTHONSHELL"
+msgid ""
+"The APSO extension could not be located in your LibreOffice "
+"installation."
+msgstr ""
+
+#. SFUnitTest could not locate the library gven as argument
+#. %1: The name of the library
+#, kde-format
+msgctxt "UNITTESTLIBRARY"
+msgid ""
+"The requested library could not be located.\n"
+"The UnitTest service has not been initialized.\n"
+"\n"
+"Library name : « %1 »"
+msgstr ""
+
+#. SFUnitTest finds a RunTest() call in a inappropriate location
+#. %1: The name of a method
+#, kde-format
+msgctxt "UNITTESTMETHOD"
+msgid ""
+"The method '%1' is unexpected in the current context.\n"
+"The UnitTest service cannot proceed further with the on-going test."
+msgstr "" \ No newline at end of file
diff --git a/wizards/source/scriptforge/po/en.po b/wizards/source/scriptforge/po/en.po
new file mode 100644
index 000000000..248d800c0
--- /dev/null
+++ b/wizards/source/scriptforge/po/en.po
@@ -0,0 +1,975 @@
+#
+# This pristine POT file has been generated by LibreOffice/ScriptForge
+# Full documentation is available on https://help.libreoffice.org/
+#
+# *********************************************************************
+# *** The ScriptForge library and its associated libraries ***
+# *** are part of the LibreOffice project. ***
+# *********************************************************************
+#
+# ScriptForge Release 7.4
+# -----------------------
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
+"POT-Creation-Date: 2022-05-04 18:07:20\n"
+"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
+"Language: en_US\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: LibreOffice - ScriptForge\n"
+"X-Accelerator-Marker: ~\n"
+
+#. Title in error message box
+#. %1: an error number
+#, kde-format
+msgctxt "ERRORNUMBER"
+msgid "Error %1"
+msgstr ""
+
+#. Error message box
+#. %1: a line number
+#, kde-format
+msgctxt "ERRORLOCATION"
+msgid "Location : %1"
+msgstr ""
+
+#. Logfile record
+#, kde-format
+msgctxt "LONGERRORDESC"
+msgid "Error %1 - Location = %2 - Description = %3"
+msgstr ""
+
+#. Any blocking error message
+msgctxt "STOPEXECUTION"
+msgid "THE EXECUTION IS CANCELLED."
+msgstr ""
+
+#. Any blocking error message
+#. %1: a method name
+#, kde-format
+msgctxt "NEEDMOREHELP"
+msgid "Do you want to receive more information about the '%1' method ?"
+msgstr ""
+
+#. SF_Exception.RaiseAbort error message
+msgctxt "INTERNALERROR"
+msgid ""
+"The ScriptForge library has crashed. The reason is unknown.\n"
+"Maybe a bug that could be reported on\n"
+" https://bugs.documentfoundation.org/\n"
+"\n"
+"More details : \n"
+"\n"
+""
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: probably ScriptForge
+#. %2: service or module name
+#. %3: property or method name where the error occurred
+#, kde-format
+msgctxt "VALIDATESOURCE"
+msgid ""
+"Library : %1\n"
+"Service : %2\n"
+"Method : %3"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: list of arguments of the method
+#, kde-format
+msgctxt "VALIDATEARGS"
+msgid "Arguments: %1"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEERROR"
+msgid "A serious error has been detected in your code on argument : « %1 »."
+msgstr ""
+
+#. SF_Utils.Validate error message
+msgctxt "VALIDATIONRULES"
+msgid " Validation rules :"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: Comma separated list of allowed types
+#, kde-format
+msgctxt "VALIDATETYPES"
+msgid " « %1 » must have next type (or one of next types) : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: Comma separated list of allowed values
+#, kde-format
+msgctxt "VALIDATEVALUES"
+msgid " « %1 » must contain one of next values : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: A regular expression
+#, kde-format
+msgctxt "VALIDATEREGEX"
+msgid " « %1 » must match next regular expression : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: The name of a Basic class
+#, kde-format
+msgctxt "VALIDATECLASS"
+msgid " « %1 » must be a Basic object of class : %2"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: The value of the argument as a string
+#, kde-format
+msgctxt "VALIDATEACTUAL"
+msgid "The actual value of « %1 » is : '%2'"
+msgstr ""
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEMISSING"
+msgid "The « %1 » argument is mandatory, yet it is missing."
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEARRAY"
+msgid " « %1 » must be an array."
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. %2: Number of dimensions of the array
+#, kde-format
+msgctxt "VALIDATEDIMS"
+msgid " « %1 » must have exactly %2 dimension(s)."
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. %2: Either one single type or 'String, Date, Numeric'
+#, kde-format
+msgctxt "VALIDATEALLTYPES"
+msgid " « %1 » must have all elements of the same type : %2"
+msgstr ""
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. NULL and EMPTY should not be translated
+#, kde-format
+msgctxt "VALIDATENOTNULL"
+msgid " « %1 » must not contain any NULL or EMPTY elements."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. 'String' should not be translated
+#, kde-format
+msgctxt "VALIDATEFILE"
+msgid " « %1 » must be of type String."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEFILESYS"
+msgid ""
+" « %1 » must be a valid file or folder name expressed in the "
+"operating system native notation."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. 'URL' should not be translated
+#, kde-format
+msgctxt "VALIDATEFILEURL"
+msgid ""
+" « %1 » must be a valid file or folder name expressed in the "
+"portable URL notation."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEFILEANY"
+msgid " « %1 » must be a valid file or folder name."
+msgstr ""
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. '(?, *)' is to be left as is
+#, kde-format
+msgctxt "VALIDATEWILDCARD"
+msgid ""
+" « %1 » may contain one or more wildcard characters (?, *) in "
+"its last path component only."
+msgstr ""
+
+#. SF_Array.RangeInit error message
+#. %1, %2, %3: Numeric values
+#. 'From', 'UpTo', 'ByStep' should not be translated
+#, kde-format
+msgctxt "ARRAYSEQUENCE"
+msgid ""
+"The respective values of 'From', 'UpTo' and 'ByStep' are incoherent.\n"
+"\n"
+" « From » = %1\n"
+" « UpTo » = %2\n"
+" « ByStep » = %3"
+msgstr ""
+
+#. SF_Array.AppendColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_2D' should not be translated
+#, kde-format
+msgctxt "ARRAYINSERT"
+msgid ""
+"The array and the vector to insert have incompatible sizes.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+msgstr ""
+
+#. SF_Array.ExtractColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_2D' should not be translated
+#, kde-format
+msgctxt "ARRAYINDEX1"
+msgid ""
+"The given index does not fit within the bounds of the array.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+msgstr ""
+
+#. SF_Array.ExtractColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_1D', 'From' and 'UpTo' should not be translated
+#, kde-format
+msgctxt "ARRAYINDEX2"
+msgid ""
+"The given slice limits do not fit within the bounds of the array.\n"
+"\n"
+" « Array_1D » = %1\n"
+" « From » = %2\n"
+" « UpTo » = %3"
+msgstr ""
+
+#. SF_Array.ImportFromCSVFile error message
+#. %1: a file name
+#. %2: numeric
+#. %3: a long string
+#, kde-format
+msgctxt "CSVPARSING"
+msgid ""
+"The given file could not be parsed as a valid CSV file.\n"
+"\n"
+" « File name » = %1\n"
+" Line number = %2\n"
+" Content = %3"
+msgstr ""
+
+#. SF_Dictionary Add/ReplaceKey error message
+#. %1: An identifier%2: a (potentially long) string
+#, kde-format
+msgctxt "DUPLICATEKEY"
+msgid ""
+"The insertion of a new key into a dictionary failed because the key "
+"already exists.\n"
+"Note that the comparison between keys is NOT case-sensitive.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Dictionary Remove/ReplaceKey/ReplaceItem error message
+#. %1: An identifier%2: a (potentially long) string
+#, kde-format
+msgctxt "UNKNOWNKEY"
+msgid ""
+"The requested key does not exist in the dictionary.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Dictionary Add/ReplaceKey error message
+#.
+msgctxt "INVALIDKEY"
+msgid ""
+"The insertion or the update of an entry into a dictionary failed "
+"because the given key contains only spaces."
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "UNKNOWNFILE"
+msgid ""
+"The given file could not be found on your system.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A folder name
+#, kde-format
+msgctxt "UNKNOWNFOLDER"
+msgid ""
+"The given folder could not be found on your system.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "NOTAFILE"
+msgid ""
+"« %1 » contains the name of an existing folder, not that of a file.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A folder name
+#, kde-format
+msgctxt "NOTAFOLDER"
+msgid ""
+"« %1 » contains the name of an existing file, not that of a folder.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/... error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "OVERWRITE"
+msgid ""
+"You tried to create a new file which already exists. Overwriting it "
+"has been rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "READONLY"
+msgid ""
+"Copying or moving a file to a destination which has its read-only "
+"attribute set, or deleting such a file or folder is forbidden.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file or folder name with wildcards
+#, kde-format
+msgctxt "NOFILEMATCH"
+msgid ""
+"When « %1 » contains wildcards. at least one file or folder must "
+"match the given filter. Otherwise the operation is rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_FileSystem CreateFolder error message
+#. %1: An identifier
+#. %2: A file or folder name
+#, kde-format
+msgctxt "FOLDERCREATION"
+msgid ""
+"« %1 » contains the name of an existing file or an existing folder. "
+"The operation is rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Services.CreateScriptService error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A Basic library name
+#. %4: A service (1 word) name
+#, kde-format
+msgctxt "UNKNOWNSERVICE"
+msgid ""
+"No service named '%4' has been registered for the library '%3'.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Services.CreateScriptService error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A Basic library name
+#, kde-format
+msgctxt "SERVICESNOTLOADED"
+msgid ""
+"The library '%3' and its services could not been loaded.\n"
+"The reason is unknown.\n"
+"However, checking the '%3.SF_Services.RegisterScriptServices()' "
+"function and its return value can be a good starting point.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Session.ExecuteCalcFunction error message
+#. 'Calc' should not be translated
+#, kde-format
+msgctxt "CALCFUNC"
+msgid ""
+"The Calc '%1' function encountered an error. Either the given "
+"function does not exist or its arguments are invalid."
+msgstr ""
+
+#. SF_Session._GetScript error message
+#. %1: 'Basic' or 'Python'
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#. %5: A string
+#, kde-format
+msgctxt "NOSCRIPT"
+msgid ""
+"The requested %1 script could not be located in the given libraries "
+"and modules.\n"
+"« %2 » = %3\n"
+"« %4 » = %5"
+msgstr ""
+
+#. SF_Session.ExecuteBasicScript error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A (long) string
+#, kde-format
+msgctxt "SCRIPTEXEC"
+msgid ""
+"An exception occurred during the execution of the Basic script.\n"
+"Cause: %3\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Session.SendMail error message
+#. %1 = a mail address
+#, kde-format
+msgctxt "WRONGEMAIL"
+msgid ""
+"One of the email addresses has been found invalid.\n"
+"Invalid mail = « %1 »"
+msgstr ""
+
+#. SF_Session.SendMail error message
+msgctxt "SENDMAIL"
+msgid ""
+"The message could not be sent due to a system error.\n"
+"A possible cause is that LibreOffice could not find any mail client."
+msgstr ""
+
+#. SF_TextStream._IsFileOpen error message
+#. %1: A file name
+#, kde-format
+msgctxt "FILENOTOPEN"
+msgid ""
+"The requested file operation could not be executed because the file "
+"was closed previously.\n"
+"\n"
+"File name = '%1'"
+msgstr ""
+
+#. SF_TextStream._IsFileOpen error message
+#. %1: A file name
+#. %2: READ, WRITE or APPEND
+#, kde-format
+msgctxt "FILEOPENMODE"
+msgid ""
+"The requested file operation could not be executed because it is "
+"incompatible with the mode in which the file was opened.\n"
+"\n"
+"File name = '%1'\n"
+"Open mode = %2"
+msgstr ""
+
+#. SF_TextStream.ReadLine/ReadAll/SkipLine error message
+#. %1: A file name
+#, kde-format
+msgctxt "ENDOFFILE"
+msgid ""
+"The requested file read operation could not be completed because an "
+"unexpected end-of-file was encountered.\n"
+"\n"
+"File name = '%1'"
+msgstr ""
+
+#. SF_UI.GetDocument error message
+#. %1: An identifier
+#. %2: A string
+#, kde-format
+msgctxt "DOCUMENT"
+msgid ""
+"The requested document could not be found.\n"
+"\n"
+"%1 = '%2'"
+msgstr ""
+
+#. SF_UI.GetDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#, kde-format
+msgctxt "DOCUMENTCREATION"
+msgid ""
+"The creation of a new document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the document type is unknown, or no template file was given,\n"
+"or the given template file was not found on your system.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+msgstr ""
+
+#. SF_UI.OpenDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#. %5: An identifier
+#. %6: A string
+#, kde-format
+msgctxt "DOCUMENTOPEN"
+msgid ""
+"The opening of the document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the file does not exist, or the password is wrong, or the "
+"given filter is invalid.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'\n"
+"%5 = '%6'"
+msgstr ""
+
+#. SF_UI.OpenDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#, kde-format
+msgctxt "BASEDOCUMENTOPEN"
+msgid ""
+"The opening of the Base document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the file does not exist, or the file is not registered under "
+"the given name.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+msgstr ""
+
+#. SF_Document._IsStillAlive error message
+#. %1: A file name
+#, kde-format
+msgctxt "DOCUMENTDEAD"
+msgid ""
+"The requested action could not be executed because the document was "
+"closed inadvertently.\n"
+"\n"
+"The concerned document is '%1'"
+msgstr ""
+
+#. SF_Document.SaveAs error message
+#. %1: An identifier
+#. %2: A file name
+#.
+#, kde-format
+msgctxt "DOCUMENTSAVE"
+msgid ""
+"The document could not be saved.\n"
+"Either the document has been opened read-only, or the destination "
+"file has a read-only attribute set, or the file where to save to is "
+"undefined.\n"
+"\n"
+"%1 = '%2'"
+msgstr ""
+
+#. SF_Document.SaveAs error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#. %5: An identifier
+#. %6: A string
+#, kde-format
+msgctxt "DOCUMENTSAVEAS"
+msgid ""
+"The document could not be saved.\n"
+"Either the document must not be overwritten, or the destination file "
+"has a read-only attribute set, or the given filter is invalid.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4\n"
+"%5 = '%6'"
+msgstr ""
+
+#. SF_Document any update
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "DOCUMENTREADONLY"
+msgid ""
+"You tried to edit a document which is not modifiable. The document "
+"has not been changed.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+
+#. SF_Base GetDatabase
+#. %1: An identifier
+#. %2: A user name
+#. %3: An identifier
+#. %4: A password
+#. %5: A file name
+#, kde-format
+msgctxt "DBCONNECT"
+msgid ""
+"The database related to the actual Base document could not be "
+"retrieved.\n"
+"Check the connection/login parameters.\n"
+"\n"
+"« %1 » = '%2'\n"
+"« %3 » = '%4'\n"
+"« Document » = %5"
+msgstr ""
+
+#. SF_Calc _ParseAddress (sheet)
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "CALCADDRESS1"
+msgid ""
+"The given address does not correspond with a valid sheet name.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+
+#. SF_Calc _ParseAddress (range)
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "CALCADDRESS2"
+msgid ""
+"The given address does not correspond with a valid range of cells.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+
+#. SF_Calc InsertSheet
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "DUPLICATESHEET"
+msgid ""
+"There exists already in the document a sheet with the same name.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+
+#. SF_Calc Offset
+#. %1: An identifier
+#. %2: A Calc reference
+#. %3: An identifier
+#. %4: A number
+#. %5: An identifier
+#. %6: A number
+#. %7: An identifier
+#. %8: A number
+#. %9: An identifier
+#. %10: A number
+#. %11: An identifier
+#. %12: A file name
+#, kde-format
+msgctxt "OFFSETADDRESS"
+msgid ""
+"The computed range falls beyond the sheet boundaries or is "
+"meaningless.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8\n"
+"« %9 » = %10\n"
+"« %11 » = %12"
+msgstr ""
+
+#. SF_Calc CreateChart
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#. %5: An identifier
+#. %6: A file name
+#, kde-format
+msgctxt "DUPLICATECHART"
+msgid ""
+"A chart with the same name exists already in the sheet.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+""
+msgstr ""
+
+#. SF_Calc.ExportRangeToFile error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#.
+#, kde-format
+msgctxt "RANGEEXPORT"
+msgid ""
+"The given range could not be exported.\n"
+"Either the destination file must not be overwritten, or it has a "
+"read-only attribute set.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4"
+msgstr ""
+
+#. SF_Chart.ExportToFile error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#.
+#, kde-format
+msgctxt "CHARTEXPORT"
+msgid ""
+"The chart could not be exported.\n"
+"Either the destination file must not be overwritten, or it has a "
+"read-only attribute set.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4"
+msgstr ""
+
+#. SF_Dialog._IsStillAlive error message
+#. %1: An identifier%2: A file name
+#, kde-format
+msgctxt "FORMDEAD"
+msgid ""
+"The requested action could not be executed because the form is not "
+"open or the document was closed inadvertently.\n"
+"\n"
+"The concerned form is '%1' in document '%2'."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A sheet name
+#. %3: A file name
+#, kde-format
+msgctxt "CALCFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the Calc sheet. The given "
+"index is off-limits.\n"
+"\n"
+"The concerned Calc document is '%3'.\n"
+"\n"
+"The name of the sheet = '%2'\n"
+"The index = %1."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A file name
+#, kde-format
+msgctxt "WRITERFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the Writer document. The "
+"given index is off-limits.\n"
+"\n"
+"The concerned Writer document is '%2'.\n"
+"\n"
+"The index = %1."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A string
+#. %3: A file name
+#, kde-format
+msgctxt "BASEFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the form document '%2'. The "
+"given index is off-limits.\n"
+"\n"
+"The concerned Base document is '%3'.\n"
+"\n"
+"The index = %1."
+msgstr ""
+
+#. SF_Form determination
+#. %1: A form name
+#. %2: A form name
+#, kde-format
+msgctxt "SUBFORMNOTFOUND"
+msgid ""
+"The requested subform could not be found below the given main form.\n"
+"\n"
+"The main form = '%2'.\n"
+"The subform = '%1'."
+msgstr ""
+
+#. SF_FormControl property setting
+#. %1: An identifier
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#, kde-format
+msgctxt "FORMCONTROLTYPE"
+msgid ""
+"The control '%1' in form '%2' is of type '%3'.\n"
+"The property or method '%4' is not applicable on that type of form "
+"controls."
+msgstr ""
+
+#. SF_Dialog creation
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#. %5: An identifier
+#. %6: A string
+#. %7: An identifier
+#. %8: A string
+#, kde-format
+msgctxt "DIALOGNOTFOUND"
+msgid ""
+"The requested dialog could not be located in the given container or "
+"library.\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8"
+msgstr ""
+
+#. SF_Dialog._IsStillAlive error message
+#. %1: An identifier
+#, kde-format
+msgctxt "DIALOGDEAD"
+msgid ""
+"The requested action could not be executed because the dialog was "
+"closed inadvertently.\n"
+"\n"
+"The concerned dialog is '%1'."
+msgstr ""
+
+#. SF_DialogControl property setting
+#. %1: An identifier
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#, kde-format
+msgctxt "CONTROLTYPE"
+msgid ""
+"The control '%1' in dialog '%2' is of type '%3'.\n"
+"The property or method '%4' is not applicable on that type of dialog "
+"controls."
+msgstr ""
+
+#. SF_DialogControl add line in textbox
+#. %1: An identifier
+#. %2: An identifier
+#, kde-format
+msgctxt "TEXTFIELD"
+msgid ""
+"The control '%1' in dialog '%2' is not a multiline text field.\n"
+"The requested method could not be executed."
+msgstr ""
+
+#. SF_Database when running update SQL statement
+#. %1: The concerned method
+#, kde-format
+msgctxt "DBREADONLY"
+msgid ""
+"The database has been opened in read-only mode.\n"
+"The '%1' method must not be executed in this context."
+msgstr ""
+
+#. SF_Database can't interpret SQL statement
+#. %1: The statement
+#, kde-format
+msgctxt "SQLSYNTAX"
+msgid ""
+"An SQL statement could not be interpreted or executed by the "
+"database system.\n"
+"Check its syntax, table and/or field names, ...\n"
+"\n"
+"SQL Statement : « %1 »"
+msgstr ""
+
+#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
+msgctxt "PYTHONSHELL"
+msgid ""
+"The APSO extension could not be located in your LibreOffice "
+"installation."
+msgstr ""
+
+#. SFUnitTest could not locate the library gven as argument
+#. %1: The name of the library
+#, kde-format
+msgctxt "UNITTESTLIBRARY"
+msgid ""
+"The requested library could not be located.\n"
+"The UnitTest service has not been initialized.\n"
+"\n"
+"Library name : « %1 »"
+msgstr ""
+
+#. SFUnitTest finds a RunTest() call in a inappropriate location
+#. %1: The name of a method
+#, kde-format
+msgctxt "UNITTESTMETHOD"
+msgid ""
+"The method '%1' is unexpected in the current context.\n"
+"The UnitTest service cannot proceed further with the on-going test."
+msgstr "" \ No newline at end of file
diff --git a/wizards/source/scriptforge/po/pt.po b/wizards/source/scriptforge/po/pt.po
new file mode 100644
index 000000000..a40aafd4c
--- /dev/null
+++ b/wizards/source/scriptforge/po/pt.po
@@ -0,0 +1,1141 @@
+#
+# This pristine POT file has been generated by LibreOffice/ScriptForge
+# Full documentation is available on https://help.libreoffice.org/
+#
+# *********************************************************************
+# *** The ScriptForge library and its associated libraries ***
+# *** are part of the LibreOffice project. ***
+# *********************************************************************
+#
+# ScriptForge Release 7.3
+# -----------------------
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?"
+"product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
+"POT-Creation-Date: 2021-06-19 16:57:15\n"
+"PO-Revision-Date: 2021-06-28 18:30-0300\n"
+"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Poedit 3.0\n"
+"X-Accelerator-Marker: ~\n"
+"Last-Translator: \n"
+"Language: pt_BR\n"
+
+#. Text in close buttons of progress and console dialog boxes
+msgctxt "CLOSEBUTTON"
+msgid "Close"
+msgstr "Fechar"
+
+#. Title in error message box
+#. %1: an error number
+#, kde-format
+msgctxt "ERRORNUMBER"
+msgid "Error %1"
+msgstr "Erro %1"
+
+#. Error message box
+#. %1: a line number
+#, kde-format
+msgctxt "ERRORLOCATION"
+msgid "Location : %1"
+msgstr "Localização : %1"
+
+#. Logfile record
+#, kde-format
+msgctxt "LONGERRORDESC"
+msgid "Error %1 - Location = %2 - Description = %3"
+msgstr "Erro %1 - Localização = %2 - Descrição = %3"
+
+#. SF_Utils._Validate error message
+msgctxt "STOPEXECUTION"
+msgid "THE EXECUTION IS CANCELLED."
+msgstr "A EXECUÇÃO FOI CANCELADA."
+
+#. SF_Exception.RaiseAbort error message
+msgctxt "INTERNALERROR"
+msgid ""
+"The ScriptForge library has crashed. The reason is unknown.\n"
+"Maybe a bug that could be reported on\n"
+" https://bugs.documentfoundation.org/\n"
+"\n"
+"More details : \n"
+"\n"
+msgstr ""
+"A biblioteca ScriptForge encontrou um erro grave. A razão é desconhecida.\n"
+"Talvez seja um bug que pode ser relatado em\n"
+" https://bugs.documentfoundation.org/\n"
+"\n"
+"Mais detalhes: \n"
+"\n"
+
+#. SF_Utils._Validate error message
+#. %1: probably ScriptForge
+#. %2: service or module name
+#. %3: property or method name where the error occurred
+#, kde-format
+msgctxt "VALIDATESOURCE"
+msgid ""
+"Library : %1\n"
+"Service : %2\n"
+"Method : %3"
+msgstr ""
+"Biblioteca : %1\n"
+"Serviço : %2\n"
+"Método : %3"
+
+#. SF_Utils._Validate error message
+#. %1: list of arguments of the method
+#, kde-format
+msgctxt "VALIDATEARGS"
+msgid "Arguments: %1"
+msgstr "Argumentos: %1"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEERROR"
+msgid "A serious error has been detected in your code on argument : « %1 »."
+msgstr "Um erro grave foi detectado em seu código no argumento : « %1»."
+
+#. SF_Utils.Validate error message
+msgctxt "VALIDATIONRULES"
+msgid " Validation rules :"
+msgstr " Regras de validação:"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: Comma separated list of allowed types
+#, kde-format
+msgctxt "VALIDATETYPES"
+msgid " « %1 » must have next type (or one of next types) : %2"
+msgstr ""
+" « %1 » deve ter o seguinte tipo (ou um dos tipos a seguir) : %2"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: Comma separated list of allowed values
+#, kde-format
+msgctxt "VALIDATEVALUES"
+msgid " « %1 » must contain one of next values : %2"
+msgstr " « %1 » deve conter um dos seguintes valores : %2"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: A regular expression
+#, kde-format
+msgctxt "VALIDATEREGEX"
+msgid " « %1 » must match next regular expression : %2"
+msgstr " « %1 » deve corresponder à seguinte expressão regular : %2"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: The name of a Basic class
+#, kde-format
+msgctxt "VALIDATECLASS"
+msgid " « %1 » must be a Basic object of class : %2"
+msgstr " « %1 » deve ser um objeto ou classe Basic : %2"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#. %2: The value of the argument as a string
+#, kde-format
+msgctxt "VALIDATEACTUAL"
+msgid "The actual value of « %1 » is : '%2'"
+msgstr "O valor atual de « %1 » é : '%2'"
+
+#. SF_Utils._Validate error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEMISSING"
+msgid "The « %1 » argument is mandatory, yet it is missing."
+msgstr "O argumento « %1 » é obrigatório, porém está ausente."
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEARRAY"
+msgid " « %1 » must be an array."
+msgstr " « %1 » deve ser um array."
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. %2: Number of dimensions of the array
+#, kde-format
+msgctxt "VALIDATEDIMS"
+msgid " « %1 » must have exactly %2 dimension(s)."
+msgstr " « %1 » deve ter exatamente %2 dimensão(ões)."
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. %2: Either one single type or 'String, Date, Numeric'
+#, kde-format
+msgctxt "VALIDATEALLTYPES"
+msgid " « %1 » must have all elements of the same type : %2"
+msgstr " « %1 » deve ter todos os elementos de um mesmo tipo : %2"
+
+#. SF_Utils._ValidateArray error message
+#. %1: Wrong argument name
+#. NULL and EMPTY should not be translated
+#, kde-format
+msgctxt "VALIDATENOTNULL"
+msgid " « %1 » must not contain any NULL or EMPTY elements."
+msgstr " « %1 » não pode conter nenhum elemento NULL ou EMPTY."
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. 'String' should not be translated
+#, kde-format
+msgctxt "VALIDATEFILE"
+msgid " « %1 » must be of type String."
+msgstr " « %1 » deve ser to tipo String."
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEFILESYS"
+msgid ""
+" « %1 » must be a valid file or folder name expressed in the "
+"operating system native notation."
+msgstr ""
+" « %1 » deve ser um nome válido de arquivo ou pasta expresso usando a "
+"notação do sistema operacional."
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. 'URL' should not be translated
+#, kde-format
+msgctxt "VALIDATEFILEURL"
+msgid ""
+" « %1 » must be a valid file or folder name expressed in the portable "
+"URL notation."
+msgstr ""
+" « %1 » deve ser um nome válido de arquivo ou pasta expresso usando a "
+"notação portável URL."
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#, kde-format
+msgctxt "VALIDATEFILEANY"
+msgid " « %1 » must be a valid file or folder name."
+msgstr " « %1 » deve ser um nome válido de arquivo ou pasta."
+
+#. SF_Utils._ValidateFile error message
+#. %1: Wrong argument name
+#. '(?, *)' is to be left as is
+#, kde-format
+msgctxt "VALIDATEWILDCARD"
+msgid ""
+" « %1 » may contain one or more wildcard characters (?, *) in its "
+"last path component only."
+msgstr ""
+" « %1 » deve conter um ou mais caracteres coringa (?,*) apenas no "
+"último componente do caminho."
+
+#. SF_Array.RangeInit error message
+#. %1, %2, %3: Numeric values
+#. 'From', 'UpTo', 'ByStep' should not be translated
+#, kde-format
+msgctxt "ARRAYSEQUENCE"
+msgid ""
+"The respective values of 'From', 'UpTo' and 'ByStep' are incoherent.\n"
+"\n"
+" « From » = %1\n"
+" « UpTo » = %2\n"
+" « ByStep » = %3"
+msgstr ""
+"Os valores informados para 'From', 'UpTo' e 'ByStep' são incoerentes.\n"
+"\n"
+" « From » = %1\n"
+" « UpTo » = %2\n"
+" « ByStep » = %3"
+
+#. SF_Array.AppendColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_2D' should not be translated
+#, kde-format
+msgctxt "ARRAYINSERT"
+msgid ""
+"The array and the vector to insert have incompatible sizes.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+msgstr ""
+"O array e vetor a serem inseridos têm tamanhos incompatíveis.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+
+#. SF_Array.ExtractColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_2D' should not be translated
+#, kde-format
+msgctxt "ARRAYINDEX1"
+msgid ""
+"The given index does not fit within the bounds of the array.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+msgstr ""
+"O índice fornecido não cabe nos limites do array.\n"
+"\n"
+" « Array_2D » = %2\n"
+" « %1 » = %3"
+
+#. SF_Array.ExtractColumn (...) error message
+#. %1: 'Column' or 'Row' of a matrix
+#. %2, %3: array contents
+#. 'Array_1D', 'From' and 'UpTo' should not be translated
+#, kde-format
+msgctxt "ARRAYINDEX2"
+msgid ""
+"The given slice limits do not fit within the bounds of the array.\n"
+"\n"
+" « Array_1D » = %1\n"
+" « From » = %2\n"
+" « UpTo » = %3"
+msgstr ""
+"Os limites fornecidos para o intervalo não cabem nos limites do array.\n"
+"\n"
+" « Array_1D » = %1\n"
+" « From » = %2\n"
+" « UpTo » = %3"
+
+#. SF_Array.ImportFromCSVFile error message
+#. %1: a file name
+#. %2: numeric
+#. %3: a long string
+#, kde-format
+msgctxt "CSVPARSING"
+msgid ""
+"The given file could not be parsed as a valid CSV file.\n"
+"\n"
+" « File name » = %1\n"
+" Line number = %2\n"
+" Content = %3"
+msgstr ""
+"O arquivo fornecido não pode ser processada como um arquivo CSV válido.\n"
+"\n"
+" « Arquivo » = %1\n"
+" Número da linha = %2\n"
+" Conteúdo = %3"
+
+#. SF_Dictionary Add/ReplaceKey error message
+#. %1: An identifier%2: a (potentially long) string
+#, kde-format
+msgctxt "DUPLICATEKEY"
+msgid ""
+"The insertion of a new key into a dictionary failed because the key already "
+"exists.\n"
+"Note that the comparison between keys is NOT case-sensitive.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"A inserção de uma nova chave ao dicionário falhou porque a chave já existe.\n"
+"Note que comparações entre chaves não são sensíveis à caixa.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_Dictionary Remove/ReplaceKey/ReplaceItem error message
+#. %1: An identifier%2: a (potentially long) string
+#, kde-format
+msgctxt "UNKNOWNKEY"
+msgid ""
+"The requested key does not exist in the dictionary.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"A chave requerida não existe no dicionário.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_Dictionary Add/ReplaceKey error message
+#.
+msgctxt "INVALIDKEY"
+msgid ""
+"The insertion or the update of an entry into a dictionary failed because the "
+"given key contains only spaces."
+msgstr ""
+"A inserção ou atualização de uma entrada em um dicionário falhou porque a "
+"chave fornecido contém apenas espaços."
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "UNKNOWNFILE"
+msgid ""
+"The given file could not be found on your system.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"O arquivo fornecido não foi encontrado em seu sistema.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A folder name
+#, kde-format
+msgctxt "UNKNOWNFOLDER"
+msgid ""
+"The given folder could not be found on your system.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"O diretório fornecido não foi encontrado em seu sistema.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "NOTAFILE"
+msgid ""
+"« %1 » contains the name of an existing folder, not that of a file.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"« %1 » contém o nome de um diretório existente em vez de conter o nome de um "
+"arquivo.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A folder name
+#, kde-format
+msgctxt "NOTAFOLDER"
+msgid ""
+"« %1 » contains the name of an existing file, not that of a folder.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"« %1 » contém o nome de um arquivo existente em vez de conter o nome de um "
+"diretório.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem copy/move/... error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "OVERWRITE"
+msgid ""
+"You tried to create a new file which already exists. Overwriting it has been "
+"rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"Você tentou criar um novo arquivo que já existe. Sobrescrever o arquivo não "
+"foi permitido\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "READONLY"
+msgid ""
+"Copying or moving a file to a destination which has its read-only attribute "
+"set, or deleting such a file or folder is forbidden.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"Copiar ou mover um arquivo para um destino que tem o atributo somente-"
+"leitura definido, bem como apagar tais arquivos ou pastas, não é permitido.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem copy/move/delete error message
+#. %1: An identifier
+#. %2: A file or folder name with wildcards
+#, kde-format
+msgctxt "NOFILEMATCH"
+msgid ""
+"When « %1 » contains wildcards. at least one file or folder must match the "
+"given filter. Otherwise the operation is rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"Quando « %1 » contiver caracteres coringa, ao menos um arquivo ou pasta deve "
+"corresponder ao filtro especificado. Caso contrário, a operação será "
+"rejeitada.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_FileSystem CreateFolder error message
+#. %1: An identifier
+#. %2: A file or folder name
+#, kde-format
+msgctxt "FOLDERCREATION"
+msgid ""
+"« %1 » contains the name of an existing file or an existing folder. The "
+"operation is rejected.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"« %1 » contém o nome de um arquivo ou pasta existente. A operação foi "
+"rejeitada.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_Services.CreateScriptService error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A Basic library name
+#. %4: A service (1 word) name
+#, kde-format
+msgctxt "UNKNOWNSERVICE"
+msgid ""
+"No service named '%4' has been registered for the library '%3'.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"Nenhum serviço com o nome '%4' foi registrado na biblioteca '%3'.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_Services.CreateScriptService error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A Basic library name
+#, kde-format
+msgctxt "SERVICESNOTLOADED"
+msgid ""
+"The library '%3' and its services could not been loaded.\n"
+"The reason is unknown.\n"
+"However, checking the '%3.SF_Services.RegisterScriptServices()' function and "
+"its return value can be a good starting point.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"A biblioteca '%3' e seus serviços não puderam ser carregados.\n"
+"A razão é desconhecida.\n"
+"Contudo, verificar a função '%3.SF_Services.RegisterScriptServices()' e seu "
+"valor de retorno pode ser um bom ponto de partida.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_Session.ExecuteCalcFunction error message
+#. 'Calc' should not be translated
+#, kde-format
+msgctxt "CALCFUNC"
+msgid ""
+"The Calc '%1' function encountered an error. Either the given function does "
+"not exist or its arguments are invalid."
+msgstr ""
+"A função Calc '%1' encontrou um erro. Ou a função dada não existe ou seus "
+"argumentos são inválidos."
+
+#. SF_Session._GetScript error message
+#. %1: 'Basic' or 'Python'
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#. %5: A string
+#, kde-format
+msgctxt "NOSCRIPT"
+msgid ""
+"The requested %1 script could not be located in the given libraries and "
+"modules.\n"
+"« %2 » = %3\n"
+"« %4 » = %5"
+msgstr ""
+"O script %1 não pode ser localizado nas bibliotecas e módulos "
+"especificados.\n"
+"« %2 » = %3\n"
+"« %4 » = %5"
+
+#. SF_Session.ExecuteBasicScript error message
+#. %1: An identifier
+#. %2: A string
+#. %3: A (long) string
+#, kde-format
+msgctxt "SCRIPTEXEC"
+msgid ""
+"An exception occurred during the execution of the Basic script.\n"
+"Cause: %3\n"
+"« %1 » = %2"
+msgstr ""
+"Uma exceção ocorreu durante a execução do script Basic.\n"
+"Cause: %3\n"
+"« %1 » = %2"
+
+#. SF_Session.SendMail error message
+#. %1 = a mail address
+#, kde-format
+msgctxt "WRONGEMAIL"
+msgid ""
+"One of the email addresses has been found invalid.\n"
+"Invalid mail = « %1 »"
+msgstr ""
+"Um dos endereços de e-mail foram considerados inválidos.\n"
+"E-mail inválido = « %1 »"
+
+#. SF_Session.SendMail error message
+msgctxt "SENDMAIL"
+msgid ""
+"The message could not be sent due to a system error.\n"
+"A possible cause is that LibreOffice could not find any mail client."
+msgstr ""
+"Esta mensagem não pode ser enviada devido a um erro de sistema.\n"
+"Uma possível causa é que o LibreOffice não pode encontrar um cliente de e-"
+"mail."
+
+#. SF_TextStream._IsFileOpen error message
+#. %1: A file name
+#, kde-format
+msgctxt "FILENOTOPEN"
+msgid ""
+"The requested file operation could not be executed because the file was "
+"closed previously.\n"
+"\n"
+"File name = '%1'"
+msgstr ""
+"A operação de arquivo não pode ser executada porque o arquivo foi fechado "
+"previamente.\n"
+"\n"
+"Nome do arquivo = '%1'"
+
+#. SF_TextStream._IsFileOpen error message
+#. %1: A file name
+#. %2: READ, WRITE or APPEND
+#, kde-format
+msgctxt "FILEOPENMODE"
+msgid ""
+"The requested file operation could not be executed because it is "
+"incompatible with the mode in which the file was opened.\n"
+"\n"
+"File name = '%1'\n"
+"Open mode = %2"
+msgstr ""
+"A operação de arquivo não pode ser executada porque é incompatível com o "
+"modo de abertura do arquivo.\n"
+"\n"
+"Nome do arquivo = '%1'\n"
+"Modo de abertura = %2"
+
+#. SF_TextStream.ReadLine/ReadAll/SkipLine error message
+#. %1: A file name
+#, kde-format
+msgctxt "ENDOFFILE"
+msgid ""
+"The requested file read operation could not be completed because an "
+"unexpected end-of-file was encountered.\n"
+"\n"
+"File name = '%1'"
+msgstr ""
+"A operação de leitura de arquivo não pode ser completada porque um fim-de-"
+"arquivo inesperado foi encontrado.\n"
+"\n"
+"Nome do arquivo = '%1'"
+
+#. SF_UI.GetDocument error message
+#. %1: An identifier
+#. %2: A string
+#, kde-format
+msgctxt "DOCUMENT"
+msgid ""
+"The requested document could not be found.\n"
+"\n"
+"%1 = '%2'"
+msgstr ""
+"O documento desejado não pode ser encontrado.\n"
+"\n"
+"%1 = '%2'"
+
+#. SF_UI.GetDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#, kde-format
+msgctxt "DOCUMENTCREATION"
+msgid ""
+"The creation of a new document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the document type is unknown, or no template file was given,\n"
+"or the given template file was not found on your system.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+msgstr ""
+"A criação de um novo documento falhou.\n"
+"Deve haver algo de errado com algum dos argumentos.\n"
+"\n"
+"Ou o tipo do documento é desconhecido, ou nenhum arquivo de template foi "
+"especificado,\n"
+"ou o arquivo do template especificado não foi encontrado no sistema.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+
+#. SF_UI.OpenDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#. %5: An identifier
+#. %6: A string
+#, kde-format
+msgctxt "DOCUMENTOPEN"
+msgid ""
+"The opening of the document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the file does not exist, or the password is wrong, or the given "
+"filter is invalid.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'\n"
+"%5 = '%6'"
+msgstr ""
+"A abertura do documento falhou.\n"
+"Deve haver algo de errado com um ou mais argumentos.\n"
+"\n"
+"Ou o arquivo não existe, ou a senha está incorreta, ou o filtro especificado "
+"é inválido.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'\n"
+"%5 = '%6'"
+
+#. SF_UI.OpenDocument error message
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A string
+#, kde-format
+msgctxt "BASEDOCUMENTOPEN"
+msgid ""
+"The opening of the Base document failed.\n"
+"Something must be wrong with some arguments.\n"
+"\n"
+"Either the file does not exist, or the file is not registered under the "
+"given name.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+msgstr ""
+"A abertura do documento Base falhou.\n"
+"Deve haver algo de errado em algum dos argumentos.\n"
+"\n"
+"Ou o arquivo não existe, ou o arquivo não está registrado com o nome "
+"informado.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = '%4'"
+
+#. SF_Document._IsStillAlive error message
+#. %1: A file name
+#, kde-format
+msgctxt "DOCUMENTDEAD"
+msgid ""
+"The requested action could not be executed because the document was closed "
+"inadvertently.\n"
+"\n"
+"The concerned document is '%1'"
+msgstr ""
+"A ação desejada não pode ser executada porque o documento foi fechado "
+"inesperadamente.\n"
+"\n"
+"O documento que gerou o erro foi '%1'"
+
+#. SF_Document.SaveAs error message
+#. %1: An identifier
+#. %2: A file name
+#.
+#, kde-format
+msgctxt "DOCUMENTSAVE"
+msgid ""
+"The document could not be saved.\n"
+"Either the document has been opened read-only, or the destination file has a "
+"read-only attribute set, or the file where to save to is undefined.\n"
+"\n"
+"%1 = '%2'"
+msgstr ""
+"O documento não pode ser salvo.\n"
+"Ou o documento foi aberto como somente-leitura, ou o arquivo de destino é "
+"somente leitura, ou o arquivo onde o documento será salvo é indefinido.\n"
+"\n"
+"%1 = '%2'"
+
+#. SF_Document.SaveAs error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#. %5: An identifier
+#. %6: A string
+#, kde-format
+msgctxt "DOCUMENTSAVEAS"
+msgid ""
+"The document could not be saved.\n"
+"Either the document must not be overwritten, or the destination file has a "
+"read-only attribute set, or the given filter is invalid.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4\n"
+"%5 = '%6'"
+msgstr ""
+"O documento não pode ser salvo.\n"
+"Ou o documento não pode ser sobrescrito, ou o arquivo de destino é somente "
+"leitura, ou o filtro especificado é inválido.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4\n"
+"%5 = '%6'"
+
+#. SF_Document any update
+#. %1: An identifier
+#. %2: A file name
+#, kde-format
+msgctxt "DOCUMENTREADONLY"
+msgid ""
+"You tried to edit a document which is not modifiable. The document has not "
+"been changed.\n"
+"\n"
+"« %1 » = %2"
+msgstr ""
+"Você tentou editar um documento que não é modificável. O documento não foi "
+"alterado.\n"
+"\n"
+"« %1 » = %2"
+
+#. SF_Base GetDatabase
+#. %1: An identifier
+#. %2: A user name
+#. %3: An identifier
+#. %4: A password
+#. %5: A file name
+#, kde-format
+msgctxt "DBCONNECT"
+msgid ""
+"The database related to the actual Base document could not be retrieved.\n"
+"Check the connection/login parameters.\n"
+"\n"
+"« %1 » = '%2'\n"
+"« %3 » = '%4'\n"
+"« Document » = %5"
+msgstr ""
+"O banco de dados associado ao documento Base atual não pode ser recuperado.\n"
+"Verifique os parâmetros de conexão e login.\n"
+"\n"
+"« %1 » = '%2'\n"
+"« %3 » = '%4'\n"
+"« Documento » = %5"
+
+#. SF_Calc _ParseAddress (sheet)
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "CALCADDRESS1"
+msgid ""
+"The given address does not correspond with a valid sheet name.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+"O endereço fornecido não corresponde a um nome de planilha válido.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+
+#. SF_Calc _ParseAddress (range)
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "CALCADDRESS2"
+msgid ""
+"The given address does not correspond with a valid range of cells.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+"O endereço fornecido não corresponde a um intervalo de células válido.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+
+#. SF_Calc InsertSheet
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#, kde-format
+msgctxt "DUPLICATESHEET"
+msgid ""
+"There exists already in the document a sheet with the same name.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+msgstr ""
+"Já existe no documento uma planilha com o mesmo nome.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4"
+
+#. SF_Calc Offset
+#. %1: An identifier
+#. %2: A Calc reference
+#. %3: An identifier
+#. %4: A number
+#. %5: An identifier
+#. %6: A number
+#. %7: An identifier
+#. %8: A number
+#. %9: An identifier
+#. %10: A number
+#. %11: An identifier
+#. %12: A file name
+#, kde-format
+msgctxt "OFFSETADDRESS"
+msgid ""
+"The computed range falls beyond the sheet boundaries or is meaningless.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8\n"
+"« %9 » = %10\n"
+"« %11 » = %12"
+msgstr ""
+"O intervalo computado vai além dos limites da planilha ou não tem sentido.\n"
+"\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8\n"
+"« %9 » = %10\n"
+"« %11 » = %12"
+
+#. SF_Dialog._IsStillAlive error message
+#. %1: An identifier%2: A file name
+#, kde-format
+msgctxt "FORMDEAD"
+msgid ""
+"The requested action could not be executed because the form is not open or "
+"the document was closed inadvertently.\n"
+"\n"
+"The concerned form is '%1' in document '%2'."
+msgstr ""
+"A ação desejada não pode ser executada porque o formulário não está aberto "
+"ou o documento foi fechado inesperadamente.\n"
+"\n"
+"O formulário em questão é '%1' no documento '%2'."
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A sheet name
+#. %3: A file name
+#, kde-format
+msgctxt "CALCFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the Calc sheet. The given index is "
+"off-limits.\n"
+"\n"
+"The concerned Calc document is '%3'.\n"
+"\n"
+"The name of the sheet = '%2'\n"
+"The index = %1."
+msgstr ""
+"O formulário desejado não pode ser encontrada na planilha Calc. O índice "
+"dado está além dos limites.\n"
+"\n"
+"O documento Calc em questão é '%3'.\n"
+"\n"
+"Nome da planilha = '%2'\n"
+"Índice da planilha = %1."
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A file name
+#, kde-format
+msgctxt "WRITERFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the Writer document. The given "
+"index is off-limits.\n"
+"\n"
+"The concerned Writer document is '%2'.\n"
+"\n"
+"The index = %1."
+msgstr ""
+"O formulário desejado não pode ser encontrado no documento Writer. O índice "
+"informado está além dos limites.\n"
+"\n"
+"O document Writer em questão é '%2'.\n"
+"\n"
+"Índice do formulário = %1."
+
+#. SF_Form determination
+#. %1: A number
+#. %2: A string
+#. %3: A file name
+#, kde-format
+msgctxt "BASEFORMNOTFOUND"
+msgid ""
+"The requested form could not be found in the form document '%2'. The given "
+"index is off-limits.\n"
+"\n"
+"The concerned Base document is '%3'.\n"
+"\n"
+"The index = %1."
+msgstr ""
+"O formulário desejado não pode ser encontrado no documento de formulário "
+"'%2'. O índice informado está além dos limites.\n"
+"\n"
+"O documento Base em questão é '%3'.\n"
+"\n"
+"Índice do formulário = %1."
+
+#. SF_Form determination
+#. %1: A form name
+#. %2: A form name
+#, kde-format
+msgctxt "SUBFORMNOTFOUND"
+msgid ""
+"The requested subform could not be found below the given main form.\n"
+"\n"
+"The main form = '%2'.\n"
+"The subform = '%1'."
+msgstr ""
+"O sub-formulário desejado não pode ser encontrado como parte do formulário "
+"principal.\n"
+"\n"
+"Formulário principal = '%2'.\n"
+"Sub-formulário = '%1'."
+
+#. SF_FormControl property setting
+#. %1: An identifier
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#, kde-format
+msgctxt "FORMCONTROLTYPE"
+msgid ""
+"The control '%1' in form '%2' is of type '%3'.\n"
+"The property or method '%4' is not applicable on that type of form controls."
+msgstr ""
+"O controle '%1' no formulário '%2' é do tipo '%3'.\n"
+"A propriedade ou método '%4' não é aplicável a este tipo de controle de "
+"formulário."
+
+#. SF_Dialog creation
+#. %1: An identifier
+#. %2: A string
+#. %3: An identifier
+#. %4: A file name
+#. %5: An identifier
+#. %6: A string
+#. %7: An identifier
+#. %8: A string
+#, kde-format
+msgctxt "DIALOGNOTFOUND"
+msgid ""
+"The requested dialog could not be located in the given container or "
+"library.\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8"
+msgstr ""
+"O diálogo desejado não pode ser localizado no container ou biblioteca "
+"informado.\n"
+"« %1 » = %2\n"
+"« %3 » = %4\n"
+"« %5 » = %6\n"
+"« %7 » = %8"
+
+#. SF_Dialog._IsStillAlive error message
+#. %1: An identifier
+#, kde-format
+msgctxt "DIALOGDEAD"
+msgid ""
+"The requested action could not be executed because the dialog was closed "
+"inadvertently.\n"
+"\n"
+"The concerned dialog is '%1'."
+msgstr ""
+"A ação desejada não pode ser executada porque o diálogo foi fechado "
+"inesperadamente.\n"
+"\n"
+"O diálogo em questão é '%1'."
+
+#. SF_DialogControl property setting
+#. %1: An identifier
+#. %2: An identifier
+#. %3: A string
+#. %4: An identifier
+#, kde-format
+msgctxt "CONTROLTYPE"
+msgid ""
+"The control '%1' in dialog '%2' is of type '%3'.\n"
+"The property or method '%4' is not applicable on that type of dialog "
+"controls."
+msgstr ""
+"O controle '%1' no diálogo '%2' é do tipo '%3'.\n"
+"A propriedade ou método '%4' não é aplicável a este tipo de controle de "
+"diálogo."
+
+#. SF_DialogControl add line in textbox
+#. %1: An identifier
+#. %2: An identifier
+#, kde-format
+msgctxt "TEXTFIELD"
+msgid ""
+"The control '%1' in dialog '%2' is not a multiline text field.\n"
+"The requested method could not be executed."
+msgstr ""
+"O controle '%1' no diálogo '%2' não é uma caixa de edição de textos de "
+"múltiplas linhas.\n"
+"O método desejado não pode ser executado."
+
+#. SF_Database when running update SQL statement
+#. %1: The concerned method
+#, kde-format
+msgctxt "DBREADONLY"
+msgid ""
+"The database has been opened in read-only mode.\n"
+"The '%1' method must not be executed in this context."
+msgstr ""
+"O banco de dados foi aberto no modo somente-leitura.\n"
+"O método '%1' não pode ser executado neste contexto."
+
+#. SF_Database can't interpret SQL statement
+#. %1: The statement
+#, kde-format
+msgctxt "SQLSYNTAX"
+msgid ""
+"An SQL statement could not be interpreted or executed by the database "
+"system.\n"
+"Check its syntax, table and/or field names, ...\n"
+"\n"
+"SQL Statement : « %1 »"
+msgstr ""
+"Uma instrução SQL não pode ser interpretada ou executada pelo sistema de "
+"banco de dados.\n"
+"Verifique sua sintaxe, nomes de tabelas, campos, etc...\n"
+"\n"
+"Instrução SQL : « %1 »"
+
+#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
+msgctxt "PYTHONSHELL"
+msgid ""
+"The APSO extension could not be located in your LibreOffice installation."
+msgstr ""
+"A extensão APSO não pode ser localizada sem sua instalação do LibreOffice."
diff --git a/wizards/source/scriptforge/python/ScriptForgeHelper.py b/wizards/source/scriptforge/python/ScriptForgeHelper.py
new file mode 100644
index 000000000..396273233
--- /dev/null
+++ b/wizards/source/scriptforge/python/ScriptForgeHelper.py
@@ -0,0 +1,317 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2019-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+# ======================================================================================================================
+# === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+# === Full documentation is available on https://help.libreoffice.org/ ===
+# ======================================================================================================================
+
+# ScriptForge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# ScriptForge is free software; you can redistribute it and/or modify it under the terms of either (at your option):
+
+# 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
+# distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
+
+# 2) The GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version. If a copy of the LGPL was not
+# distributed with this file, see http://www.gnu.org/licenses/ .
+
+"""
+Collection of Python helper functions called from the ScriptForge Basic libraries
+to execute specific services that are not or not easily available from Basic directly.
+"""
+
+import getpass
+import os
+import platform
+import hashlib
+import filecmp
+import webbrowser
+import json
+
+
+class _Singleton(type):
+ """
+ A Singleton design pattern
+ Credits: « Python in a Nutshell » by Alex Martelli, O'Reilly
+ """
+ instances = {}
+
+ def __call__(cls, *args, **kwargs):
+ if cls not in cls.instances:
+ cls.instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
+ return cls.instances[cls]
+
+
+# #################################################################
+# Dictionary service
+# #################################################################
+
+def _SF_Dictionary__ConvertToJson(propval, indent = None) -> str:
+ # used by Dictionary.ConvertToJson() Basic method
+ """
+ Given an array of PropertyValues as argument, convert it to a JSON string
+ """
+ # Array of property values => Dict(ionary) => JSON
+ pvDict = {}
+ for pv in propval:
+ pvDict[pv.Name] = pv.Value
+ return json.dumps(pvDict, indent=indent, skipkeys=True)
+
+
+def _SF_Dictionary__ImportFromJson(jsonstr: str): # used by Dictionary.ImportFromJson() Basic method
+ """
+ Given a JSON string as argument, convert it to a list of tuples (name, value)
+ The value must not be a (sub)dict. This doesn't pass the python-basic bridge.
+ """
+ # JSON => Dictionary => Array of tuples/lists
+ dico = json.loads(jsonstr)
+ result = []
+ for key in iter(dico):
+ value = dico[key]
+ item = value
+ if isinstance(value, dict): # check that first level is not itself a (sub)dict
+ item = None
+ elif isinstance(value, list): # check every member of the list is not a (sub)dict
+ for i in range(len(value)):
+ if isinstance(value[i], dict): value[i] = None
+ result.append((key, item))
+ return result
+
+
+# #################################################################
+# Exception service
+# #################################################################
+
+def _SF_Exception__PythonPrint(string: str) -> bool:
+ # used by SF_Exception.PythonPrint() Basic method
+ """
+ Write the argument to stdout.
+ If the APSO shell console is active, the argument will be displayed in the console window
+ """
+ print(string)
+ return True
+
+
+# #################################################################
+# FileSystem service
+# #################################################################
+
+def _SF_FileSystem__CompareFiles(filename1: str, filename2: str, comparecontents=True) -> bool:
+ # used by SF_FileSystem.CompareFiles() Basic method
+ """
+ Compare the 2 files, returning True if they seem equal, False otherwise.
+ By default, only their signatures (modification time, ...) are compared.
+ When comparecontents == True, their contents are compared.
+ """
+ try:
+ return filecmp.cmp(filename1, filename2, not comparecontents)
+ except Exception:
+ return False
+
+
+def _SF_FileSystem__GetFilelen(systemfilepath: str) -> str: # used by SF_FileSystem.GetFilelen() Basic method
+ return str(os.path.getsize(systemfilepath))
+
+
+def _SF_FileSystem__HashFile(filename: str, algorithm: str) -> str: # used by SF_FileSystem.HashFile() Basic method
+ """
+ Hash a given file with the given hashing algorithm
+ cfr. https://www.pythoncentral.io/hashing-files-with-python/
+ Example
+ hash = _SF_FileSystem__HashFile('myfile.txt','MD5')
+ """
+ algo = algorithm.lower()
+ try:
+ if algo in hashlib.algorithms_guaranteed:
+ BLOCKSIZE = 65535 # Provision for large size files
+ if algo == 'md5':
+ hasher = hashlib.md5()
+ elif algo == 'sha1':
+ hasher = hashlib.sha1()
+ elif algo == 'sha224':
+ hasher = hashlib.sha224()
+ elif algo == 'sha256':
+ hasher = hashlib.sha256()
+ elif algo == 'sha384':
+ hasher = hashlib.sha384()
+ elif algo == 'sha512':
+ hasher = hashlib.sha512()
+ else:
+ return ''
+ with open(filename, 'rb') as file: # open in binary mode
+ buffer = file.read(BLOCKSIZE)
+ while len(buffer) > 0:
+ hasher.update(buffer)
+ buffer = file.read(BLOCKSIZE)
+ return hasher.hexdigest()
+ else:
+ return ''
+ except Exception:
+ return ''
+
+
+# #################################################################
+# Platform service
+# #################################################################
+
+def _SF_Platform(propertyname: str): # used by SF_Platform Basic module
+ """
+ Switch between SF_Platform properties (read the documentation about the ScriptForge.Platform service)
+ """
+ pf = Platform()
+ if propertyname == 'Architecture':
+ return pf.Architecture
+ elif propertyname == 'ComputerName':
+ return pf.ComputerName
+ elif propertyname == 'CPUCount':
+ return pf.CPUCount
+ elif propertyname == 'CurrentUser':
+ return pf.CurrentUser
+ elif propertyname == 'Machine':
+ return pf.Machine
+ elif propertyname == 'OSName':
+ return pf.OSName
+ elif propertyname == 'OSPlatform':
+ return pf.OSPlatform
+ elif propertyname == 'OSRelease':
+ return pf.OSRelease
+ elif propertyname == 'OSVersion':
+ return pf.OSVersion
+ elif propertyname == 'Processor':
+ return pf.Processor
+ elif propertyname == 'PythonVersion':
+ return pf.PythonVersion
+ else:
+ return None
+
+
+class Platform(object, metaclass = _Singleton):
+ @property
+ def Architecture(self): return platform.architecture()[0]
+
+ @property # computer's network name
+ def ComputerName(self): return platform.node()
+
+ @property # number of CPU's
+ def CPUCount(self): return os.cpu_count()
+
+ @property
+ def CurrentUser(self):
+ try:
+ return getpass.getuser()
+ except Exception:
+ return ''
+
+ @property # machine type e.g. 'i386'
+ def Machine(self): return platform.machine()
+
+ @property # system/OS name e.g. 'Darwin', 'Java', 'Linux', ...
+ def OSName(self): return platform.system().replace('Darwin', 'macOS')
+
+ @property # underlying platform e.g. 'Windows-10-...'
+ def OSPlatform(self): return platform.platform(aliased = True)
+
+ @property # system's release e.g. '2.2.0'
+ def OSRelease(self): return platform.release()
+
+ @property # system's version
+ def OSVersion(self): return platform.version()
+
+ @property # real processor name e.g. 'amdk'
+ def Processor(self): return platform.processor()
+
+ @property # Python major.minor.patchlevel
+ def PythonVersion(self): return 'Python ' + platform.python_version()
+
+
+# #################################################################
+# Session service
+# #################################################################
+
+def _SF_Session__OpenURLInBrowser(url: str): # Used by SF_Session.OpenURLInBrowser() Basic method
+ """
+ Display url using the default browser
+ """
+ try:
+ webbrowser.open(url, new = 2)
+ finally:
+ return None
+
+
+# #################################################################
+# String service
+# #################################################################
+
+def _SF_String__HashStr(string: str, algorithm: str) -> str: # used by SF_String.HashStr() Basic method
+ """
+ Hash a given UTF-8 string with the given hashing algorithm
+ Example
+ hash = _SF_String__HashStr('This is a UTF-8 encoded string.','MD5')
+ """
+ algo = algorithm.lower()
+ try:
+ if algo in hashlib.algorithms_guaranteed:
+ ENCODING = 'utf-8'
+ bytestring = string.encode(ENCODING) # Hashing functions expect bytes, not strings
+ if algo == 'md5':
+ hasher = hashlib.md5(bytestring)
+ elif algo == 'sha1':
+ hasher = hashlib.sha1(bytestring)
+ elif algo == 'sha224':
+ hasher = hashlib.sha224(bytestring)
+ elif algo == 'sha256':
+ hasher = hashlib.sha256(bytestring)
+ elif algo == 'sha384':
+ hasher = hashlib.sha384(bytestring)
+ elif algo == 'sha512':
+ hasher = hashlib.sha512(bytestring)
+ else:
+ return ''
+ return hasher.hexdigest()
+ else:
+ return ''
+ except Exception:
+ return ''
+
+
+# #################################################################
+# lists the scripts, that shall be visible inside the Basic/Python IDE
+# #################################################################
+
+g_exportedScripts = ()
+
+if __name__ == "__main__":
+ print(_SF_Platform('Architecture'))
+ print(_SF_Platform('ComputerName'))
+ print(_SF_Platform('CPUCount'))
+ print(_SF_Platform('CurrentUser'))
+ print(_SF_Platform('Machine'))
+ print(_SF_Platform('OSName'))
+ print(_SF_Platform('OSPlatform'))
+ print(_SF_Platform('OSRelease'))
+ print(_SF_Platform('OSVersion'))
+ print(_SF_Platform('Processor'))
+ print(_SF_Platform('PythonVersion'))
+ #
+ print(hashlib.algorithms_guaranteed)
+ print(_SF_FileSystem__HashFile('/opt/libreoffice6.4/program/libbootstraplo.so', 'md5'))
+ print(_SF_FileSystem__HashFile('/opt/libreoffice6.4/share/Scripts/python/Capitalise.py', 'sha512'))
+ #
+ print(_SF_String__HashStr('œ∑¡™£¢∞§¶•ªº–≠œ∑´®†¥¨ˆøπ“‘åß∂ƒ©˙∆˚¬', 'MD5')) # 616eb9c513ad07cd02924b4d285b9987
+ #
+ # _SF_Session__OpenURLInBrowser('https://docs.python.org/3/library/webbrowser.html')
+ #
+ js = """
+ {"firstName": "John","lastName": "Smith","isAlive": true,"age": 27,
+ "address": {"streetAddress": "21 2nd Street","city": "New York","state": "NY","postalCode": "10021-3100"},
+ "phoneNumbers": [{"type": "home","number": "212 555-1234"},{"type": "office","number": "646 555-4567"}],
+ "children": ["Q", "M", "G", "T"],"spouse": null}
+ """
+ arr = _SF_Dictionary__ImportFromJson(js)
+ print(arr)
diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py
new file mode 100644
index 000000000..ebc6f147c
--- /dev/null
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -0,0 +1,2539 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2020-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+# =====================================================================================================================
+# === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+# === Full documentation is available on https://help.libreoffice.org/ ===
+# =====================================================================================================================
+
+# ScriptForge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# ScriptForge is free software; you can redistribute it and/or modify it under the terms of either (at your option):
+
+# 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
+# distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
+
+# 2) The GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version. If a copy of the LGPL was not
+# distributed with this file, see http://www.gnu.org/licenses/ .
+
+"""
+ ScriptForge libraries are an extensible and robust collection of macro scripting resources for LibreOffice
+ to be invoked from user Basic or Python macros. Users familiar with other BASIC macro variants often face hard
+ times to dig into the extensive LibreOffice Application Programming Interface even for the simplest operations.
+ By collecting most-demanded document operations in a set of easy to use, easy to read routines, users can now
+ program document macros with much less hassle and get quicker results.
+
+ ScriptForge abundant methods are organized in reusable modules that cleanly isolate Basic/Python programming
+ language constructs from ODF document content accesses and user interface(UI) features.
+
+ The scriptforge.py module
+ - implements a protocol between Python (user) scripts and the ScriptForge Basic library
+ - contains the interfaces (classes and attributes) to be used in Python user scripts
+ to run the services implemented in the standard libraries shipped with LibreOffice
+
+ Usage:
+
+ When Python and LibreOffice run in the same process (usual case): either
+ from scriptforge import * # or, better ...
+ from scriptforge import CreateScriptService
+
+ When Python and LibreOffice are started in separate processes,
+ LibreOffice being started from console ... (example for Linux with port = 2021)
+ ./soffice --accept='socket,host=localhost,port=2021;urp;'
+ then use next statement:
+ from scriptforge import * # or, better ...
+ from scriptforge import CreateScriptService, ScriptForge
+ ScriptForge(hostname = 'localhost', port = 2021)
+
+ Specific documentation about the use of ScriptForge from Python scripts:
+ https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_intro.html?DbPAR=BASIC
+ """
+
+import uno
+
+import datetime
+import time
+import os
+
+
+class _Singleton(type):
+ """
+ A Singleton metaclass design pattern
+ Credits: « Python in a Nutshell » by Alex Martelli, O'Reilly
+ """
+ instances = {}
+
+ def __call__(cls, *args, **kwargs):
+ if cls not in cls.instances:
+ cls.instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
+ return cls.instances[cls]
+
+
+# #####################################################################################################################
+# ScriptForge CLASS ###
+# #####################################################################################################################
+
+class ScriptForge(object, metaclass = _Singleton):
+ """
+ The ScriptForge (singleton) class encapsulates the core of the ScriptForge run-time
+ - Bridge with the LibreOffice process
+ - Implementation of the inter-language protocol with the Basic libraries
+ - Identification of the available services interfaces
+ - Dispatching of services
+ - Coexistence with UNO
+
+ It embeds the Service class that manages the protocol with Basic
+ """
+
+ # #########################################################################
+ # Class attributes
+ # #########################################################################
+ hostname = ''
+ port = 0
+ componentcontext = None
+ scriptprovider = None
+ SCRIPTFORGEINITDONE = False
+
+ # #########################################################################
+ # Class constants
+ # #########################################################################
+ library = 'ScriptForge'
+ Version = '7.4' # Actual version number
+ #
+ # Basic dispatcher for Python scripts
+ basicdispatcher = '@application#ScriptForge.SF_PythonHelper._PythonDispatcher'
+ # Python helper functions module
+ pythonhelpermodule = 'ScriptForgeHelper.py'
+ #
+ # VarType() constants
+ V_EMPTY, V_NULL, V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE = 0, 1, 2, 3, 4, 5
+ V_CURRENCY, V_DATE, V_STRING, V_OBJECT, V_BOOLEAN = 6, 7, 8, 9, 11
+ V_VARIANT, V_ARRAY, V_ERROR, V_UNO = 12, 8192, -1, 16
+ # Object types
+ objMODULE, objCLASS, objUNO = 1, 2, 3
+ # Special argument symbols
+ cstSymEmpty, cstSymNull, cstSymMissing = '+++EMPTY+++', '+++NULL+++', '+++MISSING+++'
+ # Predefined references for services implemented as standard Basic modules
+ servicesmodules = dict([('ScriptForge.Array', 0),
+ ('ScriptForge.Exception', 1),
+ ('ScriptForge.FileSystem', 2),
+ ('ScriptForge.Platform', 3),
+ ('ScriptForge.Region', 4),
+ ('ScriptForge.Services', 5),
+ ('ScriptForge.Session', 6),
+ ('ScriptForge.String', 7),
+ ('ScriptForge.UI', 8)])
+
+ def __init__(self, hostname = '', port = 0):
+ """
+ Because singleton, constructor is executed only once while Python active
+ Arguments are mandatory when Python and LibreOffice run in separate processes
+ :param hostname: probably 'localhost'
+ :param port: port number
+ """
+ ScriptForge.hostname = hostname
+ ScriptForge.port = port
+ # Determine main pyuno entry points
+ ScriptForge.componentcontext = self.ConnectToLOProcess(hostname, port) # com.sun.star.uno.XComponentContext
+ ScriptForge.scriptprovider = self.ScriptProvider(self.componentcontext) # ...script.provider.XScriptProvider
+ #
+ # Establish a list of the available services as a dictionary (servicename, serviceclass)
+ ScriptForge.serviceslist = dict((cls.servicename, cls) for cls in SFServices.__subclasses__())
+ ScriptForge.servicesdispatcher = None
+ #
+ # All properties and methods of the ScriptForge API are ProperCased
+ # Compute their synonyms as lowercased and camelCased names
+ ScriptForge.SetAttributeSynonyms()
+ #
+ ScriptForge.SCRIPTFORGEINITDONE = True
+
+ @classmethod
+ def ConnectToLOProcess(cls, hostname = '', port = 0):
+ """
+ Called by the ScriptForge class constructor to establish the connection with
+ the requested LibreOffice instance
+ The default arguments are for the usual interactive mode
+
+ :param hostname: probably 'localhost' or ''
+ :param port: port number or 0
+ :return: the derived component context
+ """
+ if len(hostname) > 0 and port > 0: # Explicit connection request via socket
+ ctx = uno.getComponentContext() # com.sun.star.uno.XComponentContext
+ resolver = ctx.ServiceManager.createInstanceWithContext(
+ 'com.sun.star.bridge.UnoUrlResolver', ctx) # com.sun.star.comp.bridge.UnoUrlResolver
+ try:
+ conn = 'socket,host=%s,port=%d' % (hostname, port)
+ url = 'uno:%s;urp;StarOffice.ComponentContext' % conn
+ ctx = resolver.resolve(url)
+ except Exception: # thrown when LibreOffice specified instance isn't started
+ raise SystemExit(
+ 'Connection to LibreOffice failed (host = ' + hostname + ', port = ' + str(port) + ')')
+ return ctx
+ elif len(hostname) == 0 and port == 0: # Usual interactive mode
+ return uno.getComponentContext()
+ else:
+ raise SystemExit('The creation of the ScriptForge() instance got invalid arguments: '
+ + '(host = ' + hostname + ', port = ' + str(port) + ')')
+
+ @classmethod
+ def ScriptProvider(cls, context = None):
+ """
+ Returns the general script provider
+ """
+ servicemanager = context.ServiceManager # com.sun.star.lang.XMultiComponentFactory
+ masterscript = servicemanager.createInstanceWithContext(
+ 'com.sun.star.script.provider.MasterScriptProviderFactory', context)
+ return masterscript.createScriptProvider("")
+
+ @classmethod
+ def InvokeSimpleScript(cls, script, *args):
+ """
+ Create a UNO object corresponding with the given Python or Basic script
+ The execution is done with the invoke() method applied on the created object
+ Implicit scope: Either
+ "application" a shared library (BASIC)
+ "share" a library of LibreOffice Macros (PYTHON)
+ :param script: Either
+ [@][scope#][library.]module.method - Must not be a class module or method
+ [@] means that the targeted method accepts ParamArray arguments (Basic only)
+ [scope#][directory/]module.py$method - Must be a method defined at module level
+ :return: the value returned by the invoked script, or an error if the script was not found
+ """
+
+ # The frequently called PythonDispatcher in the ScriptForge Basic library is cached to privilege performance
+ if cls.servicesdispatcher is not None and script == ScriptForge.basicdispatcher:
+ xscript = cls.servicesdispatcher
+ fullscript = script
+ paramarray = True
+ # Build the URI specification described in
+ # https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+ elif len(script) > 0:
+ # Check ParamArray arguments
+ paramarray = False
+ if script[0] == '@':
+ script = script[1:]
+ paramarray = True
+ scope = ''
+ if '#' in script:
+ scope, script = script.split('#')
+ if '.py$' in script.lower(): # Python
+ if len(scope) == 0:
+ scope = 'share' # Default for Python
+ # Provide an alternate helper script depending on test context
+ if script.startswith(cls.pythonhelpermodule) and hasattr(cls, 'pythonhelpermodule2'):
+ script = cls.pythonhelpermodule2 + script[len(cls.pythonhelpermodule):]
+ if '#' in script:
+ scope, script = script.split('#')
+ uri = 'vnd.sun.star.script:{0}?language=Python&location={1}'.format(script, scope)
+ else: # Basic
+ if len(scope) == 0:
+ scope = 'application' # Default for Basic
+ lib = ''
+ if len(script.split('.')) < 3:
+ lib = cls.library + '.' # Default library = ScriptForge
+ uri = 'vnd.sun.star.script:{0}{1}?language=Basic&location={2}'.format(lib, script, scope)
+ # Get the script object
+ fullscript = ('@' if paramarray else '') + scope + ':' + script
+ try:
+ xscript = cls.scriptprovider.getScript(uri)
+ except Exception:
+ raise RuntimeError(
+ 'The script \'{0}\' could not be located in your LibreOffice installation'.format(script))
+ else: # Should not happen
+ return None
+
+ # At 1st execution of the common Basic dispatcher, buffer xscript
+ if fullscript == ScriptForge.basicdispatcher and cls.servicesdispatcher is None:
+ cls.servicesdispatcher = xscript
+
+ # Execute the script with the given arguments
+ # Packaging for script provider depends on presence of ParamArray arguments in the called Basic script
+ if paramarray:
+ scriptreturn = xscript.invoke(args[0], (), ())
+ else:
+ scriptreturn = xscript.invoke(args, (), ())
+
+ #
+ return scriptreturn[0] # Updatable arguments passed by reference are ignored
+
+ @classmethod
+ def InvokeBasicService(cls, basicobject, flags, method, *args):
+ """
+ Execute a given Basic script and interpret its result
+ This method has as counterpart the ScriptForge.SF_PythonHelper._PythonDispatcher() Basic method
+ :param basicobject: a Service subclass
+ :param flags: see the vb* and flg* constants in the SFServices class
+ :param method: the name of the method or property to invoke, as a string
+ :param args: the arguments of the method. Symbolic cst* constants may be necessary
+ :return: The invoked Basic counterpart script (with InvokeSimpleScript()) will return a tuple
+ [0] The returned value - scalar, object reference or a tuple
+ [1] The Basic VarType() of the returned value
+ Null, Empty and Nothing have different vartypes but return all None to Python
+ Additionally, when [0] is a tuple:
+ [2] Number of dimensions in Basic
+ Additionally, when [0] is a UNO or Basic object:
+ [2] Module (1), Class instance (2) or UNO (3)
+ [3] The object's ObjectType
+ [4] The object's ServiceName
+ [5] The object's name
+ When an error occurs Python receives None as a scalar. This determines the occurrence of a failure
+ The method returns either
+ - the 0th element of the tuple when scalar, tuple or UNO object
+ - a new Service() object or one of its subclasses otherwise
+ """
+ # Constants
+ script = ScriptForge.basicdispatcher
+ cstNoArgs = '+++NOARGS+++'
+ cstValue, cstVarType, cstDims, cstClass, cstType, cstService, cstName = 0, 1, 2, 2, 3, 4, 5
+
+ #
+ # Run the basic script
+ # The targeted script has a ParamArray argument. Do not change next 4 lines except if you know what you do !
+ if len(args) == 0:
+ args = (basicobject,) + (flags,) + (method,) + (cstNoArgs,)
+ else:
+ args = (basicobject,) + (flags,) + (method,) + args
+ returntuple = cls.InvokeSimpleScript(script, args)
+ #
+ # Interpret the result
+ # Did an error occur in the Basic world ?
+ if not isinstance(returntuple, (tuple, list)):
+ raise RuntimeError("The execution of the method '" + method + "' failed. Execution stops.")
+ #
+ # Analyze the returned tuple
+ if returntuple[cstVarType] == ScriptForge.V_OBJECT and len(returntuple) > cstClass: # Avoid Nothing
+ if returntuple[cstClass] == ScriptForge.objUNO:
+ pass
+ else:
+ # Create the new class instance of the right subclass of SFServices()
+ servname = returntuple[cstService]
+ if servname not in cls.serviceslist:
+ # When service not found
+ raise RuntimeError("The service '" + servname + "' is not available in Python. Execution stops.")
+ subcls = cls.serviceslist[servname]
+ if subcls is not None:
+ return subcls(returntuple[cstValue], returntuple[cstType], returntuple[cstClass],
+ returntuple[cstName])
+ elif returntuple[cstVarType] >= ScriptForge.V_ARRAY:
+ # Intercept empty array
+ if isinstance(returntuple[cstValue], uno.ByteSequence):
+ return ()
+ elif returntuple[cstVarType] == ScriptForge.V_DATE:
+ dat = SFScriptForge.SF_Basic.CDateFromUnoDateTime(returntuple[cstValue])
+ return dat
+ else: # All other scalar values
+ pass
+ return returntuple[cstValue]
+
+ @staticmethod
+ def SetAttributeSynonyms():
+ """
+ A synonym of an attribute is either the lowercase or the camelCase form of its original ProperCase name.
+ In every subclass of SFServices:
+ 1) Fill the propertysynonyms dictionary with the synonyms of the properties listed in serviceproperties
+ Example:
+ serviceproperties = dict(ConfigFolder = False, InstallFolder = False)
+ propertysynonyms = dict(configfolder = 'ConfigFolder', installfolder = 'InstallFolder',
+ configFolder = 'ConfigFolder', installFolder = 'InstallFolder')
+ 2) Define new method attributes synonyms of the original methods
+ Example:
+ def CopyFile(...):
+ # etc ...
+ copyFile, copyfile = CopyFile, CopyFile
+ """
+ def camelCase(key):
+ return key[0].lower() + key[1:]
+
+ for cls in SFServices.__subclasses__():
+ # Synonyms of properties
+ if hasattr(cls, 'serviceproperties'):
+ dico = cls.serviceproperties
+ dicosyn = dict(zip(map(str.lower, dico.keys()), dico.keys())) # lower case
+ cc = dict(zip(map(camelCase, dico.keys()), dico.keys())) # camel Case
+ dicosyn.update(cc)
+ setattr(cls, 'propertysynonyms', dicosyn)
+ # Synonyms of methods. A method is a public callable attribute
+ methods = [method for method in dir(cls) if not method.startswith('_')]
+ for method in methods:
+ func = getattr(cls, method)
+ if callable(func):
+ # Assign to each synonym a reference to the original method
+ lc = method.lower()
+ setattr(cls, lc, func)
+ cc = camelCase(method)
+ if cc != lc:
+ setattr(cls, cc, func)
+ return
+
+ @staticmethod
+ def unpack_args(kwargs):
+ """
+ Convert a dictionary passed as argument to a list alternating keys and values
+ Example:
+ dict(A = 'a', B = 2) => 'A', 'a', 'B', 2
+ """
+ return [v for p in zip(list(kwargs.keys()), list(kwargs.values())) for v in p]
+
+
+# #####################################################################################################################
+# SFServices CLASS (ScriptForge services superclass) ###
+# #####################################################################################################################
+
+class SFServices(object):
+ """
+ Generic implementation of a parent Service class
+ Every service must subclass this class to be recognized as a valid service
+ A service instance is created by the CreateScriptService method
+ It can have a mirror in the Basic world or be totally defined in Python
+
+ Every subclass must initialize 3 class properties:
+ servicename (e.g. 'ScriptForge.FileSystem', 'ScriptForge.Basic')
+ servicesynonyms (e.g. 'FileSystem', 'Basic')
+ serviceimplementation: either 'python' or 'basic'
+ This is sufficient to register the service in the Python world
+
+ The communication with Basic is managed by 2 ScriptForge() methods:
+ InvokeSimpleScript(): low level invocation of a Basic script. This script must be located
+ in a usual Basic module. The result is passed as-is
+ InvokeBasicService(): the result comes back encapsulated with additional info
+ The result is interpreted in the method
+ The invoked script can be a property or a method of a Basic class or usual module
+ It is up to every service method to determine which method to use
+
+ For Basic services only:
+ Each instance is identified by its
+ - object reference: the real Basic object embedded as a UNO wrapper object
+ - object type ('SF_String', 'DICTIONARY', ...)
+ - class module: 1 for usual modules, 2 for class modules
+ - name (form, control, ... name) - may be blank
+
+ The role of the SFServices() superclass is mainly to propose a generic properties management
+ Properties are got and set following next strategy:
+ 1. Property names are controlled strictly ('Value' or 'value', not 'VALUE')
+ 2. Getting a property value for the first time is always done via a Basic call
+ 3. Next occurrences are fetched from the Python dictionary of the instance if the property
+ is read-only, otherwise via a Basic call
+ 4. Read-only properties may be modified or deleted exceptionally by the class
+ when self.internal == True. The latter must immediately be reset after use
+
+ Each subclass must define its interface with the user scripts:
+ 1. The properties
+ Property names are proper-cased
+ Conventionally, camel-cased and lower-cased synonyms are supported where relevant
+ a dictionary named 'serviceproperties' with keys = (proper-cased) property names and value = boolean
+ True = editable, False = read-only
+ a list named 'localProperties' reserved to properties for internal use
+ e.g. oDlg.Controls() is a method that uses '_Controls' to hold the list of available controls
+ When
+ forceGetProperty = False # Standard behaviour
+ read-only serviceproperties are buffered in Python after their 1st get request to Basic
+ Otherwise set it to True to force a recomputation at each property getter invocation
+ If there is a need to handle a specific property in a specific manner:
+ @property
+ def myProperty(self):
+ return self.GetProperty('myProperty')
+ 2 The methods
+ a usual def: statement
+ def myMethod(self, arg1, arg2 = ''):
+ return self.Execute(self.vbMethod, 'myMethod', arg1, arg2)
+ Method names are proper-cased, arguments are lower-cased
+ Conventionally, camel-cased and lower-cased homonyms are supported where relevant
+ All arguments must be present and initialized before the call to Basic, if any
+ """
+ # Python-Basic protocol constants and flags
+ vbGet, vbLet, vbMethod, vbSet = 2, 4, 1, 8 # CallByName constants
+ flgPost = 32 # The method or the property implies a hardcoded post-processing
+ flgDateArg = 64 # Invoked service method may contain a date argument
+ flgDateRet = 128 # Invoked service method can return a date
+ flgArrayArg = 512 # 1st argument can be a 2D array
+ flgArrayRet = 1024 # Invoked service method can return a 2D array (standard modules) or any array (class modules)
+ flgUno = 256 # Invoked service method/property can return a UNO object
+ flgObject = 2048 # 1st argument may be a Basic object
+ flgHardCode = 4096 # Force hardcoded call to method, avoid CallByName()
+ # Basic class type
+ moduleClass, moduleStandard = 2, 1
+ #
+ # Define the default behaviour for read-only properties: buffer their values in Python
+ forceGetProperty = False
+ # Empty dictionary for lower/camelcased homonyms or properties
+ propertysynonyms = {}
+ # To operate dynamic property getting/setting it is necessary to
+ # enumerate all types of properties and adapt __getattr__() and __setattr__() according to their type
+ internal_attributes = ('objectreference', 'objecttype', 'name', 'internal', 'servicename',
+ 'serviceimplementation', 'classmodule', 'EXEC', 'SIMPLEEXEC')
+ # Shortcuts to script provider interfaces
+ SIMPLEEXEC = ScriptForge.InvokeSimpleScript
+ EXEC = ScriptForge.InvokeBasicService
+
+ def __init__(self, reference = -1, objtype = None, classmodule = 0, name = ''):
+ """
+ Trivial initialization of internal properties
+ If the subclass has its own __init()__ method, a call to this one should be its first statement.
+ Afterwards localProperties should be filled with the list of its own properties
+ """
+ self.objectreference = reference # the index in the Python storage where the Basic object is stored
+ self.objecttype = objtype # ('SF_String', 'DICTIONARY', ...)
+ self.classmodule = classmodule # Module (1), Class instance (2)
+ self.name = name # '' when no name
+ self.internal = False # True to exceptionally allow assigning a new value to a read-only property
+ self.localProperties = [] # the properties reserved for internal use (often empty)
+
+ def __getattr__(self, name):
+ """
+ Executed for EVERY property reference if name not yet in the instance dict
+ At the 1st get, the property value is always got from Basic
+ Due to the use of lower/camelcase synonyms, it is called for each variant of the same property
+ The method manages itself the buffering in __dict__ based on the official ProperCase property name
+ """
+ if name in self.propertysynonyms: # Reset real name if argument provided in lower or camel case
+ name = self.propertysynonyms[name]
+ if self.serviceimplementation == 'basic':
+ if name in ('serviceproperties', 'localProperties', 'internal_attributes', 'propertysynonyms',
+ 'forceGetProperty'):
+ pass
+ elif name in self.serviceproperties:
+ if self.forceGetProperty is False and self.serviceproperties[name] is False: # False = read-only
+ if name in self.__dict__:
+ return self.__dict__[name]
+ else:
+ # Get Property from Basic and store it
+ prop = self.GetProperty(name)
+ self.__dict__[name] = prop
+ return prop
+ else: # Get Property from Basic and do not store it
+ return self.GetProperty(name)
+ # Execute the usual attributes getter
+ return super(SFServices, self).__getattribute__(name)
+
+ def __setattr__(self, name, value):
+ """
+ Executed for EVERY property assignment, including in __init__() !!
+ Setting a property requires for serviceproperties() to be executed in Basic
+ Management of __dict__ is automatically done in the final usual object.__setattr__ method
+ """
+ if self.serviceimplementation == 'basic':
+ if name in ('serviceproperties', 'localProperties', 'internal_attributes', 'propertysynonyms',
+ 'forceGetProperty'):
+ pass
+ elif name[0:2] == '__' or name in self.internal_attributes or name in self.localProperties:
+ pass
+ elif name in self.serviceproperties or name in self.propertysynonyms:
+ if name in self.propertysynonyms: # Reset real name if argument provided in lower or camel case
+ name = self.propertysynonyms[name]
+ if self.internal: # internal = True forces property local setting even if property is read-only
+ pass
+ elif self.serviceproperties[name] is True: # True == Editable
+ self.SetProperty(name, value)
+ return
+ else:
+ raise AttributeError(
+ "type object '" + self.objecttype + "' has no editable property '" + name + "'")
+ else:
+ raise AttributeError("type object '" + self.objecttype + "' has no property '" + name + "'")
+ object.__setattr__(self, name, value)
+ return
+
+ def __repr__(self):
+ return self.serviceimplementation + '/' + self.servicename + '/' + str(self.objectreference) + '/' + \
+ super(SFServices, self).__repr__()
+
+ def Dispose(self):
+ if self.serviceimplementation == 'basic':
+ if self.objectreference >= len(ScriptForge.servicesmodules): # Do not dispose predefined module objects
+ self.ExecMethod(self.vbMethod, 'Dispose')
+ self.objectreference = -1
+
+ def ExecMethod(self, flags = 0, methodname = '', *args):
+ if flags == 0:
+ flags = self.vbMethod
+ if len(methodname) > 0:
+ return self.EXEC(self.objectreference, flags, methodname, *args)
+
+ def GetProperty(self, propertyname, arg = None):
+ """
+ Get the given property from the Basic world
+ """
+ if self.serviceimplementation == 'basic':
+ # Conventionally properties starting with X (and only them) may return a UNO object
+ calltype = self.vbGet + (self.flgUno if propertyname[0] == 'X' else 0)
+ if arg is None:
+ return self.EXEC(self.objectreference, calltype, propertyname)
+ else: # There are a few cases (Calc ...) where GetProperty accepts an argument
+ return self.EXEC(self.objectreference, calltype, propertyname, arg)
+ return None
+
+ def Properties(self):
+ return list(self.serviceproperties)
+
+ def basicmethods(self):
+ if self.serviceimplementation == 'basic':
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Methods')
+ else:
+ return []
+
+ def basicproperties(self):
+ if self.serviceimplementation == 'basic':
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Properties')
+ else:
+ return []
+
+ def SetProperty(self, propertyname, value):
+ """
+ Set the given property to a new value in the Basic world
+ """
+ if self.serviceimplementation == 'basic':
+ flag = self.vbLet
+ if isinstance(value, datetime.datetime):
+ value = SFScriptForge.SF_Basic.CDateToUnoDateTime(value)
+ flag += self.flgDateArg
+ if repr(type(value)) == "<class 'pyuno'>":
+ flag += self.flgUno
+ return self.EXEC(self.objectreference, flag, propertyname, value)
+
+
+# #####################################################################################################################
+# SFScriptForge CLASS (alias of ScriptForge Basic library) ###
+# #####################################################################################################################
+class SFScriptForge:
+ pass
+
+ # #########################################################################
+ # SF_Array CLASS
+ # #########################################################################
+ class SF_Array(SFServices, metaclass = _Singleton):
+ """
+ Provides a collection of methods for manipulating and transforming arrays of one dimension (vectors)
+ and arrays of two dimensions (matrices). This includes set operations, sorting,
+ importing to and exporting from text files.
+ The Python version of the service provides a single method: ImportFromCSVFile
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.Array'
+ servicesynonyms = ('array', 'scriptforge.array')
+ serviceproperties = dict()
+
+ def ImportFromCSVFile(self, filename, delimiter = ',', dateformat = ''):
+ """
+ Difference with the Basic version: dates are returned in their iso format,
+ not as any of the datetime objects.
+ """
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'ImportFromCSVFile',
+ filename, delimiter, dateformat)
+
+ # #########################################################################
+ # SF_Basic CLASS
+ # #########################################################################
+ class SF_Basic(SFServices, metaclass = _Singleton):
+ """
+ This service proposes a collection of Basic methods to be executed in a Python context
+ simulating the exact syntax and behaviour of the identical Basic builtin method.
+ Typical example:
+ SF_Basic.MsgBox('This has to be displayed in a message box')
+
+ The signatures of Basic builtin functions are derived from
+ core/basic/source/runtime/stdobj.cxx
+
+ Detailed user documentation:
+ https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_basic.html?DbPAR=BASIC
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'python'
+ servicename = 'ScriptForge.Basic'
+ servicesynonyms = ('basic', 'scriptforge.basic')
+ # Basic helper functions invocation
+ module = 'SF_PythonHelper'
+ # Message box constants
+ MB_ABORTRETRYIGNORE, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3 = 2, 128, 256, 512
+ MB_ICONEXCLAMATION, MB_ICONINFORMATION, MB_ICONQUESTION, MB_ICONSTOP = 48, 64, 32, 16
+ MB_OK, MB_OKCANCEL, MB_RETRYCANCEL, MB_YESNO, MB_YESNOCANCEL = 0, 1, 5, 4, 3
+ IDABORT, IDCANCEL, IDIGNORE, IDNO, IDOK, IDRETRY, IDYES = 3, 2, 5, 7, 1, 4, 6
+
+ @classmethod
+ def CDate(cls, datevalue):
+ cdate = cls.SIMPLEEXEC(cls.module + '.PyCDate', datevalue)
+ return cls.CDateFromUnoDateTime(cdate)
+
+ @staticmethod
+ def CDateFromUnoDateTime(unodate):
+ """
+ Converts a UNO date/time representation to a datetime.datetime Python native object
+ :param unodate: com.sun.star.util.DateTime, com.sun.star.util.Date or com.sun.star.util.Time
+ :return: the equivalent datetime.datetime
+ """
+ date = datetime.datetime(1899, 12, 30, 0, 0, 0, 0) # Idem as Basic builtin TimeSeria() function
+ datetype = repr(type(unodate))
+ if 'com.sun.star.util.DateTime' in datetype:
+ if 1900 <= unodate.Year <= datetime.MAXYEAR:
+ date = datetime.datetime(unodate.Year, unodate.Month, unodate.Day, unodate.Hours,
+ unodate.Minutes, unodate.Seconds, int(unodate.NanoSeconds / 1000))
+ elif 'com.sun.star.util.Date' in datetype:
+ if 1900 <= unodate.Year <= datetime.MAXYEAR:
+ date = datetime.datetime(unodate.Year, unodate.Month, unodate.Day)
+ elif 'com.sun.star.util.Time' in datetype:
+ date = datetime.datetime(unodate.Hours, unodate.Minutes, unodate.Seconds,
+ int(unodate.NanoSeconds / 1000))
+ else:
+ return unodate # Not recognized as a UNO date structure
+ return date
+
+ @staticmethod
+ def CDateToUnoDateTime(date):
+ """
+ Converts a date representation into the ccom.sun.star.util.DateTime date format
+ Acceptable boundaries: year >= 1900 and <= 32767
+ :param date: datetime.datetime, datetime.date, datetime.time, float (time.time) or time.struct_time
+ :return: a com.sun.star.util.DateTime
+ """
+ unodate = uno.createUnoStruct('com.sun.star.util.DateTime')
+ unodate.Year, unodate.Month, unodate.Day, unodate.Hours, unodate.Minutes, unodate.Seconds, \
+ unodate.NanoSeconds, unodate.IsUTC = \
+ 1899, 12, 30, 0, 0, 0, 0, False # Identical to Basic TimeSerial() function
+
+ if isinstance(date, float):
+ date = time.localtime(date)
+ if isinstance(date, time.struct_time):
+ if 1900 <= date[0] <= 32767:
+ unodate.Year, unodate.Month, unodate.Day, unodate.Hours, unodate.Minutes, unodate.Seconds =\
+ date[0:6]
+ else: # Copy only the time related part
+ unodate.Hours, unodate.Minutes, unodate.Seconds = date[3:3]
+ elif isinstance(date, (datetime.datetime, datetime.date, datetime.time)):
+ if isinstance(date, (datetime.datetime, datetime.date)):
+ if 1900 <= date.year <= 32767:
+ unodate.Year, unodate.Month, unodate.Day = date.year, date.month, date.day
+ if isinstance(date, (datetime.datetime, datetime.time)):
+ unodate.Hours, unodate.Minutes, unodate.Seconds, unodate.NanoSeconds = \
+ date.hour, date.minute, date.second, date.microsecond * 1000
+ else:
+ return date # Not recognized as a date
+ return unodate
+
+ @classmethod
+ def ConvertFromUrl(cls, url):
+ return cls.SIMPLEEXEC(cls.module + '.PyConvertFromUrl', url)
+
+ @classmethod
+ def ConvertToUrl(cls, systempath):
+ return cls.SIMPLEEXEC(cls.module + '.PyConvertToUrl', systempath)
+
+ @classmethod
+ def CreateUnoService(cls, servicename):
+ return cls.SIMPLEEXEC(cls.module + '.PyCreateUnoService', servicename)
+
+ @classmethod
+ def DateAdd(cls, interval, number, date):
+ if isinstance(date, datetime.datetime):
+ date = cls.CDateToUnoDateTime(date)
+ dateadd = cls.SIMPLEEXEC(cls.module + '.PyDateAdd', interval, number, date)
+ return cls.CDateFromUnoDateTime(dateadd)
+
+ @classmethod
+ def DateDiff(cls, interval, date1, date2, firstdayofweek = 1, firstweekofyear = 1):
+ if isinstance(date1, datetime.datetime):
+ date1 = cls.CDateToUnoDateTime(date1)
+ if isinstance(date2, datetime.datetime):
+ date2 = cls.CDateToUnoDateTime(date2)
+ return cls.SIMPLEEXEC(cls.module + '.PyDateDiff', interval, date1, date2, firstdayofweek, firstweekofyear)
+
+ @classmethod
+ def DatePart(cls, interval, date, firstdayofweek = 1, firstweekofyear = 1):
+ if isinstance(date, datetime.datetime):
+ date = cls.CDateToUnoDateTime(date)
+ return cls.SIMPLEEXEC(cls.module + '.PyDatePart', interval, date, firstdayofweek, firstweekofyear)
+
+ @classmethod
+ def DateValue(cls, string):
+ if isinstance(string, datetime.datetime):
+ string = string.isoformat()
+ datevalue = cls.SIMPLEEXEC(cls.module + '.PyDateValue', string)
+ return cls.CDateFromUnoDateTime(datevalue)
+
+ @classmethod
+ def Format(cls, expression, format = ''):
+ if isinstance(expression, datetime.datetime):
+ expression = cls.CDateToUnoDateTime(expression)
+ return cls.SIMPLEEXEC(cls.module + '.PyFormat', expression, format)
+
+ @classmethod
+ def GetDefaultContext(cls):
+ return ScriptForge.componentcontext
+
+ @classmethod
+ def GetGuiType(cls):
+ return cls.SIMPLEEXEC(cls.module + '.PyGetGuiType')
+
+ @classmethod
+ def GetPathSeparator(cls):
+ return os.sep
+
+ @classmethod
+ def GetSystemTicks(cls):
+ return cls.SIMPLEEXEC(cls.module + '.PyGetSystemTicks')
+
+ class GlobalScope(object, metaclass = _Singleton):
+ @classmethod # Mandatory because the GlobalScope class is normally not instantiated
+ def BasicLibraries(cls):
+ return ScriptForge.InvokeSimpleScript(SFScriptForge.SF_Basic.module + '.PyGlobalScope', 'Basic')
+
+ @classmethod
+ def DialogLibraries(cls):
+ return ScriptForge.InvokeSimpleScript(SFScriptForge.SF_Basic.module + '.PyGlobalScope', 'Dialog')
+
+ @classmethod
+ def InputBox(cls, prompt, title = '', default = '', xpostwips = -1, ypostwips = -1):
+ if xpostwips < 0 or ypostwips < 0:
+ return cls.SIMPLEEXEC(cls.module + '.PyInputBox', prompt, title, default)
+ return cls.SIMPLEEXEC(cls.module + '.PyInputBox', prompt, title, default, xpostwips, ypostwips)
+
+ @classmethod
+ def MsgBox(cls, prompt, buttons = 0, title = ''):
+ return cls.SIMPLEEXEC(cls.module + '.PyMsgBox', prompt, buttons, title)
+
+ @classmethod
+ def Now(cls):
+ return datetime.datetime.now()
+
+ @classmethod
+ def RGB(cls, red, green, blue):
+ return int('%02x%02x%02x' % (red, green, blue), 16)
+
+ @property
+ def StarDesktop(self):
+ ctx = ScriptForge.componentcontext
+ if ctx is None:
+ return None
+ smgr = ctx.getServiceManager() # com.sun.star.lang.XMultiComponentFactory
+ DESK = 'com.sun.star.frame.Desktop'
+ desktop = smgr.createInstanceWithContext(DESK, ctx)
+ return desktop
+ starDesktop, stardesktop = StarDesktop, StarDesktop
+
+ @property
+ def ThisComponent(self):
+ """
+ When the current component is the Basic IDE, the ThisComponent object returns
+ in Basic the component owning the currently run user script.
+ Above behaviour cannot be reproduced in Python.
+ :return: the current component or None when not a document
+ """
+ comp = self.StarDesktop.getCurrentComponent()
+ if comp is None:
+ return None
+ impl = comp.ImplementationName
+ if impl in ('com.sun.star.comp.basic.BasicIDE', 'com.sun.star.comp.sfx2.BackingComp'):
+ return None # None when Basic IDE or welcome screen
+ return comp
+ thisComponent, thiscomponent = ThisComponent, ThisComponent
+
+ @property
+ def ThisDatabaseDocument(self):
+ """
+ When the current component is the Basic IDE, the ThisDatabaseDocument object returns
+ in Basic the database owning the currently run user script.
+ Above behaviour cannot be reproduced in Python.
+ :return: the current Base (main) component or None when not a Base document or one of its subcomponents
+ """
+ comp = self.ThisComponent # Get the current component
+ if comp is None:
+ return None
+ #
+ sess = CreateScriptService('Session')
+ impl, ident = '', ''
+ if sess.HasUnoProperty(comp, 'ImplementationName'):
+ impl = comp.ImplementationName
+ if sess.HasUnoProperty(comp, 'Identifier'):
+ ident = comp.Identifier
+ #
+ targetimpl = 'com.sun.star.comp.dba.ODatabaseDocument'
+ if impl == targetimpl: # The current component is the main Base window
+ return comp
+ # Identify resp. form, table/query, table/query in edit mode, report, relations diagram
+ if impl == 'SwXTextDocument' and ident == 'com.sun.star.sdb.FormDesign' \
+ or impl == 'org.openoffice.comp.dbu.ODatasourceBrowser' \
+ or impl in ('org.openoffice.comp.dbu.OTableDesign', 'org.openoffice.comp.dbu.OQuertDesign') \
+ or impl == 'SwXTextDocument' and ident == 'com.sun.star.sdb.TextReportDesign' \
+ or impl == 'org.openoffice.comp.dbu.ORelationDesign':
+ db = comp.ScriptContainer
+ if sess.HasUnoProperty(db, 'ImplementationName'):
+ if db.ImplementationName == targetimpl:
+ return db
+ return None
+ thisDatabaseDocument, thisdatabasedocument = ThisDatabaseDocument, ThisDatabaseDocument
+
+ @classmethod
+ def Xray(cls, unoobject = None):
+ return cls.SIMPLEEXEC('XrayTool._main.xray', unoobject)
+
+ # #########################################################################
+ # SF_Dictionary CLASS
+ # #########################################################################
+ class SF_Dictionary(SFServices, dict):
+ """
+ The service adds to a Python dict instance the interfaces for conversion to and from
+ a list of UNO PropertyValues
+
+ Usage:
+ dico = dict(A = 1, B = 2, C = 3)
+ myDict = CreateScriptService('Dictionary', dico) # Initialize myDict with the content of dico
+ myDict['D'] = 4
+ print(myDict) # {'A': 1, 'B': 2, 'C': 3, 'D': 4}
+ propval = myDict.ConvertToPropertyValues()
+ or
+ dico = dict(A = 1, B = 2, C = 3)
+ myDict = CreateScriptService('Dictionary') # Initialize myDict as an empty dict object
+ myDict.update(dico) # Load the values of dico into myDict
+ myDict['D'] = 4
+ print(myDict) # {'A': 1, 'B': 2, 'C': 3, 'D': 4}
+ propval = myDict.ConvertToPropertyValues()
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'python'
+ servicename = 'ScriptForge.Dictionary'
+ servicesynonyms = ('dictionary', 'scriptforge.dictionary')
+
+ def __init__(self, dic = None):
+ SFServices.__init__(self)
+ dict.__init__(self)
+ if dic is not None:
+ self.update(dic)
+
+ def ConvertToPropertyValues(self):
+ """
+ Store the content of the dictionary in an array of PropertyValues.
+ Each entry in the array is a com.sun.star.beans.PropertyValue.
+ he key is stored in Name, the value is stored in Value.
+
+ If one of the items has a type datetime, it is converted to a com.sun.star.util.DateTime structure.
+ If one of the items is an empty list, it is converted to None.
+
+ The resulting array is empty when the dictionary is empty.
+ """
+ result = []
+ for key in iter(self):
+ value = self[key]
+ item = value
+ if isinstance(value, dict): # check that first level is not itself a (sub)dict
+ item = None
+ elif isinstance(value, (tuple, list)): # check every member of the list is not a (sub)dict
+ if len(value) == 0: # Property values do not like empty lists
+ value = None
+ else:
+ for i in range(len(value)):
+ if isinstance(value[i], dict):
+ value[i] = None
+ item = value
+ elif isinstance(value, (datetime.datetime, datetime.date, datetime.time)):
+ item = SFScriptForge.SF_Basic.CDateToUnoDateTime(value)
+ pv = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
+ pv.Name = key
+ pv.Value = item
+ result.append(pv)
+ return result
+
+ def ImportFromPropertyValues(self, propertyvalues, overwrite = False):
+ """
+ Inserts the contents of an array of PropertyValue objects into the current dictionary.
+ PropertyValue Names are used as keys in the dictionary, whereas Values contain the corresponding values.
+ Date-type values are converted to datetime.datetime instances.
+ :param propertyvalues: a list.tuple containing com.sun.star.beans.PropertyValue objects
+ :param overwrite: When True, entries with same name may exist in the dictionary and their values
+ are overwritten. When False (default), repeated keys are not overwritten.
+ :return: True when successful
+ """
+ result = []
+ for pv in iter(propertyvalues):
+ key = pv.Name
+ if overwrite is True or key not in self:
+ item = pv.Value
+ if 'com.sun.star.util.DateTime' in repr(type(item)):
+ item = datetime.datetime(item.Year, item.Month, item.Day,
+ item.Hours, item.Minutes, item.Seconds, int(item.NanoSeconds / 1000))
+ elif 'com.sun.star.util.Date' in repr(type(item)):
+ item = datetime.datetime(item.Year, item.Month, item.Day)
+ elif 'com.sun.star.util.Time' in repr(type(item)):
+ item = datetime.datetime(item.Hours, item.Minutes, item.Seconds, int(item.NanoSeconds / 1000))
+ result.append((key, item))
+ self.update(result)
+ return True
+
+ # #########################################################################
+ # SF_Exception CLASS
+ # #########################################################################
+ class SF_Exception(SFServices, metaclass = _Singleton):
+ """
+ The Exception service is a collection of methods for code debugging and error handling.
+
+ The Exception service console stores events, variable values and information about errors.
+ Use the console when the Python shell is not available, for example in Calc user defined functions (UDF)
+ or during events processing.
+ Use DebugPrint() method to aggregate additional user data of any type.
+
+ Console entries can be dumped to a text file or visualized in a dialogue.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.Exception'
+ servicesynonyms = ('exception', 'scriptforge.exception')
+ serviceproperties = dict()
+
+ def Console(self, modal = True):
+ # From Python, the current XComponentContext must be added as last argument
+ return self.ExecMethod(self.vbMethod, 'Console', modal, ScriptForge.componentcontext)
+
+ def ConsoleClear(self, keep = 0):
+ return self.ExecMethod(self.vbMethod, 'ConsoleClear', keep)
+
+ def ConsoleToFile(self, filename):
+ return self.ExecMethod(self.vbMethod, 'ConsoleToFile', filename)
+
+ def DebugDisplay(self, *args):
+ # Arguments are concatenated in a single string similar to what the Python print() function would produce
+ self.DebugPrint(*args)
+ param = '\n'.join(list(map(lambda a: a.strip("'") if isinstance(a, str) else repr(a), args)))
+ bas = CreateScriptService('ScriptForge.Basic')
+ return bas.MsgBox(param, bas.MB_OK + bas.MB_ICONINFORMATION, 'DebugDisplay')
+
+ def DebugPrint(self, *args):
+ # Arguments are concatenated in a single string similar to what the Python print() function would produce
+ # Avoid using repr() on strings to not have backslashes * 4
+ param = '\t'.join(list(map(lambda a: a.strip("'") if isinstance(a, str) else repr(a),
+ args))).expandtabs(tabsize = 4)
+ return self.ExecMethod(self.vbMethod, 'DebugPrint', param)
+
+ @classmethod
+ def PythonShell(cls, variables = None):
+ """
+ Open an APSO python shell window - Thanks to its authors Hanya/Tsutomu Uchino/Hubert Lambert
+ :param variables: Typical use
+ PythonShell.({**globals(), **locals()})
+ to push the global and local dictionaries to the shell window
+ """
+ if variables is None:
+ variables = locals()
+ # Is APSO installed ?
+ ctx = ScriptForge.componentcontext
+ ext = ctx.getByName('/singletons/com.sun.star.deployment.PackageInformationProvider')
+ apso = 'apso.python.script.organizer'
+ if len(ext.getPackageLocation(apso)) > 0:
+ # Directly derived from apso.oxt|python|scripts|tools.py$console
+ # we need to load apso before import statement
+ ctx.ServiceManager.createInstance('apso.python.script.organizer.impl')
+ # now we can use apso_utils library
+ from apso_utils import console
+ kwargs = {'loc': variables}
+ kwargs['loc'].setdefault('XSCRIPTCONTEXT', uno)
+ console(**kwargs)
+ # An interprocess call is necessary to allow a redirection of STDOUT and STDERR by APSO
+ # Choice is a minimalist call to a Basic routine: no arguments, a few lines of code
+ SFScriptForge.SF_Basic.GetGuiType()
+ else:
+ # The APSO extension could not be located in your LibreOffice installation
+ cls._RaiseFatal('SF_Exception.PythonShell', 'variables=None', 'PYTHONSHELLERROR')
+
+ @classmethod
+ def RaiseFatal(cls, errorcode, *args):
+ """
+ Generate a run-time error caused by an anomaly in a user script detected by ScriptForge
+ The message is logged in the console. The execution is STOPPED
+ For INTERNAL USE only
+ """
+ # Direct call because RaiseFatal forces an execution stop in Basic
+ if len(args) == 0:
+ args = (None,)
+ return cls.SIMPLEEXEC('@SF_Exception.RaiseFatal', (errorcode, *args)) # With ParamArray
+
+ @classmethod
+ def _RaiseFatal(cls, sub, subargs, errorcode, *args):
+ """
+ Wrapper of RaiseFatal(). Includes method and syntax of the failed Python routine
+ to simulate the exact behaviour of the Basic RaiseFatal() method
+ For INTERNAL USE only
+ """
+ ScriptForge.InvokeSimpleScript('ScriptForge.SF_Utils._EnterFunction', sub, subargs)
+ cls.RaiseFatal(errorcode, *args)
+ raise RuntimeError("The execution of the method '" + sub.split('.')[-1] + "' failed. Execution stops.")
+
+ # #########################################################################
+ # SF_FileSystem CLASS
+ # #########################################################################
+ class SF_FileSystem(SFServices, metaclass = _Singleton):
+ """
+ The "FileSystem" service includes common file and folder handling routines.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.FileSystem'
+ servicesynonyms = ('filesystem', 'scriptforge.filesystem')
+ serviceproperties = dict(FileNaming = True, ConfigFolder = False, ExtensionsFolder = False, HomeFolder = False,
+ InstallFolder = False, TemplatesFolder = False, TemporaryFolder = False,
+ UserTemplatesFolder = False)
+ # Force for each property to get its value from Basic - due to FileNaming updatability
+ forceGetProperty = True
+ # Open TextStream constants
+ ForReading, ForWriting, ForAppending = 1, 2, 8
+
+ def BuildPath(self, foldername, name):
+ return self.ExecMethod(self.vbMethod, 'BuildPath', foldername, name)
+
+ def CompareFiles(self, filename1, filename2, comparecontents = False):
+ py = ScriptForge.pythonhelpermodule + '$' + '_SF_FileSystem__CompareFiles'
+ if self.FileExists(filename1) and self.FileExists(filename2):
+ file1 = self._ConvertFromUrl(filename1)
+ file2 = self._ConvertFromUrl(filename2)
+ return self.SIMPLEEXEC(py, file1, file2, comparecontents)
+ else:
+ return False
+
+ def CopyFile(self, source, destination, overwrite = True):
+ return self.ExecMethod(self.vbMethod, 'CopyFile', source, destination, overwrite)
+
+ def CopyFolder(self, source, destination, overwrite = True):
+ return self.ExecMethod(self.vbMethod, 'CopyFolder', source, destination, overwrite)
+
+ def CreateFolder(self, foldername):
+ return self.ExecMethod(self.vbMethod, 'CreateFolder', foldername)
+
+ def CreateTextFile(self, filename, overwrite = True, encoding = 'UTF-8'):
+ return self.ExecMethod(self.vbMethod, 'CreateTextFile', filename, overwrite, encoding)
+
+ def DeleteFile(self, filename):
+ return self.ExecMethod(self.vbMethod, 'DeleteFile', filename)
+
+ def DeleteFolder(self, foldername):
+ return self.ExecMethod(self.vbMethod, 'DeleteFolder', foldername)
+
+ def ExtensionFolder(self, extension):
+ return self.ExecMethod(self.vbMethod, 'ExtensionFolder', extension)
+
+ def FileExists(self, filename):
+ return self.ExecMethod(self.vbMethod, 'FileExists', filename)
+
+ def Files(self, foldername, filter = ''):
+ return self.ExecMethod(self.vbMethod, 'Files', foldername, filter)
+
+ def FolderExists(self, foldername):
+ return self.ExecMethod(self.vbMethod, 'FolderExists', foldername)
+
+ def GetBaseName(self, filename):
+ return self.ExecMethod(self.vbMethod, 'GetBaseName', filename)
+
+ def GetExtension(self, filename):
+ return self.ExecMethod(self.vbMethod, 'GetExtension', filename)
+
+ def GetFileLen(self, filename):
+ py = ScriptForge.pythonhelpermodule + '$' + '_SF_FileSystem__GetFilelen'
+ if self.FileExists(filename):
+ file = self._ConvertFromUrl(filename)
+ return int(self.SIMPLEEXEC(py, file))
+ else:
+ return 0
+
+ def GetFileModified(self, filename):
+ return self.ExecMethod(self.vbMethod + self.flgDateRet, 'GetFileModified', filename)
+
+ def GetName(self, filename):
+ return self.ExecMethod(self.vbMethod, 'GetName', filename)
+
+ def GetParentFolderName(self, filename):
+ return self.ExecMethod(self.vbMethod, 'GetParentFolderName', filename)
+
+ def GetTempName(self):
+ return self.ExecMethod(self.vbMethod, 'GetTempName')
+
+ def HashFile(self, filename, algorithm):
+ py = ScriptForge.pythonhelpermodule + '$' + '_SF_FileSystem__HashFile'
+ if self.FileExists(filename):
+ file = self._ConvertFromUrl(filename)
+ return self.SIMPLEEXEC(py, file, algorithm.lower())
+ else:
+ return ''
+
+ def MoveFile(self, source, destination):
+ return self.ExecMethod(self.vbMethod, 'MoveFile', source, destination)
+
+ def MoveFolder(self, source, destination):
+ return self.ExecMethod(self.vbMethod, 'MoveFolder', source, destination)
+
+ def OpenTextFile(self, filename, iomode = 1, create = False, encoding = 'UTF-8'):
+ return self.ExecMethod(self.vbMethod, 'OpenTextFile', filename, iomode, create, encoding)
+
+ def PickFile(self, defaultfile = ScriptForge.cstSymEmpty, mode = 'OPEN', filter = ''):
+ return self.ExecMethod(self.vbMethod, 'PickFile', defaultfile, mode, filter)
+
+ def PickFolder(self, defaultfolder = ScriptForge.cstSymEmpty, freetext = ''):
+ return self.ExecMethod(self.vbMethod, 'PickFolder', defaultfolder, freetext)
+
+ def SubFolders(self, foldername, filter = ''):
+ return self.ExecMethod(self.vbMethod, 'SubFolders', foldername, filter)
+
+ @classmethod
+ def _ConvertFromUrl(cls, filename):
+ # Alias for same function in FileSystem Basic module
+ return cls.SIMPLEEXEC('ScriptForge.SF_FileSystem._ConvertFromUrl', filename)
+
+ # #########################################################################
+ # SF_L10N CLASS
+ # #########################################################################
+ class SF_L10N(SFServices):
+ """
+ This service provides a number of methods related to the translation of strings
+ with minimal impact on the program's source code.
+ The methods provided by the L10N service can be used mainly to:
+ Create POT files that can be used as templates for translation of all strings in the program.
+ Get translated strings at runtime for the language defined in the Locale property.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.L10N'
+ servicesynonyms = ('l10n', 'scriptforge.l10n')
+ serviceproperties = dict(Folder = False, Languages = False, Locale = False)
+
+ @classmethod
+ def ReviewServiceArgs(cls, foldername = '', locale = '', encoding = 'UTF-8',
+ locale2 = '', encoding2 = 'UTF-8'):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return foldername, locale, encoding, locale2, encoding2
+
+ def AddText(self, context = '', msgid = '', comment = ''):
+ return self.ExecMethod(self.vbMethod, 'AddText', context, msgid, comment)
+
+ def AddTextsFromDialog(self, dialog):
+ dialogobj = dialog.objectreference if isinstance(dialog, SFDialogs.SF_Dialog) else dialog
+ return self.ExecMethod(self.vbMethod + self.flgObject, 'AddTextsFromDialog', dialogobj)
+
+ def ExportToPOTFile(self, filename, header = '', encoding= 'UTF-8'):
+ return self.ExecMethod(self.vbMethod, 'ExportToPOTFile', filename, header, encoding)
+
+ def GetText(self, msgid, *args):
+ return self.ExecMethod(self.vbMethod, 'GetText', msgid, *args)
+ _ = GetText
+
+ # #########################################################################
+ # SF_Platform CLASS
+ # #########################################################################
+ class SF_Platform(SFServices, metaclass = _Singleton):
+ """
+ The 'Platform' service implements a collection of properties about the actual execution environment
+ and context :
+ the hardware platform
+ the operating system
+ the LibreOffice version
+ the current user
+ All those properties are read-only.
+ The implementation is mainly based on the 'platform' module of the Python standard library
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.Platform'
+ servicesynonyms = ('platform', 'scriptforge.platform')
+ serviceproperties = dict(Architecture = False, ComputerName = False, CPUCount = False, CurrentUser = False,
+ Extensions = False, FilterNames = False, Fonts = False, FormatLocale = False,
+ Locale = False, Machine = False, OfficeLocale = False, OfficeVersion = False,
+ OSName = False, OSPlatform = False, OSRelease = False, OSVersion = False,
+ Printers = False, Processor = False, PythonVersion = False, SystemLocale = False)
+ # Python helper functions
+ py = ScriptForge.pythonhelpermodule + '$' + '_SF_Platform'
+
+ @property
+ def Architecture(self):
+ return self.SIMPLEEXEC(self.py, 'Architecture')
+
+ @property
+ def ComputerName(self):
+ return self.SIMPLEEXEC(self.py, 'ComputerName')
+
+ @property
+ def CPUCount(self):
+ return self.SIMPLEEXEC(self.py, 'CPUCount')
+
+ @property
+ def CurrentUser(self):
+ return self.SIMPLEEXEC(self.py, 'CurrentUser')
+
+ @property
+ def Machine(self):
+ return self.SIMPLEEXEC(self.py, 'Machine')
+
+ @property
+ def OSName(self):
+ return self.SIMPLEEXEC(self.py, 'OSName')
+
+ @property
+ def OSPlatform(self):
+ return self.SIMPLEEXEC(self.py, 'OSPlatform')
+
+ @property
+ def OSRelease(self):
+ return self.SIMPLEEXEC(self.py, 'OSRelease')
+
+ @property
+ def OSVersion(self):
+ return self.SIMPLEEXEC(self.py, 'OSVersion')
+
+ @property
+ def Processor(self):
+ return self.SIMPLEEXEC(self.py, 'Processor')
+
+ @property
+ def PythonVersion(self):
+ return self.SIMPLEEXEC(self.py, 'PythonVersion')
+
+ # #########################################################################
+ # SF_Region CLASS
+ # #########################################################################
+ class SF_Region(SFServices, metaclass = _Singleton):
+ """
+ The "Region" service gathers a collection of functions about languages, countries and timezones
+ - Locales
+ - Currencies
+ - Numbers and dates formatting
+ - Calendars
+ - Timezones conversions
+ - Numbers transformed to text
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.Region'
+ servicesynonyms = ('region', 'scriptforge.region')
+ serviceproperties = dict()
+
+ # Next functions are implemented in Basic as read-only properties with 1 argument
+ def Country(self, region = ''):
+ return self.GetProperty('Country', region)
+
+ def Currency(self, region = ''):
+ return self.GetProperty('Currency', region)
+
+ def DatePatterns(self, region = ''):
+ return self.GetProperty('DatePatterns', region)
+
+ def DateSeparator(self, region = ''):
+ return self.GetProperty('DateSeparator', region)
+
+ def DayAbbrevNames(self, region = ''):
+ return self.GetProperty('DayAbbrevNames', region)
+
+ def DayNames(self, region = ''):
+ return self.GetProperty('DayNames', region)
+
+ def DayNarrowNames(self, region = ''):
+ return self.GetProperty('DayNarrowNames', region)
+
+ def DecimalPoint(self, region = ''):
+ return self.GetProperty('DecimalPoint', region)
+
+ def Language(self, region = ''):
+ return self.GetProperty('Language', region)
+
+ def ListSeparator(self, region = ''):
+ return self.GetProperty('ListSeparator', region)
+
+ def MonthAbbrevNames(self, region = ''):
+ return self.GetProperty('MonthAbbrevNames', region)
+
+ def MonthNames(self, region = ''):
+ return self.GetProperty('MonthNames', region)
+
+ def MonthNarrowNames(self, region = ''):
+ return self.GetProperty('MonthNarrowNames', region)
+
+ def ThousandSeparator(self, region = ''):
+ return self.GetProperty('ThousandSeparator', region)
+
+ def TimeSeparator(self, region = ''):
+ return self.GetProperty('TimeSeparator', region)
+
+ # Usual methods
+ def DSTOffset(self, localdatetime, timezone, locale = ''):
+ if isinstance(localdatetime, datetime.datetime):
+ localdatetime = SFScriptForge.SF_Basic.CDateToUnoDateTime(localdatetime)
+ return self.ExecMethod(self.vbMethod + self.flgDateArg, 'DSTOffset', localdatetime, timezone, locale)
+
+ def LocalDateTime(self, utcdatetime, timezone, locale = ''):
+ if isinstance(utcdatetime, datetime.datetime):
+ utcdatetime = SFScriptForge.SF_Basic.CDateToUnoDateTime(utcdatetime)
+ localdate = self.ExecMethod(self.vbMethod + self.flgDateArg + self.flgDateRet, 'LocalDateTime',
+ utcdatetime, timezone, locale)
+ return SFScriptForge.SF_Basic.CDateFromUnoDateTime(localdate)
+
+ def Number2Text(self, number, locale = ''):
+ return self.ExecMethod(self.vbMethod, 'Number2Text', number, locale)
+
+ def TimeZoneOffset(self, timezone, locale = ''):
+ return self.ExecMethod(self.vbMethod, 'TimeZoneOffset', timezone, locale)
+
+ def UTCDateTime(self, localdatetime, timezone, locale = ''):
+ if isinstance(localdatetime, datetime.datetime):
+ localdatetime = SFScriptForge.SF_Basic.CDateToUnoDateTime(localdatetime)
+ utcdate = self.ExecMethod(self.vbMethod + self.flgDateArg + self.flgDateRet, 'UTCDateTime', localdatetime,
+ timezone, locale)
+ return SFScriptForge.SF_Basic.CDateFromUnoDateTime(utcdate)
+
+ def UTCNow(self, timezone, locale = ''):
+ now = self.ExecMethod(self.vbMethod + self.flgDateRet, 'UTCNow', timezone, locale)
+ return SFScriptForge.SF_Basic.CDateFromUnoDateTime(now)
+
+ # #########################################################################
+ # SF_Session CLASS
+ # #########################################################################
+ class SF_Session(SFServices, metaclass = _Singleton):
+ """
+ The Session service gathers various general-purpose methods about:
+ - UNO introspection
+ - the invocation of external scripts or programs
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.Session'
+ servicesynonyms = ('session', 'scriptforge.session')
+ serviceproperties = dict()
+
+ # Class constants Where to find an invoked library ?
+ SCRIPTISEMBEDDED = 'document' # in the document
+ SCRIPTISAPPLICATION = 'application' # in any shared library (Basic)
+ SCRIPTISPERSONAL = 'user' # in My Macros (Python)
+ SCRIPTISPERSOXT = 'user:uno_packages' # in an extension installed for the current user (Python)
+ SCRIPTISSHARED = 'share' # in LibreOffice macros (Python)
+ SCRIPTISSHAROXT = 'share:uno_packages' # in an extension installed for all users (Python)
+ SCRIPTISOXT = 'uno_packages' # in an extension but the installation parameters are unknown (Python)
+
+ @classmethod
+ def ExecuteBasicScript(cls, scope = '', script = '', *args):
+ if scope is None or scope == '':
+ scope = cls.SCRIPTISAPPLICATION
+ if len(args) == 0:
+ args = (scope,) + (script,) + (None,)
+ else:
+ args = (scope,) + (script,) + args
+ # ExecuteBasicScript method has a ParamArray parameter in Basic
+ return cls.SIMPLEEXEC('@SF_Session.ExecuteBasicScript', args)
+
+ @classmethod
+ def ExecuteCalcFunction(cls, calcfunction, *args):
+ if len(args) == 0:
+ # Arguments of Calc functions are strings or numbers. None == Empty is a good alias for no argument
+ args = (calcfunction,) + (None,)
+ else:
+ args = (calcfunction,) + args
+ # ExecuteCalcFunction method has a ParamArray parameter in Basic
+ return cls.SIMPLEEXEC('@SF_Session.ExecuteCalcFunction', args)
+
+ @classmethod
+ def ExecutePythonScript(cls, scope = '', script = '', *args):
+ return cls.SIMPLEEXEC(scope + '#' + script, *args)
+
+ def HasUnoMethod(self, unoobject, methodname):
+ return self.ExecMethod(self.vbMethod, 'HasUnoMethod', unoobject, methodname)
+
+ def HasUnoProperty(self, unoobject, propertyname):
+ return self.ExecMethod(self.vbMethod, 'HasUnoProperty', unoobject, propertyname)
+
+ @classmethod
+ def OpenURLInBrowser(cls, url):
+ py = ScriptForge.pythonhelpermodule + '$' + '_SF_Session__OpenURLInBrowser'
+ return cls.SIMPLEEXEC(py, url)
+
+ def RunApplication(self, command, parameters):
+ return self.ExecMethod(self.vbMethod, 'RunApplication', command, parameters)
+
+ def SendMail(self, recipient, cc = '', bcc = '', subject = '', body = '', filenames = '', editmessage = True):
+ return self.ExecMethod(self.vbMethod, 'SendMail', recipient, cc, bcc, subject, body, filenames, editmessage)
+
+ def UnoObjectType(self, unoobject):
+ return self.ExecMethod(self.vbMethod, 'UnoObjectType', unoobject)
+
+ def UnoMethods(self, unoobject):
+ return self.ExecMethod(self.vbMethod, 'UnoMethods', unoobject)
+
+ def UnoProperties(self, unoobject):
+ return self.ExecMethod(self.vbMethod, 'UnoProperties', unoobject)
+
+ def WebService(self, uri):
+ return self.ExecMethod(self.vbMethod, 'WebService', uri)
+
+ # #########################################################################
+ # SF_String CLASS
+ # #########################################################################
+ class SF_String(SFServices, metaclass = _Singleton):
+ """
+ Focus on string manipulation, regular expressions, encodings and hashing algorithms.
+ The methods implemented in Basic that are redundant with Python builtin functions
+ are not duplicated
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.String'
+ servicesynonyms = ('string', 'scriptforge.string')
+ serviceproperties = dict()
+
+ @classmethod
+ def HashStr(cls, inputstr, algorithm):
+ py = ScriptForge.pythonhelpermodule + '$' + '_SF_String__HashStr'
+ return cls.SIMPLEEXEC(py, inputstr, algorithm.lower())
+
+ def IsADate(self, inputstr, dateformat = 'YYYY-MM-DD'):
+ return self.ExecMethod(self.vbMethod, 'IsADate', inputstr, dateformat)
+
+ def IsEmail(self, inputstr):
+ return self.ExecMethod(self.vbMethod, 'IsEmail', inputstr)
+
+ def IsFileName(self, inputstr, osname = ScriptForge.cstSymEmpty):
+ return self.ExecMethod(self.vbMethod, 'IsFileName', inputstr, osname)
+
+ def IsIBAN(self, inputstr):
+ return self.ExecMethod(self.vbMethod, 'IsIBAN', inputstr)
+
+ def IsIPv4(self, inputstr):
+ return self.ExecMethod(self.vbMethod, 'IsIPv4', inputstr)
+
+ def IsLike(self, inputstr, pattern, casesensitive = False):
+ return self.ExecMethod(self.vbMethod, 'IsLike', inputstr, pattern, casesensitive)
+
+ def IsSheetName(self, inputstr):
+ return self.ExecMethod(self.vbMethod, 'IsSheetName', inputstr)
+
+ def IsUrl(self, inputstr):
+ return self.ExecMethod(self.vbMethod, 'IsUrl', inputstr)
+
+ def SplitNotQuoted(self, inputstr, delimiter = ' ', occurrences = 0, quotechar = '"'):
+ return self.ExecMethod(self.vbMethod, 'SplitNotQuoted', inputstr, delimiter, occurrences, quotechar)
+
+ def Wrap(self, inputstr, width = 70, tabsize = 8):
+ return self.ExecMethod(self.vbMethod, 'Wrap', inputstr, width, tabsize)
+
+ # #########################################################################
+ # SF_TextStream CLASS
+ # #########################################################################
+ class SF_TextStream(SFServices):
+ """
+ The TextStream service is used to sequentially read from and write to files opened or created
+ using the ScriptForge.FileSystem service..
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.TextStream'
+ servicesynonyms = ()
+ serviceproperties = dict(AtEndOfStream = False, Encoding = False, FileName = False, IOMode = False,
+ Line = False, NewLine = True)
+
+ @property
+ def AtEndOfStream(self):
+ return self.GetProperty('AtEndOfStream')
+ atEndOfStream, atendofstream = AtEndOfStream, AtEndOfStream
+
+ @property
+ def Line(self):
+ return self.GetProperty('Line')
+ line = Line
+
+ def CloseFile(self):
+ return self.ExecMethod(self.vbMethod, 'CloseFile')
+
+ def ReadAll(self):
+ return self.ExecMethod(self.vbMethod, 'ReadAll')
+
+ def ReadLine(self):
+ return self.ExecMethod(self.vbMethod, 'ReadLine')
+
+ def SkipLine(self):
+ return self.ExecMethod(self.vbMethod, 'SkipLine')
+
+ def WriteBlankLines(self, lines):
+ return self.ExecMethod(self.vbMethod, 'WriteBlankLines', lines)
+
+ def WriteLine(self, line):
+ return self.ExecMethod(self.vbMethod, 'WriteLine', line)
+
+ # #########################################################################
+ # SF_Timer CLASS
+ # #########################################################################
+ class SF_Timer(SFServices):
+ """
+ The "Timer" service measures the amount of time it takes to run user scripts.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.Timer'
+ servicesynonyms = ('timer', 'scriptforge.timer')
+ serviceproperties = dict(Duration = False, IsStarted = False, IsSuspended = False,
+ SuspendDuration = False, TotalDuration = False)
+ # Force for each property to get its value from Basic
+ forceGetProperty = True
+
+ @classmethod
+ def ReviewServiceArgs(cls, start = False):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return (start,)
+
+ def Continue(self):
+ return self.ExecMethod(self.vbMethod, 'Continue')
+
+ def Restart(self):
+ return self.ExecMethod(self.vbMethod, 'Restart')
+
+ def Start(self):
+ return self.ExecMethod(self.vbMethod, 'Start')
+
+ def Suspend(self):
+ return self.ExecMethod(self.vbMethod, 'Suspend')
+
+ def Terminate(self):
+ return self.ExecMethod(self.vbMethod, 'Terminate')
+
+ # #########################################################################
+ # SF_UI CLASS
+ # #########################################################################
+ class SF_UI(SFServices, metaclass = _Singleton):
+ """
+ Singleton class for the identification and the manipulation of the
+ different windows composing the whole LibreOffice application:
+ - Windows selection
+ - Windows moving and resizing
+ - Statusbar settings
+ - Creation of new windows
+ - Access to the underlying "documents"
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'ScriptForge.UI'
+ servicesynonyms = ('ui', 'scriptforge.ui')
+ serviceproperties = dict(ActiveWindow = False, Height = False, Width = False, X = False, Y = False)
+
+ # Class constants
+ MACROEXECALWAYS, MACROEXECNEVER, MACROEXECNORMAL = 2, 1, 0
+ BASEDOCUMENT, CALCDOCUMENT, DRAWDOCUMENT, IMPRESSDOCUMENT, MATHDOCUMENT, WRITERDOCUMENT = \
+ 'Base', 'Calc', 'Draw', 'Impress', 'Math', 'Writer'
+
+ @property
+ def ActiveWindow(self):
+ return self.ExecMethod(self.vbMethod, 'ActiveWindow')
+ activeWindow, activewindow = ActiveWindow, ActiveWindow
+
+ def Activate(self, windowname = ''):
+ return self.ExecMethod(self.vbMethod, 'Activate', windowname)
+
+ def CreateBaseDocument(self, filename, embeddeddatabase = 'HSQLDB', registrationname = '', calcfilename = ''):
+ return self.ExecMethod(self.vbMethod, 'CreateBaseDocument', filename, embeddeddatabase, registrationname,
+ calcfilename)
+
+ def CreateDocument(self, documenttype = '', templatefile = '', hidden = False):
+ return self.ExecMethod(self.vbMethod, 'CreateDocument', documenttype, templatefile, hidden)
+
+ def Documents(self):
+ return self.ExecMethod(self.vbMethod, 'Documents')
+
+ def GetDocument(self, windowname = ''):
+ return self.ExecMethod(self.vbMethod, 'GetDocument', windowname)
+
+ def Maximize(self, windowname = ''):
+ return self.ExecMethod(self.vbMethod, 'Maximize', windowname)
+
+ def Minimize(self, windowname = ''):
+ return self.ExecMethod(self.vbMethod, 'Minimize', windowname)
+
+ def OpenBaseDocument(self, filename = '', registrationname = '', macroexecution = MACROEXECNORMAL):
+ return self.ExecMethod(self.vbMethod, 'OpenBaseDocument', filename, registrationname, macroexecution)
+
+ def OpenDocument(self, filename, password = '', readonly = False, hidden = False,
+ macroexecution = MACROEXECNORMAL, filtername = '', filteroptions = ''):
+ return self.ExecMethod(self.vbMethod, 'OpenDocument', filename, password, readonly, hidden,
+ macroexecution, filtername, filteroptions)
+
+ def Resize(self, left = -1, top = -1, width = -1, height = -1):
+ return self.ExecMethod(self.vbMethod, 'Resize', left, top, width, height)
+
+ def RunCommand(self, command, *args, **kwargs):
+ params = tuple(list(args) + ScriptForge.unpack_args(kwargs))
+ if len(params) == 0:
+ params = (command,) + (None,)
+ else:
+ params = (command,) + params
+ return self.SIMPLEEXEC('@SF_UI.RunCommand', params)
+
+ def SetStatusbar(self, text = '', percentage = -1):
+ return self.ExecMethod(self.vbMethod, 'SetStatusbar', text, percentage)
+
+ def ShowProgressBar(self, title = '', text = '', percentage = -1):
+ # From Python, the current XComponentContext must be added as last argument
+ return self.ExecMethod(self.vbMethod, 'ShowProgressBar', title, text, percentage,
+ ScriptForge.componentcontext)
+
+ def WindowExists(self, windowname):
+ return self.ExecMethod(self.vbMethod, 'WindowExists', windowname)
+
+
+# #####################################################################################################################
+# SFDatabases CLASS (alias of SFDatabases Basic library) ###
+# #####################################################################################################################
+class SFDatabases:
+ """
+ The SFDatabases class manages databases embedded in or connected to Base documents
+ """
+ pass
+
+ # #########################################################################
+ # SF_Database CLASS
+ # #########################################################################
+ class SF_Database(SFServices):
+ """
+ Each instance of the current class represents a single database, with essentially its tables, queries
+ and data
+ The exchanges with the database are done in SQL only.
+ To make them more readable, use optionally square brackets to surround table/query/field names
+ instead of the (RDBMS-dependent) normal surrounding character.
+ SQL statements may be run in direct or indirect mode. In direct mode the statement is transferred literally
+ without syntax checking nor review to the database engine.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDatabases.Database'
+ servicesynonyms = ('database', 'sfdatabases.database')
+ serviceproperties = dict(Queries = False, Tables = False, XConnection = False, XMetaData = False)
+
+ @classmethod
+ def ReviewServiceArgs(cls, filename = '', registrationname = '', readonly = True, user = '', password = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return filename, registrationname, readonly, user, password
+
+ def CloseDatabase(self):
+ return self.ExecMethod(self.vbMethod, 'CloseDatabase')
+
+ def DAvg(self, expression, tablename, criteria = ''):
+ return self.ExecMethod(self.vbMethod, 'DAvg', expression, tablename, criteria)
+
+ def DCount(self, expression, tablename, criteria = ''):
+ return self.ExecMethod(self.vbMethod, 'DCount', expression, tablename, criteria)
+
+ def DLookup(self, expression, tablename, criteria = '', orderclause = ''):
+ return self.ExecMethod(self.vbMethod, 'DLookup', expression, tablename, criteria, orderclause)
+
+ def DMax(self, expression, tablename, criteria = ''):
+ return self.ExecMethod(self.vbMethod, 'DMax', expression, tablename, criteria)
+
+ def DMin(self, expression, tablename, criteria = ''):
+ return self.ExecMethod(self.vbMethod, 'DMin', expression, tablename, criteria)
+
+ def DSum(self, expression, tablename, criteria = ''):
+ return self.ExecMethod(self.vbMethod, 'DSum', expression, tablename, criteria)
+
+ def GetRows(self, sqlcommand, directsql = False, header = False, maxrows = 0):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'GetRows', sqlcommand, directsql, header, maxrows)
+
+ def RunSql(self, sqlcommand, directsql = False):
+ return self.ExecMethod(self.vbMethod, 'RunSql', sqlcommand, directsql)
+
+
+# #####################################################################################################################
+# SFDialogs CLASS (alias of SFDialogs Basic library) ###
+# #####################################################################################################################
+class SFDialogs:
+ """
+ The SFDialogs class manages dialogs defined with the Basic IDE
+ """
+ pass
+
+ # #########################################################################
+ # SF_Dialog CLASS
+ # #########################################################################
+ class SF_Dialog(SFServices):
+ """
+ Each instance of the current class represents a single dialog box displayed to the user.
+ The dialog box must have been designed and defined with the Basic IDE previously.
+ From a Python script, a dialog box can be displayed in modal or in non-modal modes.
+
+ In modal mode, the box is displayed and the execution of the macro process is suspended
+ until one of the OK or Cancel buttons is pressed. In the meantime, other user actions
+ executed on the box can trigger specific actions.
+
+ In non-modal mode, the floating dialog remains displayed until the dialog is terminated
+ by code (Terminate()) or until the LibreOffice application stops.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDialogs.Dialog'
+ servicesynonyms = ('dialog', 'sfdialogs.dialog')
+ serviceproperties = dict(Caption = True, Height = True, Modal = False, Name = False,
+ OnFocusGained = False, OnFocusLost = False, OnKeyPressed = False,
+ OnKeyReleased = False, OnMouseDragged = False, OnMouseEntered = False,
+ OnMouseExited = False, OnMouseMoved = False, OnMousePressed = False,
+ OnMouseReleased = False,
+ Page = True, Visible = True, Width = True, XDialogModel = False, XDialogView = False)
+ # Class constants used together with the Execute() method
+ OKBUTTON, CANCELBUTTON = 1, 0
+
+ @classmethod
+ def ReviewServiceArgs(cls, container = '', library = 'Standard', dialogname = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ Add the XComponentContext as last argument
+ """
+ return container, library, dialogname, ScriptForge.componentcontext
+
+ # Methods potentially executed while the dialog is in execution require the flgHardCode flag
+ def Activate(self):
+ return self.ExecMethod(self.vbMethod + self.flgHardCode, 'Activate')
+
+ def Center(self, parent = ScriptForge.cstSymMissing):
+ parentclasses = (SFDocuments.SF_Document, SFDocuments.SF_Base, SFDocuments.SF_Calc, SFDocuments.SF_Writer,
+ SFDialogs.SF_Dialog)
+ parentobj = parent.objectreference if isinstance(parent, parentclasses) else parent
+ return self.ExecMethod(self.vbMethod + self.flgObject + self.flgHardCode, 'Center', parentobj)
+
+ def Controls(self, controlname = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet + self.flgHardCode, 'Controls', controlname)
+
+ def EndExecute(self, returnvalue):
+ return self.ExecMethod(self.vbMethod + self.flgHardCode, 'EndExecute', returnvalue)
+
+ def Execute(self, modal = True):
+ return self.ExecMethod(self.vbMethod + self.flgHardCode, 'Execute', modal)
+
+ def GetTextsFromL10N(self, l10n):
+ l10nobj = l10n.objectreference if isinstance(l10n, SFScriptForge.SF_L10N) else l10n
+ return self.ExecMethod(self.vbMethod + self.flgObject, 'GetTextsFromL10N', l10nobj)
+
+ def Resize(self, left = -1, top = -1, width = -1, height = -1):
+ return self.ExecMethod(self.vbMethod + self.flgHardCode, 'Resize', left, top, width, height)
+
+ def Terminate(self):
+ return self.ExecMethod(self.vbMethod, 'Terminate')
+
+ # #########################################################################
+ # SF_DialogControl CLASS
+ # #########################################################################
+ class SF_DialogControl(SFServices):
+ """
+ Each instance of the current class represents a single control within a dialog box.
+ The focus is clearly set on getting and setting the values displayed by the controls of the dialog box,
+ not on their formatting.
+ A special attention is given to controls with type TreeControl.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDialogs.DialogControl'
+ servicesynonyms = ()
+ serviceproperties = dict(Cancel = True, Caption = True, ControlType = False, CurrentNode = True,
+ Default = True, Enabled = True, Format = True, ListCount = False,
+ ListIndex = True, Locked = True, MultiSelect = True, Name = False,
+ OnActionPerformed = False, OnAdjustmentValueChanged = False, OnFocusGained = False,
+ OnFocusLost = False, OnItemStateChanged = False, OnKeyPressed = False,
+ OnKeyReleased = False, OnMouseDragged = False, OnMouseEntered = False,
+ OnMouseExited = False, OnMouseMoved = False, OnMousePressed = False,
+ OnMouseReleased = False, OnNodeExpanded = True, OnNodeSelected = True,
+ OnTextChanged = False, Page = True, Parent = False, Picture = True,
+ RootNode = False, RowSource = True, Text = False, TipText = True,
+ TripleState = True, Value = True, Visible = True,
+ XControlModel = False, XControlView = False, XGridColumnModel = False,
+ XGridDataModel = False, XTreeDataModel = False)
+
+ # Root related properties do not start with X and, nevertheless, return a UNO object
+ @property
+ def CurrentNode(self):
+ return self.EXEC(self.objectreference, self.vbGet + self.flgUno, 'CurrentNode')
+
+ @property
+ def RootNode(self):
+ return self.EXEC(self.objectreference, self.vbGet + self.flgUno, 'RootNode')
+
+ def AddSubNode(self, parentnode, displayvalue, datavalue = ScriptForge.cstSymEmpty):
+ return self.ExecMethod(self.vbMethod + self.flgUno, 'AddSubNode', parentnode, displayvalue, datavalue)
+
+ def AddSubTree(self, parentnode, flattree, withdatavalue = False):
+ return self.ExecMethod(self.vbMethod, 'AddSubTree', parentnode, flattree, withdatavalue)
+
+ def CreateRoot(self, displayvalue, datavalue = ScriptForge.cstSymEmpty):
+ return self.ExecMethod(self.vbMethod + self.flgUno, 'CreateRoot', displayvalue, datavalue)
+
+ def FindNode(self, displayvalue, datavalue = ScriptForge.cstSymEmpty, casesensitive = False):
+ return self.ExecMethod(self.vbMethod + self.flgUno, 'FindNode', displayvalue, datavalue, casesensitive)
+
+ def SetFocus(self):
+ return self.ExecMethod(self.vbMethod, 'SetFocus')
+
+ def SetTableData(self, dataarray, widths = (1,), alignments = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayArg, 'SetTableData', dataarray, widths, alignments)
+
+ def WriteLine(self, line = ''):
+ return self.ExecMethod(self.vbMethod, 'WriteLine', line)
+
+
+# #####################################################################################################################
+# SFDocuments CLASS (alias of SFDocuments Basic library) ###
+# #####################################################################################################################
+class SFDocuments:
+ """
+ The SFDocuments class gathers a number of classes, methods and properties making easy
+ managing and manipulating LibreOffice documents
+ """
+ pass
+
+ # #########################################################################
+ # SF_Document CLASS
+ # #########################################################################
+ class SF_Document(SFServices):
+ """
+ The methods and properties are generic for all types of documents: they are combined in the
+ current SF_Document class
+ - saving, closing documents
+ - accessing their standard or custom properties
+ Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Base, ...
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.Document'
+ servicesynonyms = ('document', 'sfdocuments.document')
+ serviceproperties = dict(Description = True, DocumentType = False, ExportFilters = False, ImportFilters = False,
+ IsBase = False, IsCalc = False, IsDraw = False, IsImpress = False, IsMath = False,
+ IsWriter = False, Keywords = True, Readonly = False, Subject = True, Title = True,
+ XComponent = False)
+ # Force for each property to get its value from Basic - due to intense interactivity with user
+ forceGetProperty = True
+
+ @classmethod
+ def ReviewServiceArgs(cls, windowname = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return windowname,
+
+ def Activate(self):
+ return self.ExecMethod(self.vbMethod, 'Activate')
+
+ def CloseDocument(self, saveask = True):
+ return self.ExecMethod(self.vbMethod, 'CloseDocument', saveask)
+
+ def CreateMenu(self, menuheader, before = '', submenuchar = '>'):
+ return self.ExecMethod(self.vbMethod, 'CreateMenu', menuheader, before, submenuchar)
+
+ def ExportAsPDF(self, filename, overwrite = False, pages = '', password = '', watermark = ''):
+ return self.ExecMethod(self.vbMethod, 'ExportAsPDF', filename, overwrite, pages, password, watermark)
+
+ def PrintOut(self, pages = '', copies = 1):
+ return self.ExecMethod(self.vbMethod, 'PrintOut', pages, copies)
+
+ def RemoveMenu(self, menuheader):
+ return self.ExecMethod(self.vbMethod, 'RemoveMenu', menuheader)
+
+ def RunCommand(self, command, *args, **kwargs):
+ params = tuple([command] + list(args) + ScriptForge.unpack_args(kwargs))
+ return self.ExecMethod(self.vbMethod, 'RunCommand', *params)
+
+ def Save(self):
+ return self.ExecMethod(self.vbMethod, 'Save')
+
+ def SaveAs(self, filename, overwrite = False, password = '', filtername = '', filteroptions = ''):
+ return self.ExecMethod(self.vbMethod, 'SaveAs', filename, overwrite, password, filtername, filteroptions)
+
+ def SaveCopyAs(self, filename, overwrite = False, password = '', filtername = '', filteroptions = ''):
+ return self.ExecMethod(self.vbMethod, 'SaveCopyAs', filename, overwrite,
+ password, filtername, filteroptions)
+
+ def SetPrinter(self, printer = '', orientation = '', paperformat = ''):
+ return self.ExecMethod(self.vbMethod, 'SetPrinter', printer, orientation, paperformat)
+
+ # #########################################################################
+ # SF_Base CLASS
+ # #########################################################################
+ class SF_Base(SF_Document, SFServices):
+ """
+ The SF_Base module is provided mainly to block parent properties that are NOT applicable to Base documents
+ In addition, it provides methods to identify form documents and access their internal forms
+ (read more elsewhere (the "SFDocuments.Form" service) about this subject)
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.Base'
+ servicesynonyms = ('base', 'scriptforge.base')
+ serviceproperties = dict(DocumentType = False, IsBase = False, IsCalc = False,
+ IsDraw = False, IsImpress = False, IsMath = False, IsWriter = False,
+ XComponent = False)
+
+ @classmethod
+ def ReviewServiceArgs(cls, windowname = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return windowname,
+
+ def CloseDocument(self, saveask = True):
+ return self.ExecMethod(self.vbMethod, 'CloseDocument', saveask)
+
+ def CloseFormDocument(self, formdocument):
+ return self.ExecMethod(self.vbMethod, 'CloseFormDocument', formdocument)
+
+ def FormDocuments(self):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'FormDocuments')
+
+ def Forms(self, formdocument, form = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Forms', formdocument, form)
+
+ def GetDatabase(self, user = '', password = ''):
+ return self.ExecMethod(self.vbMethod, 'GetDatabase', user, password)
+
+ def IsLoaded(self, formdocument):
+ return self.ExecMethod(self.vbMethod, 'IsLoaded', formdocument)
+
+ def OpenFormDocument(self, formdocument, designmode = False):
+ return self.ExecMethod(self.vbMethod, 'OpenFormDocument', formdocument, designmode)
+
+ def PrintOut(self, formdocument, pages = '', copies = 1):
+ return self.ExecMethod(self.vbMethod, 'PrintOut', formdocument, pages, copies)
+
+ def SetPrinter(self, formdocument = '', printer = '', orientation = '', paperformat = ''):
+ return self.ExecMethod(self.vbMethod, 'SetPrinter', formdocument, printer, orientation, paperformat)
+
+ # #########################################################################
+ # SF_Calc CLASS
+ # #########################################################################
+ class SF_Calc(SF_Document, SFServices):
+ """
+ The SF_Calc module is focused on :
+ - management (copy, insert, move, ...) of sheets within a Calc document
+ - exchange of data between Basic data structures and Calc ranges of values
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.Calc'
+ servicesynonyms = ('calc', 'sfdocuments.calc')
+ serviceproperties = dict(CurrentSelection = True, Sheets = False,
+ Description = True, DocumentType = False, ExportFilters = False, ImportFilters = False,
+ IsBase = False, IsCalc = False, IsDraw = False, IsImpress = False, IsMath = False,
+ IsWriter = False, Keywords = True, Readonly = False, Subject = True, Title = True,
+ XComponent = False)
+ # Force for each property to get its value from Basic - due to intense interactivity with user
+ forceGetProperty = True
+
+ @classmethod
+ def ReviewServiceArgs(cls, windowname = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return windowname,
+
+ # Next functions are implemented in Basic as read-only properties with 1 argument
+ def FirstCell(self, rangename):
+ return self.GetProperty('FirstCell', rangename)
+
+ def FirstColumn(self, rangename):
+ return self.GetProperty('FirstColumn', rangename)
+
+ def FirstRow(self, rangename):
+ return self.GetProperty('FirstRow', rangename)
+
+ def Height(self, rangename):
+ return self.GetProperty('Height', rangename)
+
+ def LastCell(self, rangename):
+ return self.GetProperty('LastCell', rangename)
+
+ def LastColumn(self, rangename):
+ return self.GetProperty('LastColumn', rangename)
+
+ def LastRow(self, rangename):
+ return self.GetProperty('LastRow', rangename)
+
+ def Range(self, rangename):
+ return self.GetProperty('Range', rangename)
+
+ def Region(self, rangename):
+ return self.GetProperty('Region', rangename)
+
+ def Sheet(self, sheetname):
+ return self.GetProperty('Sheet', sheetname)
+
+ def SheetName(self, rangename):
+ return self.GetProperty('SheetName', rangename)
+
+ def Width(self, rangename):
+ return self.GetProperty('Width', rangename)
+
+ def XCellRange(self, rangename):
+ return self.ExecMethod(self.vbGet + self.flgUno, 'XCellRange', rangename)
+
+ def XSheetCellCursor(self, rangename):
+ return self.ExecMethod(self.vbGet + self.flgUno, 'XSheetCellCursor', rangename)
+
+ def XSpreadsheet(self, sheetname):
+ return self.ExecMethod(self.vbGet + self.flgUno, 'XSpreadsheet', sheetname)
+
+ # Usual methods
+ def A1Style(self, row1, column1, row2 = 0, column2 = 0, sheetname = '~'):
+ return self.ExecMethod(self.vbMethod, 'A1Style', row1, column1, row2, column2, sheetname)
+
+ def Activate(self, sheetname = ''):
+ return self.ExecMethod(self.vbMethod, 'Activate', sheetname)
+
+ def Charts(self, sheetname, chartname = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Charts', sheetname, chartname)
+
+ def ClearAll(self, range):
+ return self.ExecMethod(self.vbMethod, 'ClearAll', range)
+
+ def ClearFormats(self, range):
+ return self.ExecMethod(self.vbMethod, 'ClearFormats', range)
+
+ def ClearValues(self, range):
+ return self.ExecMethod(self.vbMethod, 'ClearValues', range)
+
+ def CompactLeft(self, range, wholecolumn = False, filterformula = ''):
+ return self.ExecMethod(self.vbMethod, 'CompactLeft', range, wholecolumn, filterformula)
+
+ def CompactUp(self, range, wholerow = False, filterformula = ''):
+ return self.ExecMethod(self.vbMethod, 'CompactUp', range, wholerow, filterformula)
+
+ def CopySheet(self, sheetname, newname, beforesheet = 32768):
+ sheet = (sheetname.objectreference if isinstance(sheetname, SFDocuments.SF_CalcReference) else sheetname)
+ return self.ExecMethod(self.vbMethod + self.flgObject, 'CopySheet', sheet, newname, beforesheet)
+
+ def CopySheetFromFile(self, filename, sheetname, newname, beforesheet = 32768):
+ sheet = (sheetname.objectreference if isinstance(sheetname, SFDocuments.SF_CalcReference) else sheetname)
+ return self.ExecMethod(self.vbMethod + self.flgObject, 'CopySheetFromFile',
+ filename, sheet, newname, beforesheet)
+
+ def CopyToCell(self, sourcerange, destinationcell):
+ range = (sourcerange.objectreference if isinstance(sourcerange, SFDocuments.SF_CalcReference)
+ else sourcerange)
+ return self.ExecMethod(self.vbMethod + self.flgObject, 'CopyToCell', range, destinationcell)
+
+ def CopyToRange(self, sourcerange, destinationrange):
+ range = (sourcerange.objectreference if isinstance(sourcerange, SFDocuments.SF_CalcReference)
+ else sourcerange)
+ return self.ExecMethod(self.vbMethod + self.flgObject, 'CopyToRange', range, destinationrange)
+
+ def CreateChart(self, chartname, sheetname, range, columnheader = False, rowheader = False):
+ return self.ExecMethod(self.vbMethod, 'CreateChart', chartname, sheetname, range, columnheader, rowheader)
+
+ def CreatePivotTable(self, pivottablename, sourcerange, targetcell, datafields = ScriptForge.cstSymEmpty,
+ rowfields = ScriptForge.cstSymEmpty, columnfields = ScriptForge.cstSymEmpty,
+ filterbutton = True, rowtotals = True, columntotals = True):
+ return self.ExecMethod(self.vbMethod, 'CreatePivotTable', pivottablename, sourcerange, targetcell,
+ datafields, rowfields, columnfields, filterbutton, rowtotals, columntotals)
+
+ def DAvg(self, range):
+ return self.ExecMethod(self.vbMethod, 'DAvg', range)
+
+ def DCount(self, range):
+ return self.ExecMethod(self.vbMethod, 'DCount', range)
+
+ def DMax(self, range):
+ return self.ExecMethod(self.vbMethod, 'DMax', range)
+
+ def DMin(self, range):
+ return self.ExecMethod(self.vbMethod, 'DMin', range)
+
+ def DSum(self, range):
+ return self.ExecMethod(self.vbMethod, 'DSum', range)
+
+ def ExportRangeToFile(self, range, filename, imagetype = 'pdf', overwrite = False):
+ return self.ExecMethod(self.vbMethod, 'ExportRangeToFile', range, filename, imagetype, overwrite)
+
+ def Forms(self, sheetname, form = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Forms', sheetname, form)
+
+ def GetColumnName(self, columnnumber):
+ return self.ExecMethod(self.vbMethod, 'GetColumnName', columnnumber)
+
+ def GetFormula(self, range):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'GetFormula', range)
+
+ def GetValue(self, range):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'GetValue', range)
+
+ def ImportFromCSVFile(self, filename, destinationcell, filteroptions = ScriptForge.cstSymEmpty):
+ return self.ExecMethod(self.vbMethod, 'ImportFromCSVFile', filename, destinationcell, filteroptions)
+
+ def ImportFromDatabase(self, filename = '', registrationname = '', destinationcell = '', sqlcommand = '',
+ directsql = False):
+ return self.ExecMethod(self.vbMethod, 'ImportFromDatabase', filename, registrationname,
+ destinationcell, sqlcommand, directsql)
+
+ def InsertSheet(self, sheetname, beforesheet = 32768):
+ return self.ExecMethod(self.vbMethod, 'InsertSheet', sheetname, beforesheet)
+
+ def MoveRange(self, source, destination):
+ return self.ExecMethod(self.vbMethod, 'MoveRange', source, destination)
+
+ def MoveSheet(self, sheetname, beforesheet = 32768):
+ return self.ExecMethod(self.vbMethod, 'MoveSheet', sheetname, beforesheet)
+
+ def Offset(self, range, rows = 0, columns = 0, height = ScriptForge.cstSymEmpty,
+ width = ScriptForge.cstSymEmpty):
+ return self.ExecMethod(self.vbMethod, 'Offset', range, rows, columns, height, width)
+
+ def OpenRangeSelector(self, title = '', selection = '~', singlecell = False, closeafterselect = True):
+ return self.ExecMethod(self.vbMethod, 'OpenRangeSelector', title, selection, singlecell, closeafterselect)
+
+ def Printf(self, inputstr, range, tokencharacter = '%'):
+ return self.ExecMethod(self.vbMethod, 'Printf', inputstr, range, tokencharacter)
+
+ def PrintOut(self, sheetname = '~', pages = '', copies = 1):
+ return self.ExecMethod(self.vbMethod, 'PrintOut', sheetname, pages, copies)
+
+ def RemoveSheet(self, sheetname):
+ return self.ExecMethod(self.vbMethod, 'RemoveSheet', sheetname)
+
+ def RenameSheet(self, sheetname, newname):
+ return self.ExecMethod(self.vbMethod, 'RenameSheet', sheetname, newname)
+
+ def SetArray(self, targetcell, value):
+ return self.ExecMethod(self.vbMethod + self.flgArrayArg, 'SetArray', targetcell, value)
+
+ def SetCellStyle(self, targetrange, style):
+ return self.ExecMethod(self.vbMethod, 'SetCellStyle', targetrange, style)
+
+ def SetFormula(self, targetrange, formula):
+ return self.ExecMethod(self.vbMethod + self.flgArrayArg, 'SetFormula', targetrange, formula)
+
+ def SetValue(self, targetrange, value):
+ return self.ExecMethod(self.vbMethod + self.flgArrayArg, 'SetValue', targetrange, value)
+
+ def ShiftDown(self, range, wholerow = False, rows = 0):
+ return self.ExecMethod(self.vbMethod, 'ShiftDown', range, wholerow, rows)
+
+ def ShiftLeft(self, range, wholecolumn = False, columns = 0):
+ return self.ExecMethod(self.vbMethod, 'ShiftLeft', range, wholecolumn, columns)
+
+ def ShiftRight(self, range, wholecolumn = False, columns = 0):
+ return self.ExecMethod(self.vbMethod, 'ShiftRight', range, wholecolumn, columns)
+
+ def ShiftUp(self, range, wholerow = False, rows = 0):
+ return self.ExecMethod(self.vbMethod, 'ShiftUp', range, wholerow, rows)
+
+ def SortRange(self, range, sortkeys, sortorder = 'ASC', destinationcell = ScriptForge.cstSymEmpty,
+ containsheader = False, casesensitive = False, sortcolumns = False):
+ return self.ExecMethod(self.vbMethod, 'SortRange', range, sortkeys, sortorder, destinationcell,
+ containsheader, casesensitive, sortcolumns)
+
+ # #########################################################################
+ # SF_CalcReference CLASS
+ # #########################################################################
+ class SF_CalcReference(SFServices):
+ """
+ The SF_CalcReference class has as unique role to hold sheet and range references.
+ They are implemented in Basic as Type ... End Type data structures
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.CalcReference'
+ servicesynonyms = ()
+ serviceproperties = dict()
+
+ # #########################################################################
+ # SF_Chart CLASS
+ # #########################################################################
+ class SF_Chart(SFServices):
+ """
+ The SF_Chart module is focused on the description of chart documents
+ stored in Calc sheets.
+ With this service, many chart types and chart characteristics available
+ in the user interface can be read or modified.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.Chart'
+ servicesynonyms = ()
+ serviceproperties = dict(ChartType = True, Deep = True, Dim3D = True, Exploded = True, Filled = True,
+ Legend = True, Percent = True, Stacked = True, Title = True,
+ XChartObj = False, XDiagram = False, XShape = False, XTableChart = False,
+ XTitle = True, YTitle = True)
+
+ def Resize(self, xpos = -1, ypos = -1, width = -1, height = -1):
+ return self.ExecMethod(self.vbMethod, 'Resize', xpos, ypos, width, height)
+
+ def ExportToFile(self, filename, imagetype = 'png', overwrite = False):
+ return self.ExecMethod(self.vbMethod, 'ExportToFile', filename, imagetype, overwrite)
+
+ # #########################################################################
+ # SF_Form CLASS
+ # #########################################################################
+ class SF_Form(SFServices):
+ """
+ Management of forms defined in LibreOffice documents. Supported types are Base, Calc and Writer documents.
+ It includes the management of subforms
+ Each instance of the current class represents a single form or a single subform
+ A form may optionally be (understand "is often") linked to a data source manageable with
+ the SFDatabases.Database service. The current service offers a rapid access to that service.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.Form'
+ servicesynonyms = ()
+ serviceproperties = dict(AllowDeletes = True, AllowInserts = True, AllowUpdates = True, BaseForm = False,
+ Bookmark = True, CurrentRecord = True, Filter = True, LinkChildFields = False,
+ LinkParentFields = False, Name = False,
+ OnApproveCursorMove = True, OnApproveParameter = True, OnApproveReset = True,
+ OnApproveRowChange = True, OnApproveSubmit = True, OnConfirmDelete = True,
+ OnCursorMoved = True, OnErrorOccurred = True, OnLoaded = True, OnReloaded = True,
+ OnReloading = True, OnResetted = True, OnRowChanged = True, OnUnloaded = True,
+ OnUnloading = True,
+ OrderBy = True, Parent = False, RecordSource = True, XForm = False)
+
+ def Activate(self):
+ return self.ExecMethod(self.vbMethod, 'Activate')
+
+ def CloseFormDocument(self):
+ return self.ExecMethod(self.vbMethod, 'CloseFormDocument')
+
+ def Controls(self, controlname = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Controls', controlname)
+
+ def GetDatabase(self, user = '', password = ''):
+ return self.ExecMethod(self.vbMethod, 'GetDatabase', user, password)
+
+ def MoveFirst(self):
+ return self.ExecMethod(self.vbMethod, 'MoveFirst')
+
+ def MoveLast(self):
+ return self.ExecMethod(self.vbMethod, 'MoveLast')
+
+ def MoveNew(self):
+ return self.ExecMethod(self.vbMethod, 'MoveNew')
+
+ def MoveNext(self, offset = 1):
+ return self.ExecMethod(self.vbMethod, 'MoveNext', offset)
+
+ def MovePrevious(self, offset = 1):
+ return self.ExecMethod(self.vbMethod, 'MovePrevious', offset)
+
+ def Requery(self):
+ return self.ExecMethod(self.vbMethod, 'Requery')
+
+ def Subforms(self, subform = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Subforms', subform)
+
+ # #########################################################################
+ # SF_FormControl CLASS
+ # #########################################################################
+ class SF_FormControl(SFServices):
+ """
+ Manage the controls belonging to a form or subform stored in a document.
+ Each instance of the current class represents a single control within a form, a subform or a tablecontrol.
+ A prerequisite is that all controls within the same form, subform or tablecontrol must have
+ a unique name.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.FormControl'
+ servicesynonyms = ()
+ serviceproperties = dict(Action = True, Caption = True, ControlSource = False, ControlType = False,
+ Default = True, DefaultValue = True, Enabled = True, Format = True,
+ ListCount = False, ListIndex = True, ListSource = True, ListSourceType = True,
+ Locked = True, MultiSelect = True, Name = False,
+ OnActionPerformed = True, OnAdjustmentValueChanged = True,
+ OnApproveAction = True, OnApproveReset = True, OnApproveUpdate = True,
+ OnChanged = True, OnErrorOccurred = True, OnFocusGained = True, OnFocusLost = True,
+ OnItemStateChanged = True, OnKeyPressed = True, OnKeyReleased = True,
+ OnMouseDragged = True, OnMouseEntered = True, OnMouseExited = True,
+ OnMouseMoved = True, OnMousePressed = True, OnMouseReleased = True, OnResetted = True,
+ OnTextChanged = True, OnUpdated = True, Parent = False, Picture = True,
+ Required = True, Text = False, TipText = True, TripleState = True, Value = True,
+ Visible = True, XControlModel = False, XControlView = False)
+
+ def Controls(self, controlname = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Controls', controlname)
+
+ def SetFocus(self):
+ return self.ExecMethod(self.vbMethod, 'SetFocus')
+
+ # #########################################################################
+ # SF_Writer CLASS
+ # #########################################################################
+ class SF_Writer(SF_Document, SFServices):
+ """
+ The SF_Writer module is focused on :
+ - TBD
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDocuments.Writer'
+ servicesynonyms = ('writer', 'sfdocuments.writer')
+ serviceproperties = dict(Description = True, DocumentType = False, ExportFilters = False, ImportFilters = False,
+ IsBase = False, IsCalc = False, IsDraw = False, IsImpress = False, IsMath = False,
+ IsWriter = False, Keywords = True, Readonly = False, Subject = True, Title = True,
+ XComponent = False)
+ # Force for each property to get its value from Basic - due to intense interactivity with user
+ forceGetProperty = True
+
+ @classmethod
+ def ReviewServiceArgs(cls, windowname = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return windowname,
+
+ def Forms(self, form = ''):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Forms', form)
+
+ def PrintOut(self, pages = '', copies = 1, printbackground = True, printblankpages = False,
+ printevenpages = True, printoddpages = True, printimages = True):
+ return self.ExecMethod(self.vbMethod, 'PrintOut', pages, copies, printbackground, printblankpages,
+ printevenpages, printoddpages, printimages)
+
+
+# #####################################################################################################################
+# SFWidgets CLASS (alias of SFWidgets Basic library) ###
+# #####################################################################################################################
+class SFWidgets:
+ """
+ The SFWidgets class manages toolbars and popup menus
+ """
+ pass
+
+ # #########################################################################
+ # SF_Menu CLASS
+ # #########################################################################
+ class SF_Menu(SFServices):
+ """
+ Display a menu in the menubar of a document or a form document.
+ After use, the menu will not be saved neither in the application settings, nor in the document.
+ The menu will be displayed, as usual, when its header in the menubar is clicked.
+ When one of its items is selected, there are 3 alternative options:
+ - a UNO command (like ".uno:About") is triggered
+ - a user script is run receiving a standard argument defined in this service
+ - one of above combined with a toggle of the status of the item
+ The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFWidgets.Menu'
+ servicesynonyms = ('menu', 'sfwidgets.menu')
+ serviceproperties = dict(ShortcutCharacter = False, SubmenuCharacter = False)
+
+ def AddCheckBox(self, menuitem, name = '', status = False, icon = '', tooltip = '',
+ command = '', script = ''):
+ return self.ExecMethod(self.vbMethod, 'AddCheckBox', menuitem, name, status, icon, tooltip,
+ command, script)
+
+ def AddItem(self, menuitem, name = '', icon = '', tooltip = '', command = '', script = ''):
+ return self.ExecMethod(self.vbMethod, 'AddItem', menuitem, name, icon, tooltip, command, script)
+
+ def AddRadioButton(self, menuitem, name = '', status = False, icon = '', tooltip = '',
+ command = '', script = ''):
+ return self.ExecMethod(self.vbMethod, 'AddRadioButton', menuitem, name, status, icon, tooltip,
+ command, script)
+
+ # #########################################################################
+ # SF_PopupMenu CLASS
+ # #########################################################################
+ class SF_PopupMenu(SFServices):
+ """
+ Display a popup menu anywhere and any time.
+ A popup menu is usually triggered by a mouse action (typically a right-click) on a dialog, a form
+ or one of their controls. In this case the menu will be displayed below the clicked area.
+ When triggered by other events, including in the normal flow of a user script, the script should
+ provide the coordinates of the topleft edge of the menu versus the actual component.
+ The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
+ The execute() method returns the item selected by the user.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFWidgets.PopupMenu'
+ servicesynonyms = ('popupmenu', 'sfwidgets.popupmenu')
+ serviceproperties = dict(ShortcutCharacter = False, SubmenuCharacter = False)
+
+ @classmethod
+ def ReviewServiceArgs(cls, event = None, x = 0, y = 0, submenuchar = ''):
+ """
+ Transform positional and keyword arguments into positional only
+ """
+ return event, x, y, submenuchar
+
+ def AddCheckBox(self, menuitem, name = '', status = False, icon = '', tooltip = ''):
+ return self.ExecMethod(self.vbMethod, 'AddCheckBox', menuitem, name, status, icon, tooltip)
+
+ def AddItem(self, menuitem, name = '', icon = '', tooltip = ''):
+ return self.ExecMethod(self.vbMethod, 'AddItem', menuitem, name, icon, tooltip)
+
+ def AddRadioButton(self, menuitem, name = '', status = False, icon = '', tooltip = ''):
+ return self.ExecMethod(self.vbMethod, 'AddRadioButton', menuitem, name, status, icon, tooltip)
+
+ def Execute(self, returnid = True):
+ return self.ExecMethod(self.vbMethod, 'Execute', returnid)
+
+
+# ##############################################False##################################################################
+# CreateScriptService() ###
+# #####################################################################################################################
+def CreateScriptService(service, *args, **kwargs):
+ """
+ A service being the name of a collection of properties and methods,
+ this method returns either
+ - the Python object mirror of the Basic object implementing the requested service
+ - the Python object implementing the service itself
+
+ A service may be designated by its official name, stored in its class.servicename
+ or by one of its synonyms stored in its class.servicesynonyms list
+ If the service is not identified, the service creation is delegated to Basic, that might raise an error
+ if still not identified there
+
+ :param service: the name of the service as a string 'library.service' - cased exactly
+ or one of its synonyms
+ :param args: the arguments to pass to the service constructor
+ :return: the service as a Python object
+ """
+ # Init at each CreateScriptService() invocation
+ # CreateScriptService is usually the first statement in user scripts requesting ScriptForge services
+ # ScriptForge() is optional in user scripts when Python process inside LibreOffice process
+ if ScriptForge.SCRIPTFORGEINITDONE is False:
+ ScriptForge()
+
+ def ResolveSynonyms(servicename):
+ """
+ Synonyms within service names implemented in Python or predefined are resolved here
+ :param servicename: The short name of the service
+ :return: The official service name if found, the argument otherwise
+ """
+ for cls in SFServices.__subclasses__():
+ if servicename.lower() in cls.servicesynonyms:
+ return cls.servicename
+ return servicename
+
+ #
+ # Check the list of available services
+ scriptservice = ResolveSynonyms(service)
+ if scriptservice in ScriptForge.serviceslist:
+ serv = ScriptForge.serviceslist[scriptservice]
+ # Check if the requested service is within the Python world
+ if serv.serviceimplementation == 'python':
+ return serv(*args)
+ # Check if the service is a predefined standard Basic service
+ elif scriptservice in ScriptForge.servicesmodules:
+ return serv(ScriptForge.servicesmodules[scriptservice], classmodule = SFServices.moduleStandard)
+ else:
+ serv = None
+ # The requested service is to be found in the Basic world
+ # Check if the service must review the arguments
+ if serv is not None:
+ if hasattr(serv, 'ReviewServiceArgs'):
+ # ReviewServiceArgs() must be a class method
+ args = serv.ReviewServiceArgs(*args, **kwargs)
+ # Get the service object back from Basic
+ if len(args) == 0:
+ serv = ScriptForge.InvokeBasicService('SF_Services', SFServices.vbMethod, 'CreateScriptService', service)
+ else:
+ serv = ScriptForge.InvokeBasicService('SF_Services', SFServices.vbMethod, 'CreateScriptService',
+ service, *args)
+ return serv
+
+
+createScriptService, createscriptservice = CreateScriptService, CreateScriptService
+
+
+# ######################################################################
+# Lists the scripts, that shall be visible inside the Basic/Python IDE
+# ######################################################################
+
+g_exportedScripts = ()
diff --git a/wizards/source/scriptforge/script.xlb b/wizards/source/scriptforge/script.xlb
new file mode 100644
index 000000000..dc625046f
--- /dev/null
+++ b/wizards/source/scriptforge/script.xlb
@@ -0,0 +1,23 @@
+<?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="ScriptForge" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="__License"/>
+ <library:element library:name="SF_String"/>
+ <library:element library:name="_CodingConventions"/>
+ <library:element library:name="SF_Timer"/>
+ <library:element library:name="_ModuleModel"/>
+ <library:element library:name="SF_Utils"/>
+ <library:element library:name="SF_Root"/>
+ <library:element library:name="SF_Array"/>
+ <library:element library:name="SF_Services"/>
+ <library:element library:name="SF_Dictionary"/>
+ <library:element library:name="SF_Session"/>
+ <library:element library:name="SF_FileSystem"/>
+ <library:element library:name="SF_TextStream"/>
+ <library:element library:name="SF_L10N"/>
+ <library:element library:name="SF_Exception"/>
+ <library:element library:name="SF_UI"/>
+ <library:element library:name="SF_Platform"/>
+ <library:element library:name="SF_PythonHelper"/>
+ <library:element library:name="SF_Region"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/SF_Database.xba b/wizards/source/sfdatabases/SF_Database.xba
new file mode 100644
index 000000000..804084aff
--- /dev/null
+++ b/wizards/source/sfdatabases/SF_Database.xba
@@ -0,0 +1,825 @@
+<?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_Database" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDatabases 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_Database
+&apos;&apos;&apos; =========
+&apos;&apos;&apos; Management of databases embedded in or related to Base documents
+&apos;&apos;&apos; Each instance of the current class represents a single database, with essentially its tables, queries and data
+&apos;&apos;&apos;
+&apos;&apos;&apos; The exchanges with the database are done in SQL only.
+&apos;&apos;&apos; To make them more readable, use optionally square brackets to surround table/query/field names
+&apos;&apos;&apos; instead of the (RDBMS-dependent) normal surrounding character (usually, double-quote, single-quote or other).
+&apos;&apos;&apos; SQL statements may be run in direct or indirect mode. In direct mode the statement is transferred literally
+&apos;&apos;&apos; without syntax checking nor review to the database system.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The provided interfaces include simple tables, queries and fields lists, and access to database metadata.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation and usage:
+&apos;&apos;&apos; 1) To access any database at anytime
+&apos;&apos;&apos; Dim myDatabase As Object
+&apos;&apos;&apos; Set myDatabase = CreateScriptService(&quot;SFDatabases.Database&quot;, FileName, , [ReadOnly], [User, [Password]])
+&apos;&apos;&apos; &apos; Args:
+&apos;&apos;&apos; &apos; FileName: the name of the Base file compliant with the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; &apos; RegistrationName: the name of a registered database (mutually exclusive with FileName)
+&apos;&apos;&apos; &apos; ReadOnly: Default = True
+&apos;&apos;&apos; &apos; User, Password: additional connection arguments to the database server
+&apos;&apos;&apos; &apos; ... Run queries, SQL statements, ...
+&apos;&apos;&apos; myDatabase.CloseDatabase()
+&apos;&apos;&apos;
+&apos;&apos;&apos; 2) To access the database related to the current Base document
+&apos;&apos;&apos; Dim myDoc As Object, myDatabase As Object, ui As Object
+&apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
+&apos;&apos;&apos; Set myDoc = ui.OpenBaseDocument(&quot;myDb.odb&quot;)
+&apos;&apos;&apos; Set myDatabase = myDoc.GetDatabase() &apos; user and password are supplied here, if needed
+&apos;&apos;&apos; &apos; ... Run queries, SQL statements, ...
+&apos;&apos;&apos; myDoc.CloseDocument()
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_database.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const DBREADONLYERROR = &quot;DBREADONLYERROR&quot;
+Private Const SQLSYNTAXERROR = &quot;SQLSYNTAXERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be DATABASE
+Private ServiceName As String
+Private _DataSource As Object &apos; com.sun.star.comp.dba.ODatabaseSource
+Private _Connection As Object &apos; com.sun.star.sdbc.XConnection
+Private _URL As String &apos; Text on status bar
+Private _Location As String &apos; File name
+Private _ReadOnly As Boolean
+Private _MetaData As Object &apos; com.sun.star.sdbc.XDatabaseMetaData
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;DATABASE&quot;
+ ServiceName = &quot;SFDatabases.Database&quot;
+ Set _DataSource = Nothing
+ Set _Connection = Nothing
+ _URL = &quot;&quot;
+ _Location = &quot;&quot;
+ _ReadOnly = True
+ Set _MetaData = Nothing
+End Sub &apos; SFDatabases.SF_Database Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDatabases.SF_Database Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDatabases.SF_Database Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Queries() As Variant
+&apos;&apos;&apos; Return the list of available queries in the database
+ Queries = _PropertyGet(&quot;Queries&quot;)
+End Property &apos; SFDatabases.SF_Database.Queries (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Tables() As Variant
+&apos;&apos;&apos; Return the list of available Tables in the database
+ Tables = _PropertyGet(&quot;Tables&quot;)
+End Property &apos; SFDatabases.SF_Database.Tables (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XConnection() As Variant
+&apos;&apos;&apos; Return a com.sun.star.sdbc.XConnection UNO object
+ XConnection = _PropertyGet(&quot;XConnection&quot;)
+End Property &apos; SFDatabases.SF_Database.XConnection (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XMetaData() As Variant
+&apos;&apos;&apos; Return a com.sun.star.sdbc.XDatabaseMetaData UNO object
+ XMetaData = _PropertyGet(&quot;XMetaData&quot;)
+End Property &apos; SFDatabases.SF_Database.XMetaData (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Sub CloseDatabase()
+&apos;&apos;&apos; Close the current database connection
+
+Const cstThisSub = &quot;SFDatabases.Database.CloseDatabase&quot;
+Const cstSubArgs = &quot;&quot;
+
+ On Local Error GoTo 0 &apos; Disable useless error checking
+
+Check:
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ With _Connection
+ If Not IsNull(_Connection) Then
+ If ScriptForge.SF_Session.HasUnoMethod(_Connection, &quot;flush&quot;) Then .flush()
+ .close()
+ .dispose()
+ End If
+ Dispose()
+ End With
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub
+
+REM -----------------------------------------------------------------------------
+Public Function DAvg(Optional ByVal Expression As Variant _
+ , Optional ByVal TableName As Variant _
+ , Optional ByVal Criteria As Variant _
+ ) As Variant
+&apos;&apos;&apos; Compute the aggregate function AVG() on a field or expression belonging to a table
+&apos;&apos;&apos; filtered by a WHERE-clause.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Expression: an SQL expression
+&apos;&apos;&apos; TableName: the name of a table
+&apos;&apos;&apos; Criteria: an optional WHERE clause without the word WHERE
+
+ DAvg = _DFunction(&quot;Avg&quot;, Expression, TableName, Criteria)
+
+End Function &apos; SFDatabases.SF_Database.DAvg
+
+REM -----------------------------------------------------------------------------
+Public Function DCount(Optional ByVal Expression As Variant _
+ , Optional ByVal TableName As Variant _
+ , Optional ByVal Criteria As Variant _
+ ) As Variant
+&apos;&apos;&apos; Compute the aggregate function COUNT() on a field or expression belonging to a table
+&apos;&apos;&apos; filtered by a WHERE-clause.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Expression: an SQL expression
+&apos;&apos;&apos; TableName: the name of a table
+&apos;&apos;&apos; Criteria: an optional WHERE clause without the word WHERE
+
+ DCount = _DFunction(&quot;Count&quot;, Expression, TableName, Criteria)
+
+End Function &apos; SFDatabases.SF_Database.DCount
+
+REM -----------------------------------------------------------------------------
+Public Function DLookup(Optional ByVal Expression As Variant _
+ , Optional ByVal TableName As Variant _
+ , Optional ByVal Criteria As Variant _
+ , Optional ByVal OrderClause As Variant _
+ ) As Variant
+&apos;&apos;&apos; Compute the aggregate function Lookup() on a field or expression belonging to a table
+&apos;&apos;&apos; filtered by a WHERE-clause.
+&apos;&apos;&apos; To order the results, a pvOrderClause may be precised. The 1st record will be retained.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Expression: an SQL expression
+&apos;&apos;&apos; TableName: the name of a table
+&apos;&apos;&apos; Criteria: an optional WHERE clause without the word WHERE
+&apos;&apos;&apos; pvOrderClause: an optional order clause incl. &quot;DESC&quot; if relevant
+
+ DLookup = _DFunction(&quot;Lookup&quot;, Expression, TableName, Criteria, OrderClause)
+
+End Function &apos; SFDatabases.SF_Database.DLookup
+
+REM -----------------------------------------------------------------------------
+Public Function DMax(Optional ByVal Expression As Variant _
+ , Optional ByVal TableName As Variant _
+ , Optional ByVal Criteria As Variant _
+ ) As Variant
+&apos;&apos;&apos; Compute the aggregate function MAX() on a field or expression belonging to a table
+&apos;&apos;&apos; filtered by a WHERE-clause.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Expression: an SQL expression
+&apos;&apos;&apos; TableName: the name of a table
+&apos;&apos;&apos; Criteria: an optional WHERE clause without the word WHERE
+
+ DMax = _DFunction(&quot;Max&quot;, Expression, TableName, Criteria)
+
+End Function &apos; SFDatabases.SF_Database.DMax
+
+REM -----------------------------------------------------------------------------
+Public Function DMin(Optional ByVal Expression As Variant _
+ , Optional ByVal TableName As Variant _
+ , Optional ByVal Criteria As Variant _
+ ) As Variant
+&apos;&apos;&apos; Compute the aggregate function MIN() on a field or expression belonging to a table
+&apos;&apos;&apos; filtered by a WHERE-clause.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Expression: an SQL expression
+&apos;&apos;&apos; TableName: the name of a table
+&apos;&apos;&apos; Criteria: an optional WHERE clause without the word WHERE
+
+ DMin = _DFunction(&quot;Min&quot;, Expression, TableName, Criteria)
+
+End Function &apos; SFDatabases.SF_Database.DMin
+
+REM -----------------------------------------------------------------------------
+Public Function DSum(Optional ByVal Expression As Variant _
+ , Optional ByVal TableName As Variant _
+ , Optional ByVal Criteria As Variant _
+ ) As Variant
+&apos;&apos;&apos; Compute the aggregate function Sum() on a field or expression belonging to a table
+&apos;&apos;&apos; filtered by a WHERE-clause.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Expression: an SQL expression
+&apos;&apos;&apos; TableName: the name of a table
+&apos;&apos;&apos; Criteria: an optional WHERE clause without the word WHERE
+
+ DSum = _DFunction(&quot;Sum&quot;, Expression, TableName, Criteria)
+
+End Function &apos; SFDatabases.SF_Database.DSum
+
+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
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myDatabase.GetProperty(&quot;Queries&quot;)
+
+Const cstThisSub = &quot;SFDatabases.Database.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; SFDatabases.SF_Database.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetRows(Optional ByVal SQLCommand As Variant _
+ , Optional ByVal DirectSQL As Variant _
+ , Optional ByVal Header As Variant _
+ , Optional ByVal MaxRows As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return the content of a table, a query or a SELECT SQL statement as an array
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SQLCommand: a table name, a query name or a SELECT SQL statement
+&apos;&apos;&apos; DirectSQL: when True, no syntax conversion is done by LO. Default = False
+&apos;&apos;&apos; Ignored when SQLCommand is a table or a query name
+&apos;&apos;&apos; Header: When True, a header row is inserted on the top of the array with the column names. Default = False
+&apos;&apos;&apos; MaxRows: The maximum number of returned rows. If absent, all records are returned
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a 2D array(row, column), even if only 1 column and/or 1 record
+&apos;&apos;&apos; an empty array if no records returned
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Variant
+&apos;&apos;&apos; a = myDatabase.GetRows(&quot;SELECT [First Name], [Last Name] FROM [Employees] ORDER BY [Last Name]&quot;, Header := True)
+
+Dim vResult As Variant &apos; Return value
+Dim oResult As Object &apos; com.sun.star.sdbc.XResultSet
+Dim oQuery As Object &apos; com.sun.star.ucb.XContent
+Dim sSql As String &apos; SQL statement
+Dim bDirect &apos; Alias of DirectSQL
+Dim lCols As Long &apos; Number of columns
+Dim lRows As Long &apos; Number of rows
+Dim oColumns As Object
+Dim i As Long
+Const cstThisSub = &quot;SFDatabases.Database.GetRows&quot;
+Const cstSubArgs = &quot;SQLCommand, [DirectSQL=False], [Header=False], [MaxRows=0]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vResult = Array()
+
+Check:
+ If IsMissing(DirectSQL) Or IsEmpty(DirectSQL) Then DirectSQL = False
+ If IsMissing(Header) Or IsEmpty(Header) Then Header = False
+ If IsMissing(MaxRows) Or IsEmpty(MaxRows) Then MaxRows = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ 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
+ If Not ScriptForge.SF_Utils._Validate(Header, &quot;Header&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(MaxRows, &quot;MaxRows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Table, query of SQL ? Prepare resultset
+ If ScriptForge.SF_Array.Contains(Tables, SQLCommand, CaseSensitive := True, SortOrder := &quot;ASC&quot;) Then
+ sSql = &quot;SELECT * FROM [&quot; &amp; SQLCommand &amp; &quot;]&quot;
+ bDirect = True
+ ElseIf ScriptForge.SF_Array.Contains(Queries, SQLCommand, CaseSensitive := True, SortOrder := &quot;ASC&quot;) Then
+ Set oQuery = _Connection.Queries.getByName(SQLCommand)
+ sSql = oQuery.Command
+ bDirect = Not oQuery.EscapeProcessing
+ ElseIf ScriptForge.SF_String.StartsWith(SQLCommand, &quot;SELECT&quot;, CaseSensitive := False) Then
+ sSql = SQLCommand
+ bDirect = DirectSQL
+ Else
+ GoTo Finally
+ End If
+
+ &apos; Execute command
+ Set oResult = _ExecuteSql(sSql, bDirect)
+ If IsNull(oResult) Then GoTo Finally
+
+ With oResult
+ &apos;Initialize output array with header row
+ Set oColumns = oResult.getColumns()
+ lCols = oColumns.Count - 1
+ If Header Then
+ lRows = 0
+ ReDim vResult(0 To lRows, 0 To lCols)
+ For i = 0 To lCols
+ vResult(lRows, i) = oColumns.getByIndex(i).Name
+ Next i
+ If MaxRows &gt; 0 Then MaxRows = MaxRows + 1
+ Else
+ lRows = -1
+ End If
+
+ &apos; Load data
+ .first()
+ Do While Not .isAfterLast() And (MaxRows = 0 Or lRows &lt; MaxRows - 1)
+ lRows = lRows + 1
+ If lRows = 0 Then
+ ReDim vResult(0 To lRows, 0 To lCols)
+ Else
+ ReDim Preserve vResult(0 To lRows, 0 To lCols)
+ End If
+ For i = 0 To lCols
+ vResult(lRows, i) = _GetColumnValue(oResult, i + 1)
+ Next i
+ .next()
+ Loop
+ End With
+
+Finally:
+ GetRows = vResult
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database.GetRows
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Database service as an array
+
+ Methods = Array( _
+ &quot;CloseDatabase&quot; _
+ , &quot;DAvg&quot; _
+ , &quot;DCount&quot; _
+ , &quot;DLookup&quot; _
+ , &quot;DMax&quot; _
+ , &quot;DMin&quot; _
+ , &quot;DSum&quot; _
+ , &quot;GetRows&quot; _
+ , &quot;RunSql&quot; _
+ )
+
+End Function &apos; SFDatabases.SF_Database.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Database class as an array
+
+ Properties = Array( _
+ &quot;Queries&quot; _
+ , &quot;Tables&quot; _
+ , &quot;XConnection&quot; _
+ , &quot;XMetaData&quot; _
+ )
+
+End Function &apos; SFDatabases.SF_Database.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function RunSql(Optional ByVal SQLCommand As Variant _
+ , Optional ByVal DirectSQL As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Execute an action query (table creation, record insertion, ...) or SQL statement on the current database
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SQLCommand: a query name or an SQL statement
+&apos;&apos;&apos; DirectSQL: when True, no syntax conversion is done by LO. Default = False
+&apos;&apos;&apos; Ignored when SQLCommand is a query name
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The method is not applicable on a read-only database
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myDatabase.RunSql(&quot;INSERT INTO [EMPLOYEES] VALUES(25, &apos;SMITH&apos;, &apos;John&apos;)&quot;, DirectSQL := True)
+
+Dim bResult As Boolean &apos; Return value
+Dim oStatement As Object &apos; com.sun.star.sdbc.XStatement
+Dim oQuery As Object &apos; com.sun.star.ucb.XContent
+Dim sSql As String &apos; SQL statement
+Dim bDirect &apos; Alias of DirectSQL
+Const cstQuery = 2, cstSql = 3
+Const cstThisSub = &quot;SFDatabases.Database.RunSql&quot;
+Const cstSubArgs = &quot;SQLCommand, [DirectSQL=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bResult = False
+
+Check:
+ If IsMissing(DirectSQL) Or IsEmpty(DirectSQL) Then DirectSQL = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ 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
+ If _ReadOnly Then GoTo Catch_ReadOnly
+
+Try:
+ &apos; Query of SQL ?
+ If ScriptForge.SF_Array.Contains(Queries, SQLCommand, CaseSensitive := True, SortOrder := &quot;ASC&quot;) Then
+ Set oQuery = _Connection.Queries.getByName(SQLCommand)
+ sSql = oQuery.Command
+ bDirect = Not oQuery.EscapeProcessing
+ ElseIf Not ScriptForge.SF_String.StartsWith(SQLCommand, &quot;SELECT&quot;, CaseSensitive := False) Then
+ sSql = SQLCommand
+ bDirect = DirectSQL
+ Else
+ GoTo Finally
+ End If
+
+ &apos; Execute command
+ bResult = _ExecuteSql(sSql, bDirect)
+
+Finally:
+ RunSql = bResult
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+Catch_ReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database.RunSql
+
+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;SFDatabases.Database.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; SFDatabases.SF_Database.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------------------------------------------------
+Private Function _DFunction(ByVal psFunction As String _
+ , Optional ByVal pvExpression As Variant _
+ , Optional ByVal pvTableName As Variant _
+ , Optional ByVal pvCriteria As Variant _
+ , Optional ByVal pvOrderClause As Variant _
+ ) As Variant
+&apos;&apos;&apos; Build and execute a SQL statement computing the aggregate function psFunction
+&apos;&apos;&apos; on a field or expression pvExpression belonging to a table pvTableName
+&apos;&apos;&apos; filtered by a WHERE-clause pvCriteria.
+&apos;&apos;&apos; To order the results, a pvOrderClause may be precised.
+&apos;&apos;&apos; Only the 1st record will be retained anyway.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psFunction an optional aggregate function: SUM, COUNT, AVG, LOOKUP
+&apos;&apos;&apos; pvExpression: an SQL expression
+&apos;&apos;&apos; pvTableName: the name of a table, NOT surrounded with quoting char
+&apos;&apos;&apos; pvCriteria: an optional WHERE clause without the word WHERE
+&apos;&apos;&apos; pvOrderClause: an optional order clause incl. &quot;DESC&quot; if relevant
+&apos;&apos;&apos; (meaningful only for LOOKUP)
+
+Dim vResult As Variant &apos; Return value
+Dim oResult As Object &apos; com.sun.star.sdbc.XResultSet
+Dim sSql As String &apos; SQL statement.
+Dim sExpr As String &apos; For inclusion of aggregate function
+Dim sTarget as String &apos; Alias of pvExpression
+Dim sWhere As String &apos; Alias of pvCriteria
+Dim sOrderBy As String &apos; Alias of pvOrderClause
+Dim sLimit As String &apos; TOP 1 clause
+Dim sProductName As String &apos; RDBMS as a string
+Const cstAliasField = &quot;[&quot; &amp; &quot;TMP_ALIAS_ANY_FIELD&quot; &amp; &quot;]&quot; &apos; Alias field in SQL expression
+Dim cstThisSub As String : cstThisSub = &quot;SFDatabases.SF_Database.D&quot; &amp; psFunction
+Const cstSubArgs = &quot;Expression, TableName, [Criteria=&quot;&quot;&quot;&quot;], [OrderClause=&quot;&quot;&quot;&quot;]&quot;
+Const cstLookup = &quot;Lookup&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vResult = Null
+
+Check:
+ If IsMissing(pvCriteria) Or IsEmpty(pvCriteria) Then pvCriteria = &quot;&quot;
+ If IsMissing(pvOrderClause) Or IsEmpty(pvOrderClause) Then pvOrderClause = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(pvExpression, &quot;Expression&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvTableName, &quot;TableName&quot;, V_STRING, Tables) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvCriteria, &quot;Criteria&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvOrderClause, &quot;OrderClause&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If pvCriteria &lt;&gt; &quot;&quot; Then sWhere = &quot; WHERE &quot; &amp; pvCriteria Else sWhere = &quot;&quot;
+ If pvOrderClause &lt;&gt; &quot;&quot; Then sOrderBy = &quot; ORDER BY &quot; &amp; pvOrderClause Else sOrderBy = &quot;&quot;
+ sLimit = &quot;&quot;
+
+ pvTableName = &quot;[&quot; &amp; pvTableName &amp; &quot;]&quot;
+
+ sProductName = UCase(_MetaData.getDatabaseProductName())
+
+ Select Case sProductName
+ Case &quot;MYSQL&quot;, &quot;SQLITE&quot;
+ If psFunction = cstLookup Then
+ sTarget = pvExpression
+ sLimit = &quot; LIMIT 1&quot;
+ Else
+ sTarget = UCase(psFunction) &amp; &quot;(&quot; &amp; pvExpression &amp; &quot;)&quot;
+ End If
+ sSql = &quot;SELECT &quot; &amp; sTarget &amp; &quot; AS &quot; &amp; cstAliasField &amp; &quot; FROM &quot; &amp; psTableName &amp; sWhere &amp; sOrderBy &amp; sLimit
+ Case &quot;FIREBIRD (ENGINE12)&quot;
+ If psFunction = cstLookup Then sTarget = &quot;FIRST 1 &quot; &amp; pvExpression Else sTarget = UCase(psFunction) &amp; &quot;(&quot; &amp; pvExpression &amp; &quot;)&quot;
+ sSql = &quot;SELECT &quot; &amp; sTarget &amp; &quot; AS &quot; &amp; cstAliasField &amp; &quot; FROM &quot; &amp; pvTableName &amp; sWhere &amp; sOrderBy
+ Case Else &apos; Standard syntax - Includes HSQLDB
+ If psFunction = cstLookup Then sTarget = &quot;TOP 1 &quot; &amp; pvExpression Else sTarget = UCase(psFunction) &amp; &quot;(&quot; &amp; pvExpression &amp; &quot;)&quot;
+ sSql = &quot;SELECT &quot; &amp; sTarget &amp; &quot; AS &quot; &amp; cstAliasField &amp; &quot; FROM &quot; &amp; pvTableName &amp; sWhere &amp; sOrderBy
+ End Select
+
+ &apos; Execute the SQL statement and retain the first column of the first record
+ Set oResult = _ExecuteSql(sSql, True)
+ If Not IsNull(oResult) And Not IsEmpty(oResult) Then
+ If Not oResult.first() Then Goto Finally
+ If oResult.isAfterLast() Then GoTo Finally
+ vResult = _GetColumnValue(oResult, 1, True) &apos; Force return of binary field
+ End If
+ Set oResult = Nothing
+
+Finally:
+ _DFunction = vResult
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database._DFunction
+
+REM -----------------------------------------------------------------------------
+Private Function _ExecuteSql(ByVal psSql As String _
+ , ByVal pbDirect As Boolean _
+ ) As Variant
+&apos;&apos;&apos; Return a read-only Resultset based on a SELECT SQL statement or execute the given action SQL (INSERT, CREATE TABLE, ...)
+&apos;&apos;&apos; The method raises a fatal error when the SQL statement cannot be interpreted
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psSql : the SQL statement. Square brackets are replaced by the correct field surrounding character
+&apos;&apos;&apos; pbDirect: when True, no syntax conversion is done by LO. Default = False
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; SQLSYNTAXERROR The given SQL statement is incorrect
+
+Dim vResult As Variant &apos; Return value - com.sun.star.sdbc.XResultSet or Boolean
+Dim oStatement As Object &apos; com.sun.star.sdbc.XStatement
+Dim sSql As String &apos; Alias of psSql
+Dim bSelect As Boolean &apos; True when SELECT statement
+Dim bErrorHandler As Boolean &apos; Can be set off to ease debugging of complex SQL statements
+
+ Set vResult = Nothing
+ bErrorHandler = ScriptForge.SF_Utils._ErrorHandling()
+ If bErrorHandler Then On Local Error GoTo Catch
+
+Try:
+ sSql = _ReplaceSquareBrackets(psSql)
+ bSelect = ScriptForge.SF_String.StartsWith(sSql, &quot;SELECT&quot;, CaseSensitive := False)
+
+ Set oStatement = _Connection.createStatement()
+ With oStatement
+ If bSelect Then
+ .ResultSetType = com.sun.star.sdbc.ResultSetType.SCROLL_INSENSITIVE
+ .ResultSetConcurrency = com.sun.star.sdbc.ResultSetConcurrency.READ_ONLY
+ End If
+ .EscapeProcessing = Not pbDirect
+
+ &apos; Setup the result set
+ If bErrorHandler Then On Local Error GoTo Catch_Sql
+ If bSelect Then Set vResult = .executeQuery(sSql) Else vResult = .execute(sSql)
+ End With
+
+Finally:
+ _ExecuteSql = vResult
+ Set oStatement = Nothing
+ Exit Function
+Catch_Sql:
+ ScriptForge.SF_Exception.RaiseFatal(SQLSYNTAXERROR, sSql)
+ GoTo Finally
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database._ExecuteSql
+
+REM -----------------------------------------------------------------------------
+Private Function _GetColumnValue(ByRef poResultSet As Object _
+ , ByVal plColIndex As Long _
+ , Optional ByVal pbReturnBinary As Boolean _
+ ) As Variant
+&apos;&apos;&apos; Get the data stored in the current record of a result set in a given column
+&apos;&apos;&apos; The type of the column is found in the resultset&apos;s metadata
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poResultSet: com.sun.star.sdbc.XResultSet
+&apos;&apos;&apos; plColIndex: the index of the column to extract the value from
+&apos;&apos;&apos; pbReturnBinary: when True, the method returns the content of a binary field,
+&apos;&apos;&apos; as long as its length does not exceed a maximum length.
+&apos;&apos;&apos; Default = False: binary fields are not returned, only their length
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The Variant value found in the column
+&apos;&apos;&apos; Dates and times are returned as Basic dates
+&apos;&apos;&apos; Null values are returned as Null
+&apos;&apos;&apos; Errors or strange data types are returned as Null as well
+
+Dim vValue As Variant &apos; Return value
+Dim lType As Long &apos; SQL column type: com.sun.star.sdbc.DataType
+Dim vDateTime As Variant &apos; com.sun.star.util.DateTime
+Dim oStream As Object &apos; Long character or binary streams
+Dim bNullable As Boolean &apos; The field is defined as accepting Null values
+Dim lSize As Long &apos; Binary field length
+
+Const cstMaxBinlength = 2 * 65535
+
+ On Local Error Goto 0 &apos; Disable error handler
+ vValue = Null &apos; Default value if error
+ If IsMissing(pbReturnBinary) Then pbReturnBinary = False
+
+ With com.sun.star.sdbc.DataType
+ lType = poResultSet.MetaData.getColumnType(plColIndex)
+ bNullable = ( poResultSet.MetaData.IsNullable(plColIndex) = com.sun.star.sdbc.ColumnValue.NULLABLE )
+
+ Select Case lType
+ Case .ARRAY : vValue = poResultSet.getArray(plColIndex)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ Set oStream = poResultSet.getBinaryStream(plColIndex)
+ If bNullable Then
+ If Not poResultSet.wasNull() Then
+ If Not ScriptForge.SF_Session.HasUNOMethod(oStream, &quot;getLength&quot;) Then &apos; When no recordset
+ lSize = cstMaxBinLength
+ Else
+ lSize = CLng(oValue.getLength())
+ End If
+ If lSize &lt;= cstMaxBinLength And pbReturnBinary Then
+ vValue = Array()
+ oValue.readBytes(vValue, lSize)
+ Else &apos; Return length of field, not content
+ vValue = lSize
+ End If
+ End If
+ End If
+ oValue.closeInput()
+ Case .BIT, .BOOLEAN : vValue = poResultSet.getBoolean(plColIndex)
+ Case .DATE
+ vDateTime = poResultSet.getDate(plColIndex)
+ If Not poResultSet.wasNull() Then vValue = DateSerial(CInt(vDateTime.Year), CInt(vDateTime.Month), CInt(vDateTime.Day))
+ Case .DISTINCT, .OBJECT, .OTHER, .STRUCT
+ vValue = Null
+ Case .DOUBLE, .REAL : vValue = poResultSet.getDouble(plColIndex)
+ Case .FLOAT : vValue = poResultSet.getFloat(plColIndex)
+ Case .INTEGER, .SMALLINT : vValue = poResultSet.getInt(plColIndex)
+ Case .BIGINT : vValue = CLng(poResultSet.getLong(plColIndex))
+ Case .DECIMAL, .NUMERIC : vValue = poResultSet.getDouble(plColIndex)
+ Case .SQLNULL : vValue = poResultSet.getNull(plColIndex)
+ Case .OBJECT, .OTHER, .STRUCT : vValue = Null
+ Case .REF : vValue = poResultSet.getRef(plColIndex)
+ Case .TINYINT : vValue = poResultSet.getShort(plColIndex)
+ Case .CHAR, .VARCHAR : vValue = poResultSet.getString(plColIndex)
+ Case .LONGVARCHAR, .CLOB
+ If bNullable Then
+ If Not poResultSet.wasNull() Then vValue = poResultSet.getString(plColIndex)
+ Else
+ vValue = &quot;&quot;
+ End If
+ Case .TIME
+ vDateTime = poResultSet.getTime(plColIndex)
+ If Not poResultSet.wasNull() Then vValue = TimeSerial(vDateTime.Hours, vDateTime.Minutes, vDateTime.Seconds)&apos;, vDateTime.HundredthSeconds)
+ Case .TIMESTAMP
+ vDateTime = poResultSet.getTimeStamp(plColIndex)
+ If Not poResultSet.wasNull() Then vValue = DateSerial(CInt(vDateTime.Year), CInt(vDateTime.Month), CInt(vDateTime.Day)) _
+ + TimeSerial(vDateTime.Hours, vDateTime.Minutes, vDateTime.Seconds)&apos;, vDateTime.HundredthSeconds)
+ Case Else
+ vValue = poResultSet.getString(plColIndex) &apos;GIVE STRING A TRY
+ If IsNumeric(vValue) Then vValue = Val(vValue) &apos;Required when type = &quot;&quot;, sometimes numeric fields are returned as strings (query/MSAccess)
+ End Select
+ If bNullable Then
+ If poResultSet.wasNull() Then vValue = Null
+ End If
+ End With
+
+ _GetColumnValue = vValue
+
+End Function &apos; SFDatabases.SF_Database.GetColumnValue
+
+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 cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDatabases.Database.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case psProperty
+ Case &quot;Queries&quot;
+ If Not IsNull(_Connection) Then _PropertyGet = _Connection.Queries.getElementNames() Else _PropertyGet = Array()
+ Case &quot;Tables&quot;
+ If Not IsNull(_Connection) Then _PropertyGet = _Connection.Tables.getElementNames() Else _PropertyGet = Array()
+ Case &quot;XConnection&quot;
+ Set _PropertyGet = _Connection
+ Case &quot;XMetaData&quot;
+ Set _PropertyGet = _MetaData
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _ReplaceSquareBrackets(ByVal psSql As String) As String
+&apos;&apos;&apos; Returns the input SQL command after replacement of square brackets by the table/field names quoting character
+
+Dim sSql As String &apos; Return value
+Dim sQuote As String &apos; RDBMS specific table/field surrounding character
+Dim sConstQuote As String &apos; Delimiter for string constants in SQL - usually the single quote
+Const cstDouble = &quot;&quot;&quot;&quot; : Const cstSingle = &quot;&apos;&quot;
+
+Try:
+ sQuote = _MetaData.IdentifierQuoteString
+ sConstQuote = Iif(sQuote = cstSingle, cstDouble, cstSingle)
+
+ &apos; Replace the square brackets
+ sSql = Join(ScriptForge.SF_String.SplitNotQuoted(psSql, &quot;[&quot;, , sConstQuote), sQuote)
+ sSql = Join(ScriptForge.SF_String.SplitNotQuoted(sSql, &quot;]&quot;, , sConstQuote), sQuote)
+
+Finally:
+ _ReplaceSquareBrackets = sSql
+ Exit Function
+End Function &apos; SFDatabases.SF_Database._ReplaceSquareBrackets
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Database instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[DATABASE]: Location (Statusbar)&quot;
+
+ _Repr = &quot;[DATABASE]: &quot; &amp; _Location &amp; &quot; (&quot; &amp; _URL &amp; &quot;)&quot;
+
+End Function &apos; SFDatabases.SF_Database._Repr
+
+REM ============================================ END OF SFDATABASES.SF_DATABASE
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/SF_Register.xba b/wizards/source/sfdatabases/SF_Register.xba
new file mode 100644
index 000000000..c9b3f03d7
--- /dev/null
+++ b/wizards/source/sfdatabases/SF_Register.xba
@@ -0,0 +1,195 @@
+<?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 SFDatabases 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
+
+Private Const BASEDOCUMENTOPENERROR = &quot;BASEDOCUMENTOPENERROR&quot;
+
+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;Database&quot;, &quot;SFDatabases.SF_Register._NewDatabase&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;DatabaseFromDocument&quot;, &quot;SFDatabases.SF_Register._NewDatabaseFromSource&quot;)
+ End With
+
+End Sub &apos; SFDatabases.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _NewDatabase(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the SF_Database class
+&apos; Args:
+&apos;&apos;&apos; FileName : the name of the file (compliant with the SF_FileSystem.FileNaming notation)
+&apos;&apos;&apos; RegistrationName: mutually exclusive with FileName. Used when database is registered
+&apos;&apos;&apos; ReadOnly : (boolean). Default = True
+&apos;&apos;&apos; User : connection parameters
+&apos;&apos;&apos; Password
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The instance or Nothing
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; BASEDOCUMENTOPENERROR The database file could not be opened or connected
+
+Dim oDatabase As Object &apos; Return value
+Dim vFileName As Variant &apos; alias of pvArgs(0)
+Dim vRegistration As Variant &apos; Alias of pvArgs(1)
+Dim vReadOnly As Variant &apos; Alias of pvArgs(2)
+Dim vUser As Variant &apos; Alias of pvArgs(3)
+Dim vPassword As Variant &apos; Alias of pvArgs(4)
+Dim oDBContext As Object &apos; com.sun.star.sdb.DatabaseContext
+Const cstService = &quot;SFDatabases.Database&quot;
+Const cstGlobal = &quot;GlobalScope&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
+ If UBound(pvArgs) &gt;= 0 Then vFileName = pvArgs(0) Else vFileName = &quot;&quot;
+ If IsEmpty(vFileName) Then vFileName = &quot;&quot;
+ If UBound(pvArgs) &gt;= 1 Then vRegistration = pvArgs(1) Else vRegistration = &quot;&quot;
+ If IsEmpty(vRegistration) Then vRegistration = &quot;&quot;
+ If UBound(pvArgs) &gt;= 2 Then vReadOnly = pvArgs(2) Else vReadOnly = True
+ If IsEmpty(vReadOnly) Then vReadOnly = True
+ If UBound(pvArgs) &gt;= 3 Then vUser = pvArgs(3) Else vUser = &quot;&quot;
+ If IsEmpty(vUser) Then vUser = &quot;&quot;
+ If UBound(pvArgs) &gt;= 4 Then vPassword = pvArgs(4) Else vPassword = &quot;&quot;
+ If IsEmpty(vPassword) Then vPassword = &quot;&quot;
+ If Not ScriptForge.SF_Utils._Validate(vFileName, &quot;FileName&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vRegistration, &quot;RegistrationName&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vReadOnly, &quot;ReadOnly&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vUser, &quot;User&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vPassword, &quot;Password&quot;, V_STRING) Then GoTo Finally
+ Set oDatabase = Nothing
+
+ &apos; Check the existence of FileName
+ With ScriptForge
+ Set oDBContext = .SF_Utils._GetUNOService(&quot;DatabaseContext&quot;)
+ If Len(vFileName) = 0 Then &apos; FileName has precedence over RegistrationName
+ If Len(vRegistration) = 0 Then GoTo CatchError
+ If Not oDBContext.hasRegisteredDatabase(vRegistration) Then GoTo CatchError
+ vFileName = .SF_FileSystem._ConvertFromUrl(oDBContext.getDatabaseLocation(vRegistration))
+ End If
+ If Not .SF_FileSystem.FileExists(vFileName) Then GoTo CatchError
+ End With
+
+Try:
+ &apos; Create the database Basic object and initialize attributes
+ Set oDatabase = New SF_Database
+ With oDatabase
+ Set .[Me] = oDatabase
+ ._Location = ConvertToUrl(vFileName)
+ Set ._DataSource = oDBContext.getByName(._Location)
+ Set ._Connection = ._DataSource.getConnection(vUser, vPassword)
+ ._ReadOnly = vReadOnly
+ Set ._MetaData = ._Connection.MetaData
+ ._URL = ._MetaData.URL
+ End With
+
+Finally:
+ Set _NewDatabase = oDatabase
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ ScriptForge.SF_Exception.RaiseFatal(BASEDOCUMENTOPENERROR, &quot;FileName&quot;, vFileName, &quot;RegistrationName&quot;, vRegistration)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Register._NewDatabase
+
+REM -----------------------------------------------------------------------------
+Public Function _NewDatabaseFromSource(Optional ByVal pvArgs As Variant) As Object
+&apos; ByRef poDataSource As Object _
+&apos; , ByVal psUser As String _
+&apos; , ByVal psPassword As String _
+&apos; ) As Object
+&apos;&apos;&apos; Create a new instance of the SF_Database class from the given datasource
+&apos;&apos;&apos; established in the SFDocuments.Base service
+&apos;&apos;&apos; THIS SERVICE MUST NOT BE CALLED FROM A USER SCRIPT
+&apos; Args:
+&apos;&apos;&apos; DataSource: com.sun.star.sdbc.XDataSource
+&apos;&apos;&apos; User, Password : connection parameters
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The instance or Nothing
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; managed in the calling routines when Nothing is returned
+
+Dim oDatabase As Object &apos; Return value
+Dim oConnection As Object &apos; com.sun.star.sdbc.XConnection
+Dim oDataSource As Object &apos; Alias of pvArgs(0)
+Dim sUser As String &apos; Alias of pvARgs(1)
+Dim sPassword As String &apos; Alias of pvARgs(2)
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oDatabase = Nothing
+
+Try:
+ &apos; Get arguments
+ Set oDataSource = pvArgs(0)
+ sUser = pvArgs(1)
+ sPassword = pvArgs(2)
+
+ &apos; Setup the connection
+ If oDataSource.IsPasswordRequired Then
+ Set oConnection = oDataSource.getConnection(sUser, sPassword)
+ Else
+ Set oConnection = oDataSource.getConnection(&quot;&quot;, &quot;&quot;)
+ End If
+
+ &apos; Create the database Basic object and initialize attributes
+ If Not IsNull(oConnection) Then
+ Set oDatabase = New SF_Database
+ With oDatabase
+ Set .[Me] = oDatabase
+ ._Location = &quot;&quot;
+ Set ._DataSource = oDataSource
+ Set ._Connection = oConnection
+ ._ReadOnly = oConnection.isReadOnly()
+ Set ._MetaData = oConnection.MetaData
+ ._URL = ._MetaData.URL
+ End With
+ End If
+
+Finally:
+ Set _NewDatabaseFromSource = oDatabase
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Register._NewDatabaseFromSource
+
+REM ============================================== END OF SFDATABASES.SF_REGISTER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/__License.xba b/wizards/source/sfdatabases/__License.xba
new file mode 100644
index 000000000..3b0c64d04
--- /dev/null
+++ b/wizards/source/sfdatabases/__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-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDatabases 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/sfdatabases/dialog.xlb b/wizards/source/sfdatabases/dialog.xlb
new file mode 100644
index 000000000..8b62d721a
--- /dev/null
+++ b/wizards/source/sfdatabases/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="SFDatabases" library:readonly="false" library:passwordprotected="false"/> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/script.xlb b/wizards/source/sfdatabases/script.xlb
new file mode 100644
index 000000000..6cea80d2a
--- /dev/null
+++ b/wizards/source/sfdatabases/script.xlb
@@ -0,0 +1,7 @@
+<?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="SFDatabases" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="SF_Register"/>
+ <library:element library:name="__License"/>
+ <library:element library:name="SF_Database"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/sfdialogs/SF_Dialog.xba b/wizards/source/sfdialogs/SF_Dialog.xba
new file mode 100644
index 000000000..da2afcb4a
--- /dev/null
+++ b/wizards/source/sfdialogs/SF_Dialog.xba
@@ -0,0 +1,1111 @@
+<?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_Dialog" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDialogs 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_Dialog
+&apos;&apos;&apos; =========
+&apos;&apos;&apos; Management of dialogs defined with the Basic IDE
+&apos;&apos;&apos; Each instance of the current class represents a single dialog box displayed to the user
+&apos;&apos;&apos;
+&apos;&apos;&apos; A dialog box can be displayed in modal or in non-modal modes
+&apos;&apos;&apos; In modal mode, the box is displayed and the execution of the macro process is suspended
+&apos;&apos;&apos; until one of the OK or Cancel buttons is pressed. In the meantime, other user actions
+&apos;&apos;&apos; executed on the box can trigger specific actions.
+&apos;&apos;&apos; In non-modal mode, the dialog box is &quot;floating&quot; on the user desktop and the execution
+&apos;&apos;&apos; of the macro process continues normally
+&apos;&apos;&apos; A dialog box disappears from memory after its explicit termination.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation and usage:
+&apos;&apos;&apos; Dim myDialog As Object, lButton As Long
+&apos;&apos;&apos; Set myDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, Container, Library, DialogName)
+&apos;&apos;&apos; &apos; Args:
+&apos;&apos;&apos; &apos; Container: &quot;GlobalScope&quot; for preinstalled libraries
+&apos;&apos;&apos; &apos; A window name (see its definition in the ScriptForge.UI service)
+&apos;&apos;&apos; &apos; &quot;&quot; (default) = the current document
+&apos;&apos;&apos; &apos; Library: The (case-sensitive) name of a library contained in the container
+&apos;&apos;&apos; &apos; Default = &quot;Standard&quot;
+&apos;&apos;&apos; &apos; DialogName: a case-sensitive string designating the dialog where it is about
+&apos;&apos;&apos; &apos; ... Initialize controls ...
+&apos;&apos;&apos; lButton = myDialog.Execute() &apos; Default mode = Modal
+&apos;&apos;&apos; If lButton = myDialog.OKBUTTON Then
+&apos;&apos;&apos; &apos; ... Process controls and do what is needed
+&apos;&apos;&apos; End If
+&apos;&apos;&apos; myDialog.Terminate()
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_dialog.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const DIALOGDEADERROR = &quot;DIALOGDEADERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be DIALOG
+Private ServiceName As String
+
+&apos; Dialog location
+Private _Container As String
+Private _Library As String
+Private _Name As String
+Private _CacheIndex As Long &apos; Index in cache storage
+
+&apos; Dialog UNO references
+Private _DialogProvider As Object &apos; com.sun.star.io.XInputStreamProvider
+Private _DialogControl As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
+Private _DialogModel As Object &apos; com.sun.star.awt.XControlModel - stardiv.Toolkit.UnoControlDialogModel
+
+&apos; Dialog attributes
+Private _Displayed As Boolean &apos; True after Execute()
+Private _Modal As Boolean &apos; Set by Execute()
+
+&apos; Dialog position and dimensions
+Private _Left As Long
+Private _Top As Long
+Private _Width As Long
+Private _Height As Long
+
+&apos; Persistent storage for controls
+Private _ControlCache As Variant &apos; Array of control objects sorted like ElementNames of the Dialog model
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const OKBUTTON = 1
+Private Const CANCELBUTTON = 0
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;DIALOG&quot;
+ ServiceName = &quot;SFDialogs.Dialog&quot;
+ _Container = &quot;&quot;
+ _Library = &quot;&quot;
+ _Name = &quot;&quot;
+ _CacheIndex = -1
+ Set _DialogProvider = Nothing
+ Set _DialogControl = Nothing
+ Set _DialogModel = Nothing
+ _Displayed = False
+ _Modal = True
+ _Left = -1
+ _Top = -1
+ _Width = -1
+ _Height = -1
+ _ControlCache = Array()
+End Sub &apos; SFDialogs.SF_Dialog Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDialogs.SF_Dialog Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ If _CacheIndex &gt;= 0 Then Terminate()
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDialogs.SF_Dialog Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Caption() As Variant
+&apos;&apos;&apos; The Caption property refers to the title of the dialog
+ Caption = _PropertyGet(&quot;Caption&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Caption (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Caption(Optional ByVal pvCaption As Variant)
+&apos;&apos;&apos; Set the updatable property Caption
+ _PropertySet(&quot;Caption&quot;, pvCaption)
+End Property &apos; SFDialogs.SF_Dialog.Caption (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Height() As Variant
+&apos;&apos;&apos; The Height property refers to the height of the dialog box
+ Height = _PropertyGet(&quot;Height&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Height (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Height(Optional ByVal pvHeight As Variant)
+&apos;&apos;&apos; Set the updatable property Height
+ _PropertySet(&quot;Height&quot;, pvHeight)
+End Property &apos; SFDialogs.SF_Dialog.Height (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Modal() As Boolean
+&apos;&apos;&apos; The Modal property specifies if the dialog box has been executed in modal mode
+ Modal = _PropertyGet(&quot;Modal&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Modal (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Name() As String
+&apos;&apos;&apos; Return the name of the actual dialog
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Name
+
+REM -----------------------------------------------------------------------------
+Property Get OnFocusGained() As Variant
+&apos;&apos;&apos; Get the script associated with the OnFocusGained event
+ OnFocusGained = _PropertyGet(&quot;OnFocusGained&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnFocusGained (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnFocusLost() As Variant
+&apos;&apos;&apos; Get the script associated with the OnFocusLost event
+ OnFocusLost = _PropertyGet(&quot;OnFocusLost&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnFocusLost (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnKeyPressed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnKeyPressed event
+ OnKeyPressed = _PropertyGet(&quot;OnKeyPressed&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnKeyPressed (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnKeyReleased() As Variant
+&apos;&apos;&apos; Get the script associated with the OnKeyReleased event
+ OnKeyReleased = _PropertyGet(&quot;OnKeyReleased&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnKeyReleased (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseDragged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseDragged event
+ OnMouseDragged = _PropertyGet(&quot;OnMouseDragged&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnMouseDragged (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseEntered() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseEntered event
+ OnMouseEntered = _PropertyGet(&quot;OnMouseEntered&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnMouseEntered (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseExited() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseExited event
+ OnMouseExited = _PropertyGet(&quot;OnMouseExited&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnMouseExited (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseMoved() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseMoved event
+ OnMouseMoved = _PropertyGet(&quot;OnMouseMoved&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnMouseMoved (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMousePressed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMousePressed event
+ OnMousePressed = _PropertyGet(&quot;OnMousePressed&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnMousePressed (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseReleased() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseReleased event
+ OnMouseReleased = _PropertyGet(&quot;OnMouseReleased&quot;)
+End Property &apos; SFDialogs.SF_Dialog.OnMouseReleased (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Page() As Variant
+&apos;&apos;&apos; A dialog may have several pages that can be traversed by the user step by step. The Page property of the Dialog object defines which page of the dialog is active.
+&apos;&apos;&apos; The Page property of a control defines the page of the dialog on which the control is visible.
+&apos;&apos;&apos; For example, if a control has a page value of 1, it is only visible on page 1 of the dialog.
+&apos;&apos;&apos; If the page value of the dialog is increased from 1 to 2, then all controls with a page value of 1 disappear and all controls with a page value of 2 become visible.
+ Page = _PropertyGet(&quot;Page&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Page (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Page(Optional ByVal pvPage As Variant)
+&apos;&apos;&apos; Set the updatable property Page
+ _PropertySet(&quot;Page&quot;, pvPage)
+End Property &apos; SFDialogs.SF_Dialog.Page (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Visible() As Variant
+&apos;&apos;&apos; The Visible property is False before the Execute() statement
+ Visible = _PropertyGet(&quot;Visible&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Visible (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Visible(Optional ByVal pvVisible As Variant)
+&apos;&apos;&apos; Set the updatable property Visible
+ _PropertySet(&quot;Visible&quot;, pvVisible)
+End Property &apos; SFDialogs.SF_Dialog.Visible (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Width() As Variant
+&apos;&apos;&apos; The Width property refers to the Width of the dialog box
+ Width = _PropertyGet(&quot;Width&quot;)
+End Property &apos; SFDialogs.SF_Dialog.Width (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Width(Optional ByVal pvWidth As Variant)
+&apos;&apos;&apos; Set the updatable property Width
+ _PropertySet(&quot;Width&quot;, pvWidth)
+End Property &apos; SFDialogs.SF_Dialog.Width (let)
+
+REM -----------------------------------------------------------------------------
+Property Get XDialogModel() As Object
+&apos;&apos;&apos; The XDialogModel property returns the model UNO object of the dialog
+ XDialogModel = _PropertyGet(&quot;XDialogModel&quot;)
+End Property &apos; SFDialogs.SF_Dialog.XDialogModel (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XDialogView() As Object
+&apos;&apos;&apos; The XDialogView property returns the view UNO object of the dialog
+ XDialogView = _PropertyGet(&quot;XDialogView&quot;)
+End Property &apos; SFDialogs.SF_Dialog.XDialogView (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate() As Boolean
+&apos;&apos;&apos; Set the focus on the current dialog instance
+&apos;&apos;&apos; Probably called from after an event occurrence or to focus on a non-modal dialog
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if focusing is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDlg As Object
+&apos;&apos;&apos; Set oDlg = CreateScriptService(,, &quot;myDialog&quot;) &apos; Dialog stored in current document&apos;s standard library
+&apos;&apos;&apos; oDlg.Activate()
+
+Dim bActivate As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDialogs.Dialog.Activate&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bActivate = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ If Not IsNull(_DialogControl) Then
+ _DialogControl.setFocus()
+ bActivate = True
+ End If
+
+Finally:
+ Activate = bActivate
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.Activate
+
+REM -----------------------------------------------------------------------------
+Public Function Center(Optional ByRef Parent As Variant) As Boolean
+&apos;&apos;&apos; Center the actual dialog instance in the middle of a parent window
+&apos;&apos;&apos; Without arguments, the method centers the dialog in the middle of the current window
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Parent: an object, either
+&apos;&apos;&apos; - a ScriptForge dialog object
+&apos;&apos;&apos; - a ScriptForge document (Calc, Base, ...) object
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Sub TriggerEvent(oEvent As Object)
+&apos;&apos;&apos; Dim oDialog1 As Object, oDialog2 As Object, lExec As Long
+&apos;&apos;&apos; Set oDialog1 = CreateScriptService(&quot;DialogEvent&quot;, oEvent) &apos; The dialog having caused the event
+&apos;&apos;&apos; Set oDialog2 = CreateScriptService(&quot;Dialog&quot;, ...) &apos; Open a second dialog
+&apos;&apos;&apos; oDialog2.Center(oDialog1)
+&apos;&apos;&apos; lExec = oDialog2.Execute()
+&apos;&apos;&apos; Select Case lExec
+&apos;&apos;&apos; ...
+&apos;&apos;&apos; End Sub
+
+Dim bCenter As Boolean &apos; Return value
+Dim oUi As Object &apos; ScriptForge.SF_UI
+Dim oObjDesc As Object &apos; _ObjectDescriptor type
+Dim sObjectType As String &apos; Can be uno or sf object type
+Dim oParent As Object &apos; UNO alias of parent
+Dim oParentPosSize As Object &apos; Parent com.sun.star.awt.Rectangle
+Dim lParentX As Long &apos; X position of parent dialog
+Dim lParentY As Long &apos; Y position of parent dialog
+Dim oPosSize As Object &apos; Dialog com.sun.star.awt.Rectangle
+Const cstThisSub = &quot;SFDialogs.Dialog.Center&quot;
+Const cstSubArgs = &quot;[Parent]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCenter = False
+
+Check:
+ If IsMissing(Parent) Or IsEmpty(Parent) Then Set Parent = Nothing
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Parent, &quot;Parent&quot;, ScriptForge.V_OBJECT) Then GoTo Finally
+ End If
+
+ Set oParentPosSize = Nothing
+ lParentX = 0 : lParentY = 0
+ If IsNull(Parent) Then
+ Set oUi = CreateScriptService(&quot;UI&quot;)
+ Set oParentPosSize = oUi._PosSize() &apos; Return the position and dimensions of the active window
+ Else
+ &apos; Determine the object type
+ Set oObjDesc = ScriptForge.SF_Utils._VarTypeObj(Parent)
+ If oObjDesc.iVarType = ScriptForge.V_SFOBJECT Then &apos; ScriptForge object
+ sObjectType = oObjDesc.sObjectType
+ &apos; Document or dialog ?
+ If Not ScriptForge.SF_Array.Contains(Array(&quot;BASE&quot;, &quot;CALC&quot;, &quot;DIALOG&quot;, &quot;DOCUMENT&quot;, &quot;WRITER&quot;), sObjectType, CaseSensitive := True) Then GoTo Finally
+ If sObjectType = &quot;DIALOG&quot; Then
+ Set oParent = Parent._DialogControl
+ Set oParentPosSize = oParent.getPosSize()
+ lParentX = oParentPosSize.X
+ lParentY = oParentPosSize.Y
+ Else
+ Set oParent = Parent._Component.getCurrentController().Frame.getComponentWindow()
+ Set oParentPosSize = oParent.getPosSize()
+ End If
+ Else
+ GoTo Finally &apos; UNO object, do nothing
+ End If
+ End If
+ If IsNull(oParentPosSize) Then GoTo Finally
+
+Try:
+ Set oPosSize = _DialogControl.getPosSize()
+ With oPosSize
+ _DialogControl.setPosSize( _
+ lParentX + CLng((oParentPosSize.Width - .Width) \ 2) _
+ , lParentY + CLng((oParentPosSize.Height - .Height) \ 2) _
+ , .Width _
+ , .Height _
+ , com.sun.star.awt.PosSize.POSSIZE)
+ End With
+ bCenter = True
+
+Finally:
+ Center = bCenter
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Dialog.Center
+
+REM -----------------------------------------------------------------------------
+Public Function Controls(Optional ByVal ControlName As Variant) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the controls contained in the dialog
+&apos;&apos;&apos; - a dialog control object based on its name
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ControlName: a valid control name as a case-sensitive string. If absent the list is returned
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-base array of strings if ControlName is absent
+&apos;&apos;&apos; An instance of the SF_DialogControl class if ControlName exists
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ControlName is invalid
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myDialog As Object, myList As Variant, myControl As Object
+&apos;&apos;&apos; Set myDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, Container, Library, DialogName)
+&apos;&apos;&apos; myList = myDialog.Controls()
+&apos;&apos;&apos; Set myControl = myDialog.Controls(&quot;myTextBox&quot;)
+
+Dim oControl As Object &apos; The new control class instance
+Dim lIndexOfNames As Long &apos; Index in ElementNames array. Used to access _ControlCache
+Dim vControl As Variant &apos; Alias of _ControlCache entry
+Const cstThisSub = &quot;SFDialogs.Dialog.Controls&quot;
+Const cstSubArgs = &quot;[ControlName]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(ControlName) Or IsEmpty(ControlName) Then ControlName = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ControlName, &quot;ControlName&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(ControlName) = 0 Then
+ Controls = _DialogModel.getElementNames()
+ Else
+ If Not _DialogModel.hasByName(ControlName) Then GoTo CatchNotFound
+ lIndexOfNames = ScriptForge.IndexOf(_DialogModel.getElementNames(), ControlName, CaseSensitive := True)
+ &apos; Reuse cache when relevant
+ vControl = _ControlCache(lIndexOfNames)
+ If IsEmpty(vControl) Then
+ &apos; Create the new dialog control class instance
+ Set oControl = New SF_DialogControl
+ With oControl
+ ._Name = ControlName
+ Set .[Me] = oControl
+ Set .[_Parent] = [Me]
+ ._IndexOfNames = ScriptForge.IndexOf(_DialogModel.getElementNames(), ControlName, CaseSensitive := True)
+ ._DialogName = _Name
+ Set ._ControlModel = _DialogModel.getByName(ControlName)
+ Set ._ControlView = _DialogControl.getControl(ControlName)
+ ._Initialize()
+ End With
+ Else
+ Set oControl = vControl
+ End If
+ Set Controls = oControl
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Utils._Validate(ControlName, &quot;ControlName&quot;, V_STRING, _DialogModel.getElementNames())
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.Controls
+
+REM -----------------------------------------------------------------------------
+Public Sub EndExecute(Optional ByVal ReturnValue As Variant)
+&apos;&apos;&apos; Ends the display of a modal dialog and gives back the argument
+&apos;&apos;&apos; as return value for the current Execute() action
+&apos;&apos;&apos; EndExecute is usually contained in the processing of a macro
+&apos;&apos;&apos; triggered by a dialog or control event
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ReturnValue: must be numeric. The value passed to the running Execute() method
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Sub OnEvent(poEvent As Variant)
+&apos;&apos;&apos; Dim oDlg As Object
+&apos;&apos;&apos; Set oDlg = CreateScriptService(&quot;SFDialogs.DialogEvent&quot;, poEvent)
+&apos;&apos;&apos; oDlg.EndExecute(25)
+&apos;&apos;&apos; End Sub
+
+Dim lExecute As Long &apos; Alias of ReturnValue
+Const cstThisSub = &quot;SFDialogs.Dialog.EndExecute&quot;
+Const cstSubArgs = &quot;ReturnValue&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(ReturnValue, &quot;ReturnValue&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ lExecute = CLng(ReturnValue)
+ Call _DialogControl.endDialog(lExecute)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SFDialogs.SF_Dialog.EndExecute
+
+REM -----------------------------------------------------------------------------
+Public Function Execute(Optional ByVal Modal As Variant) As Long
+&apos;&apos;&apos; Display the dialog and wait for its termination by the user
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Modal: False when non-modal dialog. Default = True
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; 0 = Cancel button pressed
+&apos;&apos;&apos; 1 = OK button pressed
+&apos;&apos;&apos; Otherwise: the dialog stopped with an EndExecute statement executed from a dialog or control event
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDlg As Object, lReturn As Long
+&apos;&apos;&apos; Set oDlg = CreateScriptService(,, &quot;myDialog&quot;) &apos; Dialog stored in current document&apos;s standard library
+&apos;&apos;&apos; lReturn = oDlg.Execute()
+&apos;&apos;&apos; Select Case lReturn
+
+Dim lExecute As Long &apos; Return value
+Const cstThisSub = &quot;SFDialogs.Dialog.Execute&quot;
+Const cstSubArgs = &quot;[Modal=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ lExecute = -1
+
+Check:
+ If IsMissing(Modal) Or IsEmpty(Modal) Then Modal = True
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Modal, &quot;Modal&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ If Modal Then
+ _Modal = True
+ _Displayed = True
+ lExecute = _DialogControl.execute()
+ Select Case lExecute
+ Case 1 : lExecute = OKBUTTON
+ Case 0 : lExecute = CANCELBUTTON
+ Case Else
+ End Select
+ _Displayed = False
+ Else
+ _Modal = False
+ _Displayed = True
+ _DialogModel.DesktopAsParent = True
+ _DialogControl.setVisible(True)
+ lExecute = 0
+ End If
+
+Finally:
+ Execute = lExecute
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.Execute
+
+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
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDlg.GetProperty(&quot;Caption&quot;)
+
+Const cstThisSub = &quot;SFDialogs.Dialog.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If 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:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetTextsFromL10N(Optional ByRef L10N As Variant) As Boolean
+&apos;&apos;&apos; Replace all fixed text strings of a dialog by their localized version
+&apos;&apos;&apos; Replaced texts are:
+&apos;&apos;&apos; - the title of the dialog
+&apos;&apos;&apos; - the caption associated with next control types: Button, CheckBox, FixedLine, FixedText, GroupBox and RadioButton
+&apos;&apos;&apos; - the content of list- and comboboxes
+&apos;&apos;&apos; - the tip- or helptext displayed when the mouse is hovering the control
+&apos;&apos;&apos; The current method has a twin method ScriptForge.SF_L10N.AddTextsFromDialog
+&apos;&apos;&apos; The current method is probably run before the Execute() method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; L10N : a &quot;L10N&quot; service instance created with CreateScriptService(&quot;L10N&quot;)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myPO As Object, oDlg As Object
+&apos;&apos;&apos; Set oDlg = CreateScriptService(&quot;Dialog&quot;, &quot;GlobalScope&quot;, &quot;XrayTool&quot;, &quot;DlgXray&quot;)
+&apos;&apos;&apos; Set myPO = CreateScriptService(&quot;L10N&quot;, &quot;C:\myPOFiles\&quot;, &quot;fr-BE&quot;)
+&apos;&apos;&apos; oDlg.GetTextsFromL10N(myPO)
+
+Dim bGet As Boolean &apos; Return value
+Dim vControls As Variant &apos; Array of control names
+Dim sControl As String &apos; A single control name
+Dim oControl As Object &apos; SFDialogs.DialogControl
+Dim sText As String &apos; The text found in the dialog
+Dim sTranslation As String &apos; The translated text got from the dictionary
+Dim vSource As Variant &apos; RowSource property of dialog control as an array
+Dim bChanged As Boolean &apos; True when at least 1 item of a RowSource is modified
+Dim i As Long
+
+Const cstThisSub = &quot;SFDialogs.Dialog.GetTextsFromL10N&quot;
+Const cstSubArgs = &quot;L10N&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bGet = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(L10N, &quot;L10N&quot;, V_OBJECT, , , &quot;L10N&quot;) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Get the dialog title
+ sText = Caption
+ If Len(sText) &gt; 0 Then
+ sTranslation = L10N._(sText)
+ If sText &lt;&gt; sTranslation Then Caption = sTranslation
+ End If
+ &apos; Scan all controls
+ vControls = Controls()
+ For Each sControl In vControls
+ Set oControl = Controls(sControl)
+ With oControl
+ &apos; Extract fixed texts
+ sText = .Caption
+ If Len(sText) &gt; 0 Then
+ sTranslation = L10N._(sText)
+ If sText &lt;&gt; sTranslation Then .Caption = sTranslation
+ End If
+ vSource = .RowSource &apos; List and comboboxes only
+ If IsArray(vSource) Then
+ bChanged = False
+ For i = 0 To UBound(vSource)
+ If Len(vSource(i)) &gt; 0 Then
+ sTranslation = L10N._(vSource(i))
+ If sTranslation &lt;&gt; vSource(i) Then
+ bChanged = True
+ vSource(i) = sTranslation
+ End If
+ End If
+ Next i
+ &apos; Rewrite if at least 1 item has been modified by the translation process
+ If bChanged Then .RowSource = vSource
+ End If
+ sText = .TipText
+ If Len(sText) &gt; 0 Then
+ sTranslation = L10N._(sText)
+ If sText &lt;&gt; sTranslation Then .TipText = sTranslation
+ End If
+ End With
+ Next sControl
+
+ bGet = True
+
+Finally:
+ GetTextsFromL10N = bGet
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.GetTextsFromL10N
+
+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;Center&quot; _
+ , &quot;Controls&quot; _
+ , &quot;EndExecute&quot; _
+ , &quot;Execute&quot; _
+ , &quot;GetTextsFromL10N&quot; _
+ , &quot;Resize&quot; _
+ , &quot;Terminate&quot; _
+ )
+
+End Function &apos; SFDialogs.SF_Dialog.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Dialog class as an array
+
+ Properties = Array( _
+ &quot;Caption&quot; _
+ , &quot;Height&quot; _
+ , &quot;Modal&quot; _
+ , &quot;Name&quot; _
+ , &quot;OnFocusGained&quot; _
+ , &quot;OnFocusLost&quot; _
+ , &quot;OnKeyPressed&quot; _
+ , &quot;OnKeyReleased&quot; _
+ , &quot;OnMouseDragged&quot; _
+ , &quot;OnMouseEntered&quot; _
+ , &quot;OnMouseExited&quot; _
+ , &quot;OnMouseMoved&quot; _
+ , &quot;OnMousePressed&quot; _
+ , &quot;OnMouseReleased&quot; _
+ , &quot;Page&quot; _
+ , &quot;Visible&quot; _
+ , &quot;Width&quot; _
+ , &quot;XDialogModel&quot; _
+ , &quot;XDialogView&quot; _
+ )
+
+End Function &apos; SFDialogs.SF_Dialog.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Resize(Optional ByVal Left As Variant _
+ , Optional ByVal Top As Variant _
+ , Optional ByVal Width As Variant _
+ , Optional ByVal Height As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Move the top-left corner of a dialog to new coordinates and/or modify its dimensions
+&apos;&apos;&apos; All distances are expressed in 1/100 mm.
+&apos;&apos;&apos; Without arguments, the method resets the initial dimensions
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Left : the horizontal distance from the top-left corner
+&apos;&apos;&apos; Top : the vertical distance from the top-left corner
+&apos;&apos;&apos; Width : the horizontal width of the rectangle containing the Dialog
+&apos;&apos;&apos; Height : the vertical height of the rectangle containing the Dialog
+&apos;&apos;&apos; Negative or missing arguments are left unchanged
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDialog.Resize(1000, 2000, Height := 6000) &apos; Width is not changed
+
+Dim bResize As Boolean &apos; Return value
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+Dim iFlags As Integer &apos; com.sun.star.awt.PosSize constants
+Const cstThisSub = &quot;SFDialogs.Dialog.Resize&quot;
+Const cstSubArgs = &quot;[Left], [Top], [Width], [Height]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bResize = False
+
+Check:
+ If IsMissing(Left) Or IsEmpty(Left) Then Left = -1
+ If IsMissing(Top) Or IsEmpty(Top) Then Top = -1
+ If IsMissing(Height) Or IsEmpty(Height) Then Height = -1
+ If IsMissing(Width) Or IsEmpty(Width) Then Width = -1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Left, &quot;Left&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Top, &quot;Top&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Width, &quot;Width&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Height, &quot;Height&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ With _DialogControl
+ Set oPosSize = .getPosSize()
+ &apos; Reset factory settings
+ If Left = -1 And Top = -1 And Width = -1 And Height = -1 Then
+ &apos;Left = _Left &apos; Initial positions determination is unstable
+ &apos;Top = _Top
+ Width = _Width
+ Height = _Height
+ End If
+ &apos; Trace the elements to change
+ iFlags = 0
+ With com.sun.star.awt.PosSize
+ If Left &gt;= 0 Then iFlags = iFlags + .X Else Left = oPosSize.X
+ If Top &gt;= 0 Then iFlags = iFlags + .Y Else Top = oPosSize.Y
+ If Width &gt; 0 Then iFlags = iFlags + .WIDTH Else Width = oPosSize.Width
+ If Height &gt; 0 Then iFlags = iFlags + .HEIGHT Else Height = oPosSize.Height
+ End With
+ &apos; Rewrite
+ If iFlags &gt; 0 Then .setPosSize(CLng(Left), CLng(Top), CLng(Width), CLng(Height), iFlags)
+ End With
+ bResize = True
+
+Finally:
+ Resize = bResize
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Dialog.Resize
+
+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;SFDialogs.Dialog.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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Terminate() As Boolean
+&apos;&apos;&apos; Terminate the dialog service for the current dialog instance
+&apos;&apos;&apos; After termination any action on the current instance will be ignored
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if termination is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDlg As Object, lReturn As Long
+&apos;&apos;&apos; Set oDlg = CreateScriptService(,, &quot;myDialog&quot;) &apos; Dialog stored in current document&apos;s standard library
+&apos;&apos;&apos; lreturn = oDlg.Execute()
+&apos;&apos;&apos; Select Case lReturn
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; End Select
+&apos;&apos;&apos; oDlg.Terminate()
+
+Dim bTerminate As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDialogs.Dialog.Terminate&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bTerminate = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ _DialogControl.dispose()
+ Set _DialogControl = Nothing
+ SF_Register._CleanCacheEntry(_CacheIndex)
+ _CacheIndex = -1
+ Dispose()
+
+ bTerminate = True
+
+Finally:
+ Terminate = bTerminate
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog.Terminate
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _GetEventName(ByVal psProperty As String) As String
+&apos;&apos;&apos; Return the LO internal event name derived from the SF property name
+&apos;&apos;&apos; The SF property name is not case sensitive, while the LO name is case-sensitive
+&apos; Corrects the typo on ErrorOccur(r?)ed, if necessary
+
+Dim vProperties As Variant &apos; Array of class properties
+Dim sProperty As String &apos; Correctly cased property name
+
+ vProperties = Properties()
+ sProperty = vProperties(ScriptForge.SF_Array.IndexOf(vProperties, psProperty, SortOrder := &quot;ASC&quot;))
+
+ _GetEventName = LCase(Mid(sProperty, 3, 1)) &amp; Right(sProperty, Len(sProperty) - 3)
+
+End Function &apos; SFDialogs.SF_Dialog._GetEventName
+
+REM -----------------------------------------------------------------------------
+Private Function _GetListener(ByVal psEventName As String) As String
+&apos;&apos;&apos; Getting/Setting macros triggered by events requires a Listener-EventName pair
+&apos;&apos;&apos; Return the X...Listener corresponding with the event name in argument
+
+ Select Case UCase(psEventName)
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;)
+ _GetListener = &quot;XFocusListener&quot;
+ Case UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;)
+ _GetListener = &quot;XKeyListener&quot;
+ Case UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseMoved&quot;)
+ _GetListener = &quot;XMouseMotionListener&quot;
+ Case UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ _GetListener = &quot;XMouseListener&quot;
+ Case Else
+ _GetListener = &quot;&quot;
+ End Select
+
+End Function &apos; SFDialogs.SF_Dialog._GetListener
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos;&apos;&apos; Complete the object creation process:
+&apos;&apos;&apos; - Initialization of private members
+&apos;&apos;&apos; - Creation of the dialog graphical interface
+&apos;&apos;&apos; - Addition of the new object in the Dialogs buffer
+&apos;&apos;&apos; - Initialisation of persistent storage for controls
+
+Dim oPosSize As Object &apos; com.sun.star.awt.Rectangle
+
+Try:
+ &apos; Keep reference to model
+ Set _DialogModel = _DialogControl.Model
+
+ &apos; Store initial position and dimensions
+ Set oPosSize = _DialogControl.getPosSize()
+ With oPosSize
+ _Left = .X
+ _Top = .Y
+ _Width = .Width
+ _Height = .Height
+ End With
+
+ &apos; Add dialog reference to cache
+ _CacheIndex = SF_Register._AddDialogToCache(_DialogControl, [Me])
+
+ &apos; Size the persistent storage
+ _ControlCache = Array()
+ ReDim _ControlCache(0 To UBound(_DialogModel.getElementNames()))
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDialogs.SF_Dialog._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _IsStillAlive(Optional ByVal pbError As Boolean) As Boolean
+&apos;&apos;&apos; Return True if the dialog service is still active
+&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; pbError: if True (default), raise a fatal error
+
+Dim bAlive As Boolean &apos; Return value
+Dim sDialog As String &apos; Alias of DialogName
+
+Check:
+ On Local Error GoTo Catch &apos; Anticipate DisposedException errors or alike
+ If IsMissing(pbError) Then pbError = True
+
+Try:
+ bAlive = ( Not IsNull(_DialogProvider) And Not IsNull(_DialogControl) )
+ If Not bAlive Then GoTo Catch
+
+Finally:
+ _IsStillAlive = bAlive
+ Exit Function
+Catch:
+ bAlive = False
+ On Error GoTo 0
+ sDialog = _Name
+ Dispose()
+ If pbError Then ScriptForge.SF_Exception.RaiseFatal(DIALOGDEADERROR, sDialog)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog._IsStillAlive
+
+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
+
+Static oSession As Object &apos; Alias of SF_Session
+Dim oDialogEvents As Object &apos; com.sun.star.container.XNameContainer
+Dim sEventName As String &apos; Internal event name
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDialogs.Dialog.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Caption&quot;)
+ If oSession.HasUNOProperty(_DialogModel, &quot;Title&quot;) Then _PropertyGet = _DialogModel.Title
+ Case UCase(&quot;Height&quot;)
+ If oSession.HasUNOProperty(_DialogModel, &quot;Height&quot;) Then _PropertyGet = _DialogModel.Height
+ Case UCase(&quot;Modal&quot;)
+ _PropertyGet = _Modal
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ Set oDialogEvents = _DialogModel.getEvents()
+ sEventName = &quot;com.sun.star.awt.&quot; &amp; _GetListener(psProperty) &amp; &quot;::&quot; &amp; _GetEventName(psProperty)
+ If oDialogEvents.hasByName(sEventName) Then
+ _PropertyGet = oDialogEvents.getByName(sEventName).ScriptCode
+ Else
+ _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;Page&quot;)
+ If oSession.HasUNOProperty(_DialogModel, &quot;Step&quot;) Then _PropertyGet = _DialogModel.Step
+ Case UCase(&quot;Visible&quot;)
+ If oSession.HasUnoMethod(_DialogControl, &quot;isVisible&quot;) Then _PropertyGet = CBool(_DialogControl.isVisible())
+ Case UCase(&quot;Width&quot;)
+ If oSession.HasUNOProperty(_DialogModel, &quot;Width&quot;) Then _PropertyGet = _DialogModel.Width
+ Case UCase(&quot;XDialogModel&quot;)
+ Set _PropertyGet = _DialogModel
+ Case UCase(&quot;XDialogView&quot;)
+ Set _PropertyGet = _DialogControl
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(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;SFDialogs.Dialog.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Caption&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Caption&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUNOProperty(_DialogModel, &quot;Title&quot;) Then _DialogModel.Title = pvValue
+ Case UCase(&quot;Height&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Height&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUNOProperty(_DialogModel, &quot;Height&quot;) Then _DialogModel.Height = pvValue
+ Case UCase(&quot;Page&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Page&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUNOProperty(_DialogModel, &quot;Step&quot;) Then _DialogModel.Step = CLng(pvValue)
+ Case UCase(&quot;Visible&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Visible&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoMethod(_DialogControl, &quot;setVisible&quot;) Then _DialogControl.setVisible(pvValue)
+ Case UCase(&quot;Width&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Width&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUNOProperty(_DialogModel, &quot;Width&quot;) Then _DialogModel.Width = pvValue
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Dialog._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[DIALOG]: Container.Library.Name&quot;
+
+ _Repr = &quot;[DIALOG]: &quot; &amp; _Container &amp; &quot;.&quot; &amp; _Library &amp; &quot;.&quot; &amp; _Name
+
+End Function &apos; SFDialogs.SF_Dialog._Repr
+
+REM ============================================ END OF SFDIALOGS.SF_DIALOG
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdialogs/SF_DialogControl.xba b/wizards/source/sfdialogs/SF_DialogControl.xba
new file mode 100644
index 000000000..f4a0891d9
--- /dev/null
+++ b/wizards/source/sfdialogs/SF_DialogControl.xba
@@ -0,0 +1,2084 @@
+<?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_DialogControl" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDialogs 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_DialogControl
+&apos;&apos;&apos; ================
+&apos;&apos;&apos; Manage the controls belonging to a dialog defined with the Basic IDE
+&apos;&apos;&apos; Each instance of the current class represents a single control within a dialog box
+&apos;&apos;&apos;
+&apos;&apos;&apos; The focus is clearly set on getting and setting the values displayed by the controls of the dialog box,
+&apos;&apos;&apos; not on their formatting. The latter is easily accessible via the XControlModel and XControlView
+&apos;&apos;&apos; UNO objects.
+&apos;&apos;&apos; Essentially a single property &quot;Value&quot; maps many alternative UNO properties depending each on
+&apos;&apos;&apos; the control type.
+&apos;&apos;&apos;
+&apos;&apos;&apos; A special attention is given to controls with types TreeControl and TableControl
+&apos;&apos;&apos; It is easy with the API proposed in the current class to populate a tree, either
+&apos;&apos;&apos; - branch by branch (CreateRoot and AddSubNode), or
+&apos;&apos;&apos; - with a set of branches at once (AddSubtree)
+&apos;&apos;&apos; Additionally populating a TreeControl can be done statically or dynamically
+&apos;&apos;&apos;
+&apos;&apos;&apos; With the method SetTableData(), feed a tablecontrol with a sortable and selectable
+&apos;&apos;&apos; array of data. Columns and rows may receive a header. Column widths are adjusted manually by the user or
+&apos;&apos;&apos; with the same method. Alignments can be set as well by script.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation:
+&apos;&apos;&apos; Dim myDialog As Object, myControl As Object
+&apos;&apos;&apos; Set myDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, &quot;GlobalScope&quot;, myLibrary, DialogName)
+&apos;&apos;&apos; Set myControl = myDialog.Controls(&quot;myTextBox&quot;)
+&apos;&apos;&apos; myControl.Value = &quot;Dialog started at &quot; &amp; Now()
+&apos;&apos;&apos; myDialog.Execute()
+&apos;&apos;&apos; &apos; ... process the controls actual values
+&apos;&apos;&apos; myDialog.Terminate()
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_dialogcontrol.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const CONTROLTYPEERROR = &quot;CONTROLTYPEERROR&quot;
+Private Const TEXTFIELDERROR = &quot;TEXTFIELDERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be DIALOGCONTROL
+Private ServiceName As String
+
+&apos; Control naming
+Private _Name As String
+Private _IndexOfNames As Long &apos; Index in ElementNames array. Used to access SF_Dialog._ControlCache
+Private _DialogName As String &apos; Parent dialog name
+
+&apos; Control UNO references
+Private _ControlModel As Object &apos; com.sun.star.awt.XControlModel
+Private _ControlView As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
+Private _TreeDataModel As Object &apos; com.sun.star.awt.tree.MutableTreeDataModel
+Private _GridColumnModel As Object &apos; com.sun.star.awt.grid.XGridColumnModel
+Private _GridDataModel As Object &apos; com.sun.star.awt.grid.XGridDataModel
+
+&apos; Control attributes
+Private _ImplementationName As String
+Private _ControlType As String &apos; One of the CTLxxx constants
+
+&apos; Tree control on-select and on-expand attributes
+&apos; Tree controls may be associated with events not defined in the Basic IDE
+Private _OnNodeSelected As String &apos; Script to invoke when a node is selected
+Private _OnNodeExpanded As String &apos; Script to invoke when a node is expanded
+Private _SelectListener As Object &apos; com.sun.star.view.XSelectionChangeListener
+Private _ExpandListener As Object &apos; com.sun.star.awt.tree.XTreeExpansionListener
+
+&apos; Table control attributes
+Private _ColumnWidths As Variant &apos; Array of column widths
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const CTLBUTTON = &quot;Button&quot;
+Private Const CTLCHECKBOX = &quot;CheckBox&quot;
+Private Const CTLCOMBOBOX = &quot;ComboBox&quot;
+Private Const CTLCURRENCYFIELD = &quot;CurrencyField&quot;
+Private Const CTLDATEFIELD = &quot;DateField&quot;
+Private Const CTLFILECONTROL = &quot;FileControl&quot;
+Private Const CTLFIXEDLINE = &quot;FixedLine&quot;
+Private Const CTLFIXEDTEXT = &quot;FixedText&quot;
+Private Const CTLFORMATTEDFIELD = &quot;FormattedField&quot;
+Private Const CTLGROUPBOX = &quot;GroupBox&quot;
+Private Const CTLIMAGECONTROL = &quot;ImageControl&quot;
+Private Const CTLLISTBOX = &quot;ListBox&quot;
+Private Const CTLNUMERICFIELD = &quot;NumericField&quot;
+Private Const CTLPATTERNFIELD = &quot;PatternField&quot;
+Private Const CTLPROGRESSBAR = &quot;ProgressBar&quot;
+Private Const CTLRADIOBUTTON = &quot;RadioButton&quot;
+Private Const CTLSCROLLBAR = &quot;ScrollBar&quot;
+Private Const CTLTABLECONTROL = &quot;TableControl&quot;
+Private Const CTLTEXTFIELD = &quot;TextField&quot;
+Private Const CTLTIMEFIELD = &quot;TimeField&quot;
+Private Const CTLTREECONTROL = &quot;TreeControl&quot;
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;DIALOGCONTROL&quot;
+ ServiceName = &quot;SFDialogs.DialogControl&quot;
+ _Name = &quot;&quot;
+ _IndexOfNames = -1
+ _DialogName = &quot;&quot;
+ Set _ControlModel = Nothing
+ Set _ControlView = Nothing
+ Set _TreeDataModel = Nothing
+ Set _GridColumnModel = Nothing
+ Set _GridDataModel = Nothing
+ _ImplementationName = &quot;&quot;
+ _ControlType = &quot;&quot;
+ _OnNodeSelected = &quot;&quot;
+ _OnNodeExpanded = &quot;&quot;
+ Set _SelectListener = Nothing
+ Set _ExpandListener = Nothing
+ _ColumnWidths = Array()
+End Sub &apos; SFDialogs.SF_DialogControl Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDialogs.SF_DialogControl Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDialogs.SF_DialogControl Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Cancel() As Variant
+&apos;&apos;&apos; The Cancel property specifies if a command button has or not the behaviour of a Cancel button.
+ Cancel = _PropertyGet(&quot;Cancel&quot;, False)
+End Property &apos; SFDialogs.SF_DialogControl.Cancel (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Cancel(Optional ByVal pvCancel As Variant)
+&apos;&apos;&apos; Set the updatable property Cancel
+ _PropertySet(&quot;Cancel&quot;, pvCancel)
+End Property &apos; SFDialogs.SF_DialogControl.Cancel (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Caption() As Variant
+&apos;&apos;&apos; The Caption property refers to the text associated with the control
+ Caption = _PropertyGet(&quot;Caption&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Caption (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Caption(Optional ByVal pvCaption As Variant)
+&apos;&apos;&apos; Set the updatable property Caption
+ _PropertySet(&quot;Caption&quot;, pvCaption)
+End Property &apos; SFDialogs.SF_DialogControl.Caption (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ControlType() As String
+&apos;&apos;&apos; Return the type of the actual control: &quot;CheckBox&quot;, &quot;TextField&quot;, &quot;DateField&quot;, ...
+ ControlType = _PropertyGet(&quot;ControlType&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.ControlType
+
+REM -----------------------------------------------------------------------------
+Property Get CurrentNode() As Variant
+&apos;&apos;&apos; The CurrentNode property returns the currently selected node
+&apos;&apos;&apos; It returns Empty when there is no node selected
+&apos;&apos;&apos; When there are several selections, it returns the topmost node among the selected ones
+ CurrentNode = _PropertyGet(&quot;CurrentNode&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.CurrentNode (get)
+
+REM -----------------------------------------------------------------------------
+Property Let CurrentNode(Optional ByVal pvCurrentNode As Variant)
+&apos;&apos;&apos; Set a single selection in a tree control
+ _PropertySet(&quot;CurrentNode&quot;, pvCurrentNode)
+End Property &apos; SFDialogs.SF_DialogControl.CurrentNode (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Default() As Variant
+&apos;&apos;&apos; The Default property specifies whether a command button is the default (OK) button.
+ Default = _PropertyGet(&quot;Default&quot;, False)
+End Property &apos; SFDialogs.SF_DialogControl.Default (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Default(Optional ByVal pvDefault As Variant)
+&apos;&apos;&apos; Set the updatable property Default
+ _PropertySet(&quot;Default&quot;, pvDefault)
+End Property &apos; SFDialogs.SF_DialogControl.Default (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Enabled() As Variant
+&apos;&apos;&apos; The Enabled property specifies if the control is accessible with the cursor.
+ Enabled = _PropertyGet(&quot;Enabled&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Enabled (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Enabled(Optional ByVal pvEnabled As Variant)
+&apos;&apos;&apos; Set the updatable property Enabled
+ _PropertySet(&quot;Enabled&quot;, pvEnabled)
+End Property &apos; SFDialogs.SF_DialogControl.Enabled (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Format() As Variant
+&apos;&apos;&apos; The Format property specifies the format in which to display dates and times.
+ Format = _PropertyGet(&quot;Format&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Format (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Format(Optional ByVal pvFormat As Variant)
+&apos;&apos;&apos; Set the updatable property Format
+&apos;&apos;&apos; NB: Format is read-only for formatted field controls
+ _PropertySet(&quot;Format&quot;, pvFormat)
+End Property &apos; SFDialogs.SF_DialogControl.Format (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ListCount() As Long
+&apos;&apos;&apos; The ListCount property specifies the number of rows in a list box or a combo box
+ ListCount = _PropertyGet(&quot;ListCount&quot;, 0)
+End Property &apos; SFDialogs.SF_DialogControl.ListCount (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ListIndex() As Variant
+&apos;&apos;&apos; The ListIndex property specifies which item is selected in a list box or combo box.
+&apos;&apos;&apos; In case of multiple selection, the index of the first one is returned or only one is set
+ ListIndex = _PropertyGet(&quot;ListIndex&quot;, -1)
+End Property &apos; SFDialogs.SF_DialogControl.ListIndex (get)
+
+REM -----------------------------------------------------------------------------
+Property Let ListIndex(Optional ByVal pvListIndex As Variant)
+&apos;&apos;&apos; Set the updatable property ListIndex
+ _PropertySet(&quot;ListIndex&quot;, pvListIndex)
+End Property &apos; SFDialogs.SF_DialogControl.ListIndex (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Locked() As Variant
+&apos;&apos;&apos; The Locked property specifies if a control is read-only
+ Locked = _PropertyGet(&quot;Locked&quot;, False)
+End Property &apos; SFDialogs.SF_DialogControl.Locked (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Locked(Optional ByVal pvLocked As Variant)
+&apos;&apos;&apos; Set the updatable property Locked
+ _PropertySet(&quot;Locked&quot;, pvLocked)
+End Property &apos; SFDialogs.SF_DialogControl.Locked (let)
+
+REM -----------------------------------------------------------------------------
+Property Get MultiSelect() As Variant
+&apos;&apos;&apos; The MultiSelect property specifies whether a user can make multiple selections in a listbox
+ MultiSelect = _PropertyGet(&quot;MultiSelect&quot;, False)
+End Property &apos; SFDialogs.SF_DialogControl.MultiSelect (get)
+
+REM -----------------------------------------------------------------------------
+Property Let MultiSelect(Optional ByVal pvMultiSelect As Variant)
+&apos;&apos;&apos; Set the updatable property MultiSelect
+ _PropertySet(&quot;MultiSelect&quot;, pvMultiSelect)
+End Property &apos; SFDialogs.SF_DialogControl.MultiSelect (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Name() As String
+&apos;&apos;&apos; Return the name of the actual control
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Name
+
+REM -----------------------------------------------------------------------------
+Property Get OnActionPerformed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnActionPerformed event
+ OnActionPerformed = _PropertyGet(&quot;OnActionPerformed&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnActionPerformed (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnAdjustmentValueChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnAdjustmentValueChanged event
+ OnAdjustmentValueChanged = _PropertyGet(&quot;OnAdjustmentValueChanged&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnAdjustmentValueChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnFocusGained() As Variant
+&apos;&apos;&apos; Get the script associated with the OnFocusGained event
+ OnFocusGained = _PropertyGet(&quot;OnFocusGained&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnFocusGained (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnFocusLost() As Variant
+&apos;&apos;&apos; Get the script associated with the OnFocusLost event
+ OnFocusLost = _PropertyGet(&quot;OnFocusLost&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnFocusLost (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnItemStateChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnItemStateChanged event
+ OnItemStateChanged = _PropertyGet(&quot;OnItemStateChanged&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnItemStateChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnKeyPressed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnKeyPressed event
+ OnKeyPressed = _PropertyGet(&quot;OnKeyPressed&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnKeyPressed (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnKeyReleased() As Variant
+&apos;&apos;&apos; Get the script associated with the OnKeyReleased event
+ OnKeyReleased = _PropertyGet(&quot;OnKeyReleased&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnKeyReleased (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseDragged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseDragged event
+ OnMouseDragged = _PropertyGet(&quot;OnMouseDragged&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnMouseDragged (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseEntered() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseEntered event
+ OnMouseEntered = _PropertyGet(&quot;OnMouseEntered&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnMouseEntered (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseExited() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseExited event
+ OnMouseExited = _PropertyGet(&quot;OnMouseExited&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnMouseExited (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseMoved() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseMoved event
+ OnMouseMoved = _PropertyGet(&quot;OnMouseMoved&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnMouseMoved (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMousePressed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMousePressed event
+ OnMousePressed = _PropertyGet(&quot;OnMousePressed&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnMousePressed (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseReleased() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseReleased event
+ OnMouseReleased = _PropertyGet(&quot;OnMouseReleased&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnMouseReleased (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OnNodeExpanded() As Variant
+&apos;&apos;&apos; Get the script associated with the OnNodeExpanded event
+ OnNodeExpanded = _PropertyGet(&quot;OnNodeExpanded&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnNodeExpanded (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnNodeExpanded(Optional ByVal pvOnNodeExpanded As Variant)
+&apos;&apos;&apos; Set the updatable property OnNodeExpanded
+ _PropertySet(&quot;OnNodeExpanded&quot;, pvOnNodeExpanded)
+End Property &apos; SFDialogs.SF_DialogControl.OnNodeExpanded (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnNodeSelected() As Variant
+&apos;&apos;&apos; Get the script associated with the OnNodeSelected event
+ OnNodeSelected = _PropertyGet(&quot;OnNodeSelected&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnNodeSelected (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnNodeSelected(Optional ByVal pvOnNodeSelected As Variant)
+&apos;&apos;&apos; Set the updatable property OnNodeSelected
+ _PropertySet(&quot;OnNodeSelected&quot;, pvOnNodeSelected)
+End Property &apos; SFDialogs.SF_DialogControl.OnNodeSelected (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnTextChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnTextChanged event
+ OnTextChanged = _PropertyGet(&quot;OnTextChanged&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.OnTextChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Page() As Variant
+&apos;&apos;&apos; A dialog may have several pages that can be traversed by the user step by step. The Page property of the Dialog object defines which page of the dialog is active.
+&apos;&apos;&apos; The Page property of a control defines the page of the dialog on which the control is visible.
+&apos;&apos;&apos; For example, if a control has a page value of 1, it is only visible on page 1 of the dialog.
+&apos;&apos;&apos; If the page value of the dialog is increased from 1 to 2, then all controls with a page value of 1 disappear and all controls with a page value of 2 become visible.
+ Page = _PropertyGet(&quot;Page&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Page (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Page(Optional ByVal pvPage As Variant)
+&apos;&apos;&apos; Set the updatable property Page
+ _PropertySet(&quot;Page&quot;, pvPage)
+End Property &apos; SFDialogs.SF_DialogControl.Page (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Parent() As Object
+&apos;&apos;&apos; Return the Parent dialog object of the actual control
+ Parent = _PropertyGet(&quot;Parent&quot;, Nothing)
+End Property &apos; SFDialogs.SF_DialogControl.Parent
+
+REM -----------------------------------------------------------------------------
+Property Get Picture() As Variant
+&apos;&apos;&apos; The Picture property specifies a bitmap or other type of graphic to be displayed on the specified control
+ Picture = _PropertyGet(&quot;Picture&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Picture (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Picture(Optional ByVal pvPicture As Variant)
+&apos;&apos;&apos; Set the updatable property Picture
+ _PropertySet(&quot;Picture&quot;, pvPicture)
+End Property &apos; SFDialogs.SF_DialogControl.Picture (let)
+
+REM -----------------------------------------------------------------------------
+Property Get RootNode() As Variant
+&apos;&apos;&apos; The RootNode property returns the last root node of a tree control
+ RootNode = _PropertyGet(&quot;RootNode&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.RootNode (get)
+
+REM -----------------------------------------------------------------------------
+Property Get RowSource() As Variant
+&apos;&apos;&apos; The RowSource property specifies the data contained in a combobox or a listbox
+&apos;&apos;&apos; as a zero-based array of string values
+ RowSource = _PropertyGet(&quot;RowSource&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.RowSource (get)
+
+REM -----------------------------------------------------------------------------
+Property Let RowSource(Optional ByVal pvRowSource As Variant)
+&apos;&apos;&apos; Set the updatable property RowSource
+ _PropertySet(&quot;RowSource&quot;, pvRowSource)
+End Property &apos; SFDialogs.SF_DialogControl.RowSource (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Text() As Variant
+&apos;&apos;&apos; The Text property specifies the actual content of the control like it is displayed on the screen
+ Text = _PropertyGet(&quot;Text&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.Text (get)
+
+REM -----------------------------------------------------------------------------
+Property Get TipText() As Variant
+&apos;&apos;&apos; The TipText property specifies the text that appears in a screentip when you hold the mouse pointer over a control
+ TipText = _PropertyGet(&quot;TipText&quot;, &quot;&quot;)
+End Property &apos; SFDialogs.SF_DialogControl.TipText (get)
+
+REM -----------------------------------------------------------------------------
+Property Let TipText(Optional ByVal pvTipText As Variant)
+&apos;&apos;&apos; Set the updatable property TipText
+ _PropertySet(&quot;TipText&quot;, pvTipText)
+End Property &apos; SFDialogs.SF_DialogControl.TipText (let)
+
+REM -----------------------------------------------------------------------------
+Property Get TripleState() As Variant
+&apos;&apos;&apos; The TripleState property specifies how a check box will display Null values
+&apos;&apos;&apos; When True, the control will cycle through states for Yes, No, and Null values. The control appears dimmed (grayed) when its Value property is set to Null.
+&apos;&apos;&apos; When False, the control will cycle through states for Yes and No values. Null values display as if they were No values.
+ TripleState = _PropertyGet(&quot;TripleState&quot;, False)
+End Property &apos; SFDialogs.SF_DialogControl.TripleState (get)
+
+REM -----------------------------------------------------------------------------
+Property Let TripleState(Optional ByVal pvTripleState As Variant)
+&apos;&apos;&apos; Set the updatable property TripleState
+ _PropertySet(&quot;TripleState&quot;, pvTripleState)
+End Property &apos; SFDialogs.SF_DialogControl.TripleState (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Value() As Variant
+&apos;&apos;&apos; The Value property specifies the data contained in the control
+ Value = _PropertyGet(&quot;Value&quot;, Empty)
+End Property &apos; SFDialogs.SF_DialogControl.Value (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Value(Optional ByVal pvValue As Variant)
+&apos;&apos;&apos; Set the updatable property Value
+ _PropertySet(&quot;Value&quot;, pvValue)
+End Property &apos; SFDialogs.SF_DialogControl.Value (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Visible() As Variant
+&apos;&apos;&apos; The Visible property specifies if the control is accessible with the cursor.
+ Visible = _PropertyGet(&quot;Visible&quot;, True)
+End Property &apos; SFDialogs.SF_DialogControl.Visible (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Visible(Optional ByVal pvVisible As Variant)
+&apos;&apos;&apos; Set the updatable property Visible
+ _PropertySet(&quot;Visible&quot;, pvVisible)
+End Property &apos; SFDialogs.SF_DialogControl.Visible (let)
+
+REM -----------------------------------------------------------------------------
+Property Get XControlModel() As Object
+&apos;&apos;&apos; The XControlModel property returns the model UNO object of the control
+ XControlModel = _PropertyGet(&quot;XControlModel&quot;, Nothing)
+End Property &apos; SFDialogs.SF_DialogControl.XControlModel (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XControlView() As Object
+&apos;&apos;&apos; The XControlView property returns the view UNO object of the control
+ XControlView = _PropertyGet(&quot;XControlView&quot;, Nothing)
+End Property &apos; SFDialogs.SF_DialogControl.XControlView (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XGridColumnModel() As Object
+&apos;&apos;&apos; The XGridColumnModel property returns the mutable data model UNO object of the tree control
+ XGridColumnModel = _PropertyGet(&quot;XGridColumnModel&quot;, Nothing)
+End Property &apos; SFDialogs.SF_DialogControl.XGridColumnModel (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XGridDataModel() As Object
+&apos;&apos;&apos; The XGridDataModel property returns the mutable data model UNO object of the tree control
+ XGridDataModel = _PropertyGet(&quot;XGridDataModel&quot;, Nothing)
+End Property &apos; SFDialogs.SF_DialogControl.XGridDataModel (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XTreeDataModel() As Object
+&apos;&apos;&apos; The XTreeDataModel property returns the mutable data model UNO object of the tree control
+ XTreeDataModel = _PropertyGet(&quot;XTreeDataModel&quot;, Nothing)
+End Property &apos; SFDialogs.SF_DialogControl.XTreeDataModel (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function AddSubNode(Optional ByRef ParentNode As Variant _
+ , Optional ByVal DisplayValue As Variant _
+ , Optional ByRef DataValue As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return a new node of the tree control subordinate to a parent node
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ParentNode: A node UNO object, of type com.sun.star.awt.tree.XMutableTreeNode
+&apos;&apos;&apos; DisplayValue: the text appearing in the control box
+&apos;&apos;&apos; DataValue: any value associated with the new node. Default = Empty
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new node UNO object: com.sun.star.awt.tree.XMutableTreeNode
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myTree As Object, myNode As Object, theRoot As Object
+&apos;&apos;&apos; Set myTree = myDialog.Controls(&quot;myTreeControl&quot;)
+&apos;&apos;&apos; Set theRoot = myTree.CreateRoot(&quot;Tree top&quot;)
+&apos;&apos;&apos; Set myNode = myTree.AddSubNode(theRoot, &quot;A branch ...&quot;)
+
+Dim oNode As Object &apos; Return value
+Const cstThisSub = &quot;SFDialogs.DialogControl.AddSubNode&quot;
+Const cstSubArgs = &quot;ParentNode, DisplayValue, [DataValue=Empty]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oNode = Nothing
+
+Check:
+ If IsMissing(DataValue) Then DataValue = Empty
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If _ControlType &lt;&gt; CTLTREECONTROL Then GoTo CatchType
+ If Not ScriptForge.SF_Utils._Validate(ParentNode, &quot;ParentNode&quot;, V_OBJECT) Then GoTo Catch
+ If ScriptForge.SF_Session.UnoObjectType(ParentNode) &lt;&gt; &quot;toolkit.MutableTreeNode&quot; Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(DisplayValue, &quot;DisplayValue&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ With _TreeDataModel
+ Set oNode = .createNode(DisplayValue, True)
+ oNode.DataValue = DataValue
+ ParentNode.appendChild(oNode)
+ End With
+
+Finally:
+ Set AddSubNode = oNode
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ ScriptForge.SF_Exception.RaiseFatal(CONTROLTYPEERROR, _Name, _DialogName, _ControlType, &quot;AddSubNode&quot;)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl.AddSubNode
+
+REM -----------------------------------------------------------------------------
+Public Function AddSubTree(Optional ByRef ParentNode As Variant _
+ , Optional ByRef FlatTree As Variant _
+ , Optional ByVal WithDataValue As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Return True when a subtree, subordinate to a parent node, could be inserted successfully in a tree control
+&apos;&apos;&apos; If the parent node had already child nodes before calling this method, the child nodes are erased
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ParentNode: A node UNO object, of type com.sun.star.awt.tree.XMutableTreeNode
+&apos;&apos;&apos; FlatTree: a 2D array sorted on the columns containing the DisplayValues
+&apos;&apos;&apos; Flat tree &gt;&gt;&gt;&gt; Resulting subtree
+&apos;&apos;&apos; A1 B1 C1 |__ A1
+&apos;&apos;&apos; A1 B1 C2 |__ B1
+&apos;&apos;&apos; A1 B2 C3 |__ C1
+&apos;&apos;&apos; A2 B3 C4 |__ C2
+&apos;&apos;&apos; A2 B3 C5 |__ B2
+&apos;&apos;&apos; A3 B4 C6 |__ C3
+&apos;&apos;&apos; |__ A2
+&apos;&apos;&apos; |__ B3
+&apos;&apos;&apos; |__ C4
+&apos;&apos;&apos; |__ C5
+&apos;&apos;&apos; |__ A3
+&apos;&apos;&apos; |__ B4
+&apos;&apos;&apos; |__ C6
+&apos;&apos;&apos; Typically, such an array can be issued by the GetRows method applied on the SFDatabases.Database service
+&apos;&apos;&apos; when an array item containing the text to be displayed is = &quot;&quot; or is empty/null,
+&apos;&apos;&apos; no new subnode is created and the remainder of the row is skipped
+&apos;&apos;&apos; When AddSubTree() is called from a Python script, FlatTree may be an array of arrays
+&apos;&apos;&apos; WithDataValue:
+&apos;&apos;&apos; When False (default), every column of FlatTree contains the text to be displayed in the tree control
+&apos;&apos;&apos; When True, the texts to be displayed (DisplayValue) are in columns 0, 2, 4, ...
+&apos;&apos;&apos; while the DataValues are in columns 1, 3, 5, ...
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myTree As Object, theRoot As Object, oDb As Object, vData As Variant
+&apos;&apos;&apos; Set myTree = myDialog.Controls(&quot;myTreeControl&quot;)
+&apos;&apos;&apos; Set theRoot = myTree.CreateRoot(&quot;By product category&quot;)
+&apos;&apos;&apos; Set oDb = CreateScriptService(&quot;SFDatabases.Database&quot;, &quot;/home/.../mydatabase.odb&quot;)
+&apos;&apos;&apos; vData = oDb.GetRows(&quot;SELECT [Category].[Name], [Category].[ID], [Product].[Name], [Product].[ID] &quot; _
+&apos;&apos;&apos; &amp; &quot;FROM [Category], [Product] WHERE [Product].[CategoryID] = [Category].[ID] &quot; _
+&apos;&apos;&apos; &amp; &quot;ORDER BY [Category].[Name], [Product].[Name]&quot;)
+&apos;&apos;&apos; myTree.AddSubTree(theRoot, vData, WithDataValue := True)
+
+Dim bSubTree As Boolean &apos; Return value
+Dim oNode As Object &apos; com.sun.star.awt.tree.XMutableTreeNode
+Dim oNewNode As Object &apos; com.sun.star.awt.tree.XMutableTreeNode
+Dim lChildCount As Long &apos; Number of children nodes of a parent node
+Dim iStep As Integer &apos; 1 when WithDataValue = False, 2 otherwise
+Dim iDims As Integer &apos; Number of dimensions of FlatTree
+Dim lMin1 As Long &apos; Lower bound (rows)
+Dim lMin2 As Long &apos; Lower bounds (cols)
+Dim lMax1 As Long &apos; Upper bound (rows)
+Dim lMax2 As Long &apos; Upper bounds (cols)
+Dim vFlatItem As Variant &apos; A single FlatTree item: FlatTree(i, j)
+Dim vFlatItem2 As Variant &apos; A single FlatTree item
+Dim bChange As Boolean &apos; When True, the item in FlatTree is different from the item above
+Dim sValue As String &apos; Alias for display values
+Dim i As Long, j As Long
+Const cstThisSub = &quot;SFDialogs.DialogControl.AddSubTree&quot;
+Const cstSubArgs = &quot;ParentNode, FlatTree, [WithDataValue=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSubTree = False
+
+Check:
+ If IsMissing(WithDataValue) Or IsEmpty(WithDataValue) Then WithDataValue = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If _ControlType &lt;&gt; CTLTREECONTROL Then GoTo CatchType
+ If Not ScriptForge.SF_Utils._Validate(ParentNode, &quot;ParentNode&quot;, V_OBJECT) Then GoTo Catch
+ If ScriptForge.SF_Session.UnoObjectType(ParentNode) &lt;&gt; &quot;toolkit.MutableTreeNode&quot; Then GoTo Catch
+ If Not ScriptForge.SF_Utils._ValidateArray(FlatTree, &quot;FlatTree&quot;) Then GoTo Catch &apos; Dimensions checked below
+ If Not ScriptForge.SF_Utils._Validate(WithDataValue, &quot;WithDataValue&quot;, V_BOOLEAN) Then GoTo Catch
+ End If
+
+Try:
+ With _TreeDataModel
+ &apos; Clean subtree
+ lChildCount = ParentNode.getChildCount()
+ For i = 1 To lChildCount
+ ParentNode.removeChildByIndex(0) &apos; This cleans all subtrees too
+ Next i
+
+ &apos; Determine bounds
+ iDims = ScriptForge.SF_Array.CountDims(FlatTree)
+ Select Case iDims
+ Case -1, 0 : GoTo Catch
+ Case 1 &apos; Called probably from Python
+ lMin1 = LBound(FlatTree, 1) : lMax1 = UBound(FlatTree, 1)
+ If Not IsArray(FlatTree(0)) Then GoTo Catch
+ If UBound(FlatTree(0)) &lt; LBound(FlatTree(0)) Then GoTo Catch &apos; No columns
+ lMin2 = LBound(FlatTree(0)) : lMax2 = UBound(FlatTree(0))
+ Case 2
+ lMin1 = LBound(FlatTree, 1) : lMax1 = UBound(FlatTree, 1)
+ lMin2 = LBound(FlatTree, 2) : lMax2 = UBound(FlatTree, 2)
+ Case Else : GoTo Catch
+ End Select
+
+ &apos; Build a new subtree
+ iStep = Iif(WithDataValue, 2, 1)
+ For i = lMin1 To lMax1
+ bChange = ( i = 0 )
+ &apos; Restart from the parent node at each i-iteration
+ Set oNode = ParentNode
+ For j = lMin2 To lMax2 Step iStep &apos; Array columns
+ If iDims = 1 Then vFlatItem = FlatTree(i)(j) Else vFlatItem = FlatTree(i, j)
+ If vFlatItem = &quot;&quot; Or IsNull(vFlatItem) Or IsEmpty(vFlatItem) Then
+ Set oNode = Nothing
+ Exit For &apos; Exit j-loop
+ End If
+ If Not bChange Then
+ If iDims = 1 Then vFlatItem2 = FlatTree(i - 1)(j) Else vFlatItem2 = FlatTree(i - 1, j)
+ bChange = ( vFlatItem &lt;&gt; vFlatItem2 )
+ End If
+ If bChange Then &apos; Create new subnode at tree depth = j
+ If VarType(vFlatItem) = V_STRING Then sValue = vFlatItem Else sValue = ScriptForge.SF_String.Represent(vFlatItem)
+ Set oNewNode = .createNode(sValue, True)
+ If WithDataValue Then
+ If iDims = 1 Then vFlatItem2 = FlatTree(i)(j + 1) Else vFlatItem2 = FlatTree(i, j + 1)
+ oNewNode.DataValue = vFlatItem2
+ End If
+ oNode.appendChild(oNewNode)
+ Set oNode = oNewNode
+ Else
+ &apos; Position next current node on last child of actual current node
+ lChildCount = oNode.getChildCount()
+ If lChildCount &gt; 0 Then Set oNode = oNode.getChildAt(lChildCount - 1) Else Set oNode = Nothing
+ End If
+ Next j
+ Next i
+ bSubTree = True
+ End With
+
+Finally:
+ AddSubTree = bSubTree
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ ScriptForge.SF_Exception.RaiseFatal(CONTROLTYPEERROR, _Name, _DialogName, _ControlType, &quot;AddSubTree&quot;)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl.AddSubTree
+
+REM -----------------------------------------------------------------------------
+Public Function CreateRoot(Optional ByVal DisplayValue As Variant _
+ , Optional ByRef DataValue As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return a new root node of the tree control. The new tree root is inserted below pre-existing root nodes
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DisplayValue: the text appearing in the control box
+&apos;&apos;&apos; DataValue: any value associated with the root node. Default = Empty
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The new root node as a UNO object of type com.sun.star.awt.tree.XMutableTreeNode
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myTree As Object, myNode As Object
+&apos;&apos;&apos; Set myTree = myDialog.Controls(&quot;myTreeControl&quot;)
+&apos;&apos;&apos; Set myNode = myTree.CreateRoot(&quot;Tree starts here ...&quot;)
+
+Dim oRoot As Object &apos; Return value
+Const cstThisSub = &quot;SFDialogs.DialogControl.CreateRoot&quot;
+Const cstSubArgs = &quot;DisplayValue, [DataValue=Empty]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oRoot = Nothing
+
+Check:
+ If IsMissing(DataValue) Then DataValue = Empty
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If _ControlType &lt;&gt; CTLTREECONTROL Then GoTo CatchType
+ If Not ScriptForge.SF_Utils._Validate(DisplayValue, &quot;DisplayValue&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ With _TreeDataModel
+ Set oRoot = .createNode(DisplayValue, True)
+ oRoot.DataValue = DataValue
+ .setRoot(oRoot)
+ &apos; To be visible, a root must have contained at least 1 child. Create a fictive one and erase it.
+ &apos; This behaviour does not seem related to the RootDisplayed property ??
+ oRoot.appendChild(.createNode(&quot;Something&quot;, False))
+ oRoot.removeChildByIndex(0)
+ End With
+
+Finally:
+ Set CreateRoot = oRoot
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ ScriptForge.SF_Exception.RaiseFatal(CONTROLTYPEERROR, _Name, _DialogName, _ControlType, &quot;CreateRoot&quot;)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl.CreateRoot
+
+REM -----------------------------------------------------------------------------
+Public Function FindNode(Optional ByVal DisplayValue As String _
+ , Optional ByRef DataValue As Variant _
+ , Optional ByVal CaseSensitive As Boolean _
+ ) As Object
+&apos;&apos;&apos; Traverses the tree and find recursively, starting from the root, a node meeting some criteria
+&apos;&apos;&apos; Either (1 match is enough):
+&apos;&apos;&apos; having its DisplayValue like DisplayValue
+&apos;&apos;&apos; having its DataValue = DataValue
+&apos;&apos;&apos; Comparisons may be or not case-sensitive
+&apos;&apos;&apos; The first matching occurrence is returned
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DisplayValue: the pattern to be matched
+&apos;&apos;&apos; DataValue: a string, a numeric value or a date or Empty (if not applicable)
+&apos;&apos;&apos; CaseSensitive: applicable on both criteria. Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The found node of type com.sun.star.awt.tree.XMutableTreeNode or Nothing if not found
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myTree As Object, myNode As Object
+&apos;&apos;&apos; Set myTree = myDialog.Controls(&quot;myTreeControl&quot;)
+&apos;&apos;&apos; Set myNode = myTree.FindNode(&quot;*Sophie*&quot;, CaseSensitive := True)
+
+
+Dim oNode As Object &apos; Return value
+Const cstThisSub = &quot;SFDialogs.DialogControl.FindNode&quot;
+Const cstSubArgs = &quot;[DisplayValue=&quot;&quot;&quot;&quot;], [DataValue=Empty], [CaseSensitive=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oNode = Nothing
+
+Check:
+ If IsMissing(DisplayValue) Or IsEmpty(DisplayValue) Then DisplayValue = &quot;&quot;
+ If IsMissing(DataValue) Then DataValue = Empty
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If _ControlType &lt;&gt; CTLTREECONTROL Then GoTo CatchType
+ If Not ScriptForge.SF_Utils._Validate(DisplayValue, &quot;DisplayValue&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ End If
+
+Try:
+ Set oNode = _FindNode(_TreeDataModel.getRoot(), DisplayValue, DataValue, CaseSensitive)
+
+Finally:
+ Set FindNode = oNode
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ ScriptForge.SF_Exception.RaiseFatal(CONTROLTYPEERROR, _Name, _DialogName, _ControlType, &quot;FindNode&quot;)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl.FindNode
+
+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;SFDialogs.DialogControl.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; SFDialogs.SF_DialogControl.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;AddSubNode&quot; _
+ , &quot;AddSubTree&quot; _
+ , &quot;CreateRoot&quot; _
+ , &quot;FindNode&quot; _
+ , &quot;SetFocus&quot; _
+ , &quot;WriteLine&quot; _
+ )
+
+End Function &apos; SFDialogs.SF_DialogControl.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;Cancel&quot; _
+ , &quot;Caption&quot; _
+ , &quot;ControlType&quot; _
+ , &quot;CurrentNode&quot; _
+ , &quot;Default&quot; _
+ , &quot;Enabled&quot; _
+ , &quot;Format&quot; _
+ , &quot;ListCount&quot; _
+ , &quot;ListIndex&quot; _
+ , &quot;Locked&quot; _
+ , &quot;MultiSelect&quot; _
+ , &quot;Name&quot; _
+ , &quot;OnActionPerformed&quot; _
+ , &quot;OnAdjustmentValueChanged&quot; _
+ , &quot;OnFocusGained&quot; _
+ , &quot;OnFocusLost&quot; _
+ , &quot;OnItemStateChanged&quot; _
+ , &quot;OnKeyPressed&quot; _
+ , &quot;OnKeyReleased&quot; _
+ , &quot;OnMouseDragged&quot; _
+ , &quot;OnMouseEntered&quot; _
+ , &quot;OnMouseExited&quot; _
+ , &quot;OnMouseMoved&quot; _
+ , &quot;OnMousePressed&quot; _
+ , &quot;OnMouseReleased&quot; _
+ , &quot;OnNodeExpanded&quot; _
+ , &quot;OnNodeSelected&quot; _
+ , &quot;OnTextChanged&quot; _
+ , &quot;Page&quot; _
+ , &quot;Parent&quot; _
+ , &quot;Picture&quot; _
+ , &quot;RootNode&quot; _
+ , &quot;RowSource&quot; _
+ , &quot;Text&quot; _
+ , &quot;TipText&quot; _
+ , &quot;TripleState&quot; _
+ , &quot;Value&quot; _
+ , &quot;Visible&quot; _
+ , &quot;XControlModel&quot; _
+ , &quot;XControlView&quot; _
+ , &quot;XGridColumnModel&quot; _
+ , &quot;XGridDataModel&quot; _
+ , &quot;XTreeDataModel&quot; _
+ )
+
+End Function &apos; SFDialogs.SF_DialogControl.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function SetFocus() As Boolean
+&apos;&apos;&apos; Set the focus on the current Control instance
+&apos;&apos;&apos; Probably called from after an event occurrence
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if focusing is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDlg As Object, oControl As Object
+&apos;&apos;&apos; Set oDlg = CreateScriptService(,, &quot;myControl&quot;) &apos; Control stored in current document&apos;s standard library
+&apos;&apos;&apos; Set oControl = oDlg.Controls(&quot;thisControl&quot;)
+&apos;&apos;&apos; oControl.SetFocus()
+
+Dim bSetFocus As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDialogs.DialogControl.SetFocus&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSetFocus = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+ End If
+
+Try:
+ If Not IsNull(_ControlView) Then
+ _ControlView.setFocus()
+ bSetFocus = True
+ End If
+
+Finally:
+ SetFocus = bSetFocus
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFControls.SF_DialogControl.SetFocus
+
+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;SFDialogs.DialogControl.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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function SetTableData(Optional ByRef DataArray As Variant _
+ , Optional ByRef Widths As Variant _
+ , Optional ByRef Alignments As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Fill a table control with the given data. Preexisting data is erased
+&apos;&apos;&apos; The Basic IDE allows to define if the control has a row and/or a column header
+&apos;&apos;&apos; When it is the case, the array in argument should contain those headers resp. in the first
+&apos;&apos;&apos; column and/or in the first row
+&apos;&apos;&apos; A column in the control shall be sortable when the data (headers excluded) in that column
+&apos;&apos;&apos; is homogeneously filled either with numbers or with strings
+&apos;&apos;&apos; Columns containing strings will be left-aligned, those with numbers will be right-aligned
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DataArray: the set of data to display in the table control, including optional column/row headers
+&apos;&apos;&apos; Is a 2D array in Basic, is a tuple of tuples when called from Python
+&apos;&apos;&apos; Widths: the column&apos;s relative widths as a 1D array, each element corresponding with a column
+&apos;&apos;&apos; If the array is shorter than the number of columns, the last value is kept for the next columns.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Widths := Array(1, 2)
+&apos;&apos;&apos; means that the first column is half as wide as all the other columns
+&apos;&apos;&apos; When the argument is absent, the columns are evenly spread over the control
+&apos;&apos;&apos; Alignments: the column&apos;s horizontal alignment as a string with length = number of columns.
+&apos;&apos;&apos; Possible characters are:
+&apos;&apos;&apos; L(EFT), C(ENTER), R(IGHT) or space (default behaviour)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myTable As Object, bSet As Boolean, vData As Variant
+&apos;&apos;&apos; Set myTable = myDialog.Controls(&quot;myTableControl&quot;) &apos; This control has only column headers
+&apos;&apos;&apos; vData = Array(&quot;Col1&quot;, &quot;Col2&quot;, &quot;Col3&quot;)
+&apos;&apos;&apos; vData = SF_Array.AppendRow(vData, Array(1, 2, 3))
+&apos;&apos;&apos; vData = SF_Array.AppendRow(vData, Array(4, 5, 6))
+&apos;&apos;&apos; vData = SF_Array.AppendRow(vData, Array(7, 8, 9))
+&apos;&apos;&apos; bSet = myTable.SetTableData(vData, Alignments := &quot; C &quot;)
+
+Dim bData As Boolean &apos; Return value
+Dim iDims As Integer &apos; Number of dimensions of DataArray
+Dim lMin1 As Long &apos; LBound1 of input array
+Dim lMax1 As Long &apos; UBound1 of input array
+Dim lMin2 As Long &apos; LBound2 of input array
+Dim lMax2 As Long &apos; UBound2 of input array
+Dim lControlWidth As Long &apos; Width of the table control
+Dim lMinW As Long &apos; lBound of Widths
+Dim lMaxW As Long &apos; UBound of vWidths
+Dim lMinRow As Long &apos; Row index of effective data subarray
+Dim lMinCol As Long &apos; Column index of effective data subarray
+Dim vRowHeaders As Variant &apos; Array of row headers
+Dim sRowHeader As String &apos; A single row header
+Dim vColHeaders As Variant &apos; Array of column headers
+Dim oColumn As Object &apos; com.sun.star.awt.grid.XGridColumn
+Dim dWidth As Double &apos; A single item of Widths
+Dim dRelativeWidth As Double &apos; Sum of Widths up to the number of columns
+Dim dWidthFactor As Double &apos; Factor to apply to relative widths to get absolute column widths
+Dim vDataRow As Variant &apos; A single row content in the tablecontrol
+Dim vDataItem As Variant &apos; A single DataArray item
+Dim sAlign As String &apos; Column&apos;s horizontal alignments (single chars: L, C, R, space)
+Dim lAlign As Long &apos; com.sun.star.style.HorizontalAlignment.XXX
+Dim i As Long, j As Long, k As Long
+
+Const cstRowHdrWidth = 12 &apos; Estimated width of the row header
+
+Const cstThisSub = &quot;SFDialogs.DialogControl.SetTableData&quot;
+Const cstSubArgs = &quot;DataArray, [Widths=Array(1)], [Alignments=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bData = False
+
+Check:
+ If IsMissing(Widths) Or IsEmpty(Widths) Then Widths = Array(1)
+ If IsMissing(Alignments) Or IsEmpty(Alignments) Then Alignments = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If _ControlType &lt;&gt; CTLTABLECONTROL Then GoTo CatchType
+ If Not ScriptForge.SF_Utils._ValidateArray(DataArray, &quot;DataArray&quot;) Then GoTo Catch &apos; Dimensions are checked below
+ If Not ScriptForge.SF_Utils._ValidateArray(Widths, &quot;Widths&quot;, 1, ScriptForge.V_NUMERIC, True) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Alignments, &quot;Alignments&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ &apos; Erase any pre-existing data and columns
+ _GridDataModel.removeAllRows()
+ For i = _GridColumnModel.ColumnCount - 1 To 0 Step -1
+ _GridColumnModel.removeColumn(i)
+ Next i
+
+ &apos; LBounds, UBounds - Basic or Pytho
+ iDims = ScriptForge.SF_Array.CountDims(DataArray)
+ Select Case iDims
+ Case -1, 0 : GoTo Catch
+ Case 1 &apos; Called probably from Python
+ lMin1 = LBound(DataArray, 1) : lMax1 = UBound(DataArray, 1)
+ If Not IsArray(DataArray(0)) Then GoTo Catch
+ If UBound(DataArray(0)) &lt; LBound(DataArray(0)) Then GoTo Catch &apos; No columns
+ lMin2 = LBound(DataArray(0)) : lMax2 = UBound(DataArray(0))
+ Case 2
+ lMin1 = LBound(DataArray, 1) : lMax1 = UBound(DataArray, 1)
+ lMin2 = LBound(DataArray, 2) : lMax2 = UBound(DataArray, 2)
+ Case Else : GoTo Catch
+ End Select
+
+ &apos; Extract headers from data array
+ lMinW = LBound(Widths) : lMaxW = UBound(Widths)
+ With _ControlModel
+ If .ShowColumnHeader Then
+ lMinRow = lMin1 + 1
+ If iDims = 1 Then
+ vColHeaders = DataArray(lMin1)
+ Else
+ vColHeaders = ScriptForge.SF_Array.ExtractRow(DataArray, lMin1)
+ End If
+ Else
+ lMinRow = lMin1
+ vColHeaders = Array()
+ End If
+ If .ShowRowHeader Then
+ lMinCol = lMin2 + 1
+ If iDims = 1 Then
+ vRowHeaders = Array()
+ ReDim vRowHeaders(lMin1 To lMax1)
+ For i = lMin1 To lMax1
+ vRowHeaders(i) = DataArray(i)(lMin2)
+ Next i
+ Else
+ vRowHeaders = ScriptForge.SF_Array.ExtractColumn(DataArray, lMin2)
+ End If
+ Else
+ lMinCol = lMin2
+ vRowHeaders = Array()
+ End If
+ End With
+
+ &apos; Create the columns
+ For j = lMinCol To lMax2
+ Set oColumn = _GridColumnModel.createColumn()
+ If _ControlModel.ShowColumnHeader Then oColumn.Title = vColHeaders(j)
+ _GridColumnModel.addColumn(oColumn)
+ Next j
+ &apos; Size the columns. Column sizing cannot be done before all the columns are added
+ If lMaxW &gt;= lMinW Then &apos; There must be at least 1 width given as argument
+ &apos; Size the columns proportionally with their relative widths
+ dRelativeWidth = 0.0
+ i = lMinW - 1
+ &apos; Compute the sum of the relative widths
+ For j = 0 To lMax2 - lMinCol
+ i = i + 1
+ If i &gt;= lMinW And i &lt;= lMaxW Then dRelativeWidth = dRelativeWidth + Widths(i) Else dRelativeWidth = dRelativeWidth + Widths(lMaxW)
+ Next j
+ &apos; Set absolute widths
+ If dRelativeWidth &gt; 0.0 Then dWidthFactor = CDbl((_ControlModel.Width - cstRowHdrWidth) / dRelativeWidth) Else dWidthFactor = 1.0
+ i = lMinW - 1
+ For j = 0 To lMax2 - lMinCol
+ i = i + 1
+ If i &gt;= lMinW And i &lt;= lMaxW Then dWidth = CDbl(Widths(i)) Else dWidth = CDbl(Widths(lMaxW))
+ _GridColumnModel.Columns(j).ColumnWidth = CLng(dWidthFactor * dWidth)
+ Next j
+ Else
+ &apos; Size all columns evenly
+ For j = 0 To lMax2 - lMinCol
+ _GridColumnModel.Columns(j).ColumnWidth = (_ControlModel.Width - cstRowHdrWidth) / (lMax2 - lMonCol + 1)
+ Next j
+ End If
+
+ &apos; Initialize the column alignment
+ If Len(Alignments) &gt;= lMax2 - lMinCol + 1 Then sAlign = Alignments Else sAlign = Alignments &amp; Space(lMax2 - lMinCol + 1 - Len(Alignments))
+
+ &apos; Feed the table with data and define/confirm the column alignment
+ vDataRow = Array()
+ For i = lMinRow To lMax1
+ ReDim vDataRow(0 To lMax2 - lMinCol)
+ For j = lMinCol To lMax2
+ If iDims = 1 Then vDataItem = DataArray(i)(j) Else vDataItem = DataArray(i, j)
+ If VarType(vDataItem) = V_STRING Then
+ ElseIf ScriptForge.SF_Utils._VarTypeExt(vDataItem) = ScriptForge.V_NUMERIC Then
+ Else
+ vDataItem = ScriptForge.SF_String.Represent(vDataItem)
+ End If
+ vDataRow(j - lMinCol) = vDataItem
+ &apos; Store alignment while processing the first row of the array
+ If i = lMinRow Then
+ k = j - lMinCol + 1
+ If Mid(sAlign, k, 1) = &quot; &quot; Then Mid(sAlign, k, 1) = Iif(VarType(vDataItem) = V_STRING, &quot;L&quot;, &quot;R&quot;)
+ End If
+ Next j
+ If _ControlModel.ShowRowHeader Then sRowHeader = vRowHeaders(i) Else sRowHeader = &quot;&quot;
+ _GridDataModel.addRow(sRowHeader, vDataRow)
+ Next i
+
+ &apos; Determine alignments of each column
+ For j = 0 To lMax2 - lMinCol
+ Select Case Mid(sAlign, j + 1, 1)
+ Case &quot;L&quot;, &quot; &quot; : lAlign = com.sun.star.style.HorizontalAlignment.LEFT
+ Case &quot;R&quot; : lAlign = com.sun.star.style.HorizontalAlignment.RIGHT
+ Case &quot;C&quot; : lAlign = com.sun.star.style.HorizontalAlignment.CENTER
+ Case Else
+ End Select
+ _GridColumnModel.Columns(j).HorizontalAlign = lAlign
+ Next j
+
+ bData = True
+
+Finally:
+ SetTableData = bData
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ ScriptForge.SF_Exception.RaiseFatal(CONTROLTYPEERROR, _Name, _DialogName, _ControlType, &quot;SetTableData&quot;)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl.SetTableData
+
+REM -----------------------------------------------------------------------------
+Public Function WriteLine(Optional ByVal Line As Variant) As Boolean
+&apos;&apos;&apos; Add a new line to a multiline TextField control
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Line: (default = &quot;&quot;) the line to insert at the end of the text box
+&apos;&apos;&apos; a newline character will be inserted before the line, if relevant
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if insertion is successful
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; TEXTFIELDERROR Method applicable on multiline text fields only
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDlg As Object, oControl As Object
+&apos;&apos;&apos; Set oDlg = CreateScriptService(,, &quot;myControl&quot;) &apos; Control stored in current document&apos;s standard library
+&apos;&apos;&apos; Set oControl = oDlg.Controls(&quot;thisControl&quot;)
+&apos;&apos;&apos; oControl.WriteLine(&quot;a new line&quot;)
+
+Dim bWriteLine As Boolean &apos; Return value
+Dim lTextLength As Long &apos; Actual length of text in box
+Dim oSelection As New com.sun.star.awt.Selection
+Dim sNewLine As String &apos; Newline character(s)
+Const cstThisSub = &quot;SFDialogs.DialogControl.WriteLine&quot;
+Const cstSubArgs = &quot;[Line=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bWriteLine = False
+
+Check:
+ If IsMissing(Line) Or IsEmpty(Line) Then Line = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Line, &quot;Line&quot;, V_STRING) Then GoTo Finally
+ End If
+ If ControlType &lt;&gt; CTLTEXTFIELD Then GoTo CatchField
+ If _ControlModel.MultiLine = False Then GoTo CatchField
+
+Try:
+ _ControlModel.HardLineBreaks = True
+ sNewLine = ScriptForge.SF_String.sfNEWLINE
+ With _ControlView
+ lTextLength = Len(.getText())
+ If lTextLength = 0 Then &apos; Text field is still empty
+ oSelection.Min = 0 : oSelection.Max = 0
+ .setText(Line)
+ Else &apos; Put cursor at the end of the actual text
+ oSelection.Min = lTextLength : oSelection.Max = lTextLength
+ .insertText(oSelection, sNewLine &amp; Line)
+ End If
+ &apos; Put the cursor at the end of the inserted text
+ oSelection.Max = oSelection.Max + Len(sNewLine) + Len(Line)
+ oSelection.Min = oSelection.Max
+ .setSelection(oSelection)
+ End With
+ bWriteLine = True
+
+Finally:
+ WriteLine = bWriteLine
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchField:
+ ScriptForge.SF_Exception.RaiseFatal(TEXTFIELDERROR, _Name, _DialogName)
+ GoTo Finally
+End Function &apos; SFControls.SF_DialogControl.WriteLine
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _FindNode(ByRef poNode As Object _
+ , ByVal psDisplayValue As String _
+ , ByRef pvDataValue As Variant _
+ , ByVal pbCaseSensitive As Boolean _
+ ) As Object
+&apos;&apos;&apos; Traverses the tree and find recursively, starting from the root, a node meeting some criteria
+&apos;&apos;&apos; Either (1 match is enough):
+&apos;&apos;&apos; having its DisplayValue like psDisplayValue
+&apos;&apos;&apos; having its DataValue = pvDataValue
+&apos;&apos;&apos; Comparisons may be or not case-sensitive
+&apos;&apos;&apos; The first matching occurrence is returned
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poNode: the current node, the root at 1st call
+&apos;&apos;&apos; psDisplayValue: the pattern to be matched
+&apos;&apos;&apos; pvDataValue: a string, a numeric value or a date or Empty (if not applicable)
+&apos;&apos;&apos; pbCaseSensitive: applicable on both criteria
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The found node of type com.sun.star.awt.tree.XMutableTreeNode
+
+Dim oChild As Object &apos; Child node com.sun.star.awt.tree.XMutableTreeNode
+Dim oFind As Object &apos; Found node com.sun.star.awt.tree.XMutableTreeNode
+Dim lChildCount As Long &apos; Number of children of a node
+Dim bFound As Boolean &apos; True when node found
+Dim i As Long
+
+ Set _FindNode = Nothing
+ On Local Error GoTo Finally &apos; Better not found than raise an error
+
+Check:
+ &apos; Does the actual node match the criteria ?
+ bFound = False
+ If Len(psDisplayValue) &gt; 0 Then
+ bFound = ScriptForge.SF_String.IsLike(poNode.DisplayValue, psDisplayValue, pbCaseSensitive)
+ End If
+ If Not bFound And Not IsEmpty(poNode.DataValue) Then
+ If Not IsEmpty(pvdataValue) Then bFound = ( ScriptForge.SF_Array._ValCompare(poNode.DataValue, pvDataB-Value, pbCaseSensitive) = 0 )
+ End If
+ If bFound Then
+ Set _FindNode = poNode
+ Exit Function
+ End If
+
+Try:
+ &apos; Explore sub-branches
+ lChildCount = poNode.getChildCount
+ If lChildCount &gt; 0 Then
+ For i = 0 To lChildCount - 1
+ Set oChild = poNode.getChildAt(i)
+ Set oFind = _FindNode(oChild, psDisplayValue, pvDataValue, pbCaseSensitive) &apos; Recursive call
+ If Not IsNull(oFind) Then
+ Set _FindNode = oFind
+ Exit For
+ End If
+ Next i
+ End If
+
+Finally:
+ Exit Function
+End Function &apos; SFDialogs.SF_DialogControl._FindNode
+
+REM -----------------------------------------------------------------------------
+Private Function _FormatsList() As Variant
+&apos;&apos;&apos; Return the allowed format entries as a zero-based array for Date and Time control types
+
+Dim vFormats() As Variant &apos; Return value
+
+ Select Case _ControlType
+ Case CTLDATEFIELD
+ vFormats = Array( _
+ &quot;Standard (short)&quot; _
+ , &quot;Standard (short YY)&quot; _
+ , &quot;Standard (short YYYY)&quot; _
+ , &quot;Standard (long)&quot; _
+ , &quot;DD/MM/YY&quot; _
+ , &quot;MM/DD/YY&quot; _
+ , &quot;YY/MM/DD&quot; _
+ , &quot;DD/MM/YYYY&quot; _
+ , &quot;MM/DD/YYYY&quot; _
+ , &quot;YYYY/MM/DD&quot; _
+ , &quot;YY-MM-DD&quot; _
+ , &quot;YYYY-MM-DD&quot; _
+ )
+ Case CTLTIMEFIELD
+ vFormats = Array( _
+ &quot;24h short&quot; _
+ , &quot;24h long&quot; _
+ , &quot;12h short&quot; _
+ , &quot;12h long&quot; _
+ )
+ Case Else
+ vFormats = Array()
+ End Select
+
+ _FormatsList = vFormats
+
+End Function &apos; SFDialogs.SF_DialogControl._FormatsList
+
+REM -----------------------------------------------------------------------------
+Public Function _GetEventName(ByVal psProperty As String) As String
+&apos;&apos;&apos; Return the LO internal event name derived from the SF property name
+&apos;&apos;&apos; The SF property name is not case sensitive, while the LO name is case-sensitive
+&apos; Corrects the typo on ErrorOccur(r?)ed, if necessary
+
+Dim vProperties As Variant &apos; Array of class properties
+Dim sProperty As String &apos; Correctly cased property name
+
+ vProperties = Properties()
+ sProperty = vProperties(ScriptForge.SF_Array.IndexOf(vProperties, psProperty, SortOrder := &quot;ASC&quot;))
+
+ _GetEventName = LCase(Mid(sProperty, 3, 1)) &amp; Right(sProperty, Len(sProperty) - 3)
+
+End Function &apos; SFDialogs.SF_DialogControl._GetEventName
+
+REM -----------------------------------------------------------------------------
+Private Function _GetListener(ByVal psEventName As String) As String
+&apos;&apos;&apos; Getting/Setting macros triggered by events requires a Listener-EventName pair
+&apos;&apos;&apos; Return the X...Listener corresponding with the event name in argument
+
+ Select Case UCase(psEventName)
+ Case UCase(&quot;OnActionPerformed&quot;)
+ _GetListener = &quot;XActionListener&quot;
+ Case UCase(&quot;OnAdjustmentValueChanged&quot;)
+ _GetListener = &quot;XAdjustmentListener&quot;
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;)
+ _GetListener = &quot;XFocusListener&quot;
+ Case UCase(&quot;OnItemStateChanged&quot;)
+ _GetListener = &quot;XItemListener&quot;
+ Case UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;)
+ _GetListener = &quot;XKeyListener&quot;
+ Case UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseMoved&quot;)
+ _GetListener = &quot;XMouseMotionListener&quot;
+ Case UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ _GetListener = &quot;XMouseListener&quot;
+ Case UCase(&quot;OnTextChanged&quot;)
+ _GetListener = &quot;XTextListener&quot;
+ Case Else
+ _GetListener = &quot;&quot;
+ End Select
+
+End Function &apos; SFDialogs.SF_DialogControl._GetListener
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos;&apos;&apos; Complete the object creation process:
+&apos;&apos;&apos; - Initialization of private members
+&apos;&apos;&apos; - Collection of specific attributes
+&apos;&apos;&apos; - synchronization with parent dialog instance
+
+Dim vServiceName As Variant &apos; Split service name
+Dim sType As String &apos; Last component of service name
+
+Try:
+ _ImplementationName = _ControlModel.getImplementationName()
+
+ &apos; Identify the control type
+ vServiceName = Split(_ControlModel.getServiceName(), &quot;.&quot;)
+ sType = vServiceName(UBound(vServiceName))
+ Select Case sType
+ Case &quot;UnoControlSpinButtonModel&quot;
+ _ControlType = &quot;&quot; &apos; Not supported
+ Case &quot;Edit&quot; : _ControlType = CTLTEXTFIELD
+ Case &quot;TreeControlModel&quot;
+ &apos; Initialize the data model
+ _ControlType = CTLTREECONTROL
+ Set _ControlModel.DataModel = CreateUnoService(&quot;com.sun.star.awt.tree.MutableTreeDataModel&quot;)
+ Set _TreeDataModel = _ControlModel.DataModel
+ Case &quot;UnoControlGridModel&quot;
+ _ControlType = CTLTABLECONTROL
+ Set _GridColumnModel = _ControlModel.ColumnModel
+ Set _GridDataModel = _ControlModel.GridDataModel
+ Case Else : _ControlType = sType
+ End Select
+
+ &apos; Store the SF_DialogControl object in the parent cache
+ Set _Parent._ControlCache(_IndexOfNames) = [Me]
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDialogs.SF_DialogControl._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String _
+ , Optional ByVal pvDefault 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
+&apos;&apos;&apos; pvDefault: the value returned when the property is not applicable on the control&apos;s type
+&apos;&apos;&apos; Getting a non-existing property for a specific control type should
+&apos;&apos;&apos; not generate an error to not disrupt the Basic IDE debugger
+
+Dim vGet As Variant &apos; Return value
+Static oSession As Object &apos; Alias of SF_Session
+Dim vSelection As Variant &apos; Alias of Model.SelectedItems or Model.Selection
+Dim vList As Variant &apos; Alias of Model.StringItemList
+Dim lIndex As Long &apos; Index in StringItemList
+Dim sItem As String &apos; A single item
+Dim vDate As Variant &apos; com.sun.star.util.Date or com.sun.star.util.Time
+Dim vValues As Variant &apos; Array of listbox values
+Dim oControlEvents As Object &apos; com.sun.star.container.XNameContainer
+Dim sEventName As String &apos; Internal event name
+Dim i As Long
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDialogs.DialogControl.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+
+ If IsMissing(pvDefault) Then pvDefault = Null
+ _PropertyGet = pvDefault
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Cancel&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;PushButtonType&quot;) Then _PropertyGet = ( _ControlModel.PushButtonType = com.sun.star.awt.PushButtonType.CANCEL )
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Caption&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLCHECKBOX, CTLFIXEDLINE, CTLFIXEDTEXT, CTLGROUPBOX, CTLRADIOBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;Label&quot;) Then _PropertyGet = _ControlModel.Label
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ControlType&quot;)
+ _PropertyGet = _ControlType
+ Case UCase(&quot;CurrentNode&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ If oSession.HasUNOMethod(_ControlView, &quot;getSelection&quot;) Then
+ _PropertyGet = Empty
+ If _ControlModel.SelectionType &lt;&gt; com.sun.star.view.SelectionType.NONE Then
+ vSelection = _ControlView.getSelection()
+ If IsArray(vSelection) Then
+ If UBound(vSelection) &gt;= 0 Then Set _PropertyGet = vSelection(0)
+ Else
+ Set _PropertyGet = vSelection
+ End If
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Default&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultButton&quot;) Then _PropertyGet = _ControlModel.DefaultButton
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Enabled&quot;)
+ If oSession.HasUnoProperty(_ControlModel, &quot;Enabled&quot;) Then _PropertyGet = _ControlModel.Enabled
+ Case UCase(&quot;Format&quot;)
+ Select Case _ControlType
+ Case CTLDATEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DateFormat&quot;) Then _PropertyGet = _FormatsList()(_ControlModel.DateFormat)
+ Case CTLTIMEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;TimeFormat&quot;) Then _PropertyGet = _FormatsList()(_ControlModel.TimeFormat)
+ Case CTLFORMATTEDFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;FormatsSupplier&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;FormatKey&quot;) Then
+ _PropertyGet = _ControlModel.FormatsSupplier.getNumberFormats.getByKey(_ControlModel.FormatKey).FormatString
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListCount&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then _PropertyGet = UBound(_ControlModel.StringItemList) + 1
+ Case CTLTABLECONTROL &apos; Returns zero when no table data yet
+ If oSession.HasUNOProperty(_GridDataModel, &quot;RowCount&quot;) Then _PropertyGet = _GridDataModel.RowCount
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListIndex&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX
+ _PropertyGet = -1 &apos; Not found, multiselection
+ If oSession.HasUNOProperty(_ControlModel, &quot;Text&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ _PropertyGet = ScriptForge.SF_Array.IndexOf(_ControlModel.StringItemList, _ControlModel.Text, CaseSensitive := True)
+ End If
+ Case CTLLISTBOX
+ _PropertyGet = -1 &apos; Not found, multiselection
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectedItems&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ vSelection = _ControlModel.SelectedItems
+ If UBound(vSelection) &gt;= 0 Then _PropertyGet = vSelection(0)
+ End If
+ Case CTLTABLECONTROL
+ _PropertyGet = -1 &apos; No row selected, no data, multiselection
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectionModel&quot;) _
+ And oSession.HasUNOProperty(_ControlView, &quot;CurrentRow&quot;) Then
+ &apos; Other selection types (multi, range) not supported
+ If _ControlModel.SelectionModel = com.sun.star.view.SelectionType.SINGLE Then
+ lIndex = _ControlView.CurrentRow
+ If lIndex &lt; 0 And oSession.HasUNOProperty(_ControlView, &quot;SelectedRows&quot;) Then
+ If UBound(_ControlView.SelectedRows) &gt;= 0 Then lIndex = _ControlView.SelectedRows(0)
+ End If
+ _PropertyGet = lIndex
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Locked&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLCURRENCYFIELD, CTLDATEFIELD, CTLFILECONTROL, CTLFORMATTEDFIELD, CTLLISTBOX _
+ , CTLNUMERICFIELD, CTLPATTERNFIELD, CTLTEXTFIELD, CTLTIMEFIELD
+ If oSession.HasUnoProperty(_ControlModel, &quot;ReadOnly&quot;) Then _PropertyGet = _ControlModel.ReadOnly
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;MultiSelect&quot;)
+ Select Case _ControlType
+ Case CTLLISTBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then
+ _PropertyGet = _ControlModel.MultiSelection
+ ElseIf oSession.HasUnoProperty(_ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then &apos; Not documented: gridcontrols only TBC ??
+ _PropertyGet = _ControlModel.MultiSelectionSimpleMode
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;OnActionPerformed&quot;), UCase(&quot;OnAdjustmentValueChanged&quot;), UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;) _
+ , UCase(&quot;OnItemStateChanged&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;), UCase(&quot;OnTextChanged&quot;)
+ Set oControlEvents = _ControlModel.getEvents()
+ sEventName = &quot;com.sun.star.awt.&quot; &amp; _GetListener(psProperty) &amp; &quot;::&quot; &amp; _GetEventName(psProperty)
+ If oControlEvents.hasByName(sEventName) Then
+ _PropertyGet = oControlEvents.getByName(sEventName).ScriptCode
+ Else
+ _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;OnNodeExpanded&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ _PropertyGet = _OnNodeExpanded
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;OnNodeSelected&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ _PropertyGet = _OnNodeSelected
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Page&quot;)
+ If oSession.HasUnoProperty(_ControlModel, &quot;Step&quot;) Then _PropertyGet = _ControlModel.Step
+ Case UCase(&quot;Parent&quot;)
+ Set _PropertyGet = [_Parent]
+ Case UCase(&quot;Picture&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLIMAGECONTROL
+ If oSession.HasUnoProperty(_ControlModel, &quot;ImageURL&quot;) Then _PropertyGet = ScriptForge.SF_FileSystem._ConvertFromUrl(_ControlModel.ImageURL)
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;RootNode&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ _PropertyGet = _TreeDataModel.getRoot()
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;RowSource&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ If IsArray(_ControlModel.StringItemList) Then _PropertyGet = _ControlModel.StringItemList Else _PropertyGet = Array(_ControlModel.StringItemList)
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Text&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLFORMATTEDFIELD, CTLPATTERNFIELD, CTLTEXTFIELD
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then _PropertyGet = _ControlModel.Text
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;TipText&quot;)
+ If oSession.HasUnoProperty(_ControlModel, &quot;HelpText&quot;) Then _PropertyGet = _ControlModel.HelpText
+ Case UCase(&quot;TripleState&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;TriState&quot;) Then _PropertyGet = _ControlModel.TriState
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Value&quot;) &apos; Default values are set here by control type, not in the 2nd argument
+ vGet = pvDefault
+ Select Case _ControlType
+ Case CTLBUTTON &apos;Boolean, toggle buttons only
+ vGet = False
+ If oSession.HasUnoProperty(_ControlModel, &quot;Toggle&quot;) Then
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then vGet = ( _ControlModel.State = 1 )
+ End If
+ Case CTLCHECKBOX &apos;0 = Not checked, 1 = Checked, 2 = Don&apos;t know
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then vGet = _ControlModel.State Else vGet = 2
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD &apos;String
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then vGet = _ControlModel.Text Else vGet = &quot;&quot;
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD &apos;Numeric
+ If oSession.HasUnoProperty(_ControlModel, &quot;Value&quot;) Then vGet = _ControlModel.Value Else vGet = 0
+ Case CTLDATEFIELD &apos;Date
+ vGet = CDate(1)
+ If oSession.HasUnoProperty(_ControlModel, &quot;Date&quot;) Then
+ If VarType(_ControlModel.Date) = ScriptForge.V_OBJECT Then &apos; com.sun.star.util.Date
+ Set vDate = _ControlModel.Date
+ vGet = DateSerial(vDate.Year, vDate.Month, vDate.Day)
+ End If
+ End If
+ Case CTLFORMATTEDFIELD &apos;String or numeric
+ If oSession.HasUnoProperty(_ControlModel, &quot;EffectiveValue&quot;) Then vGet = _ControlModel.EffectiveValue Else vGet = &quot;&quot;
+ Case CTLLISTBOX &apos;String or array of strings depending on MultiSelection
+ &apos; StringItemList is the list of the items displayed in the box
+ &apos; SelectedItems is the list of the indexes in StringItemList of the selected items
+ &apos; It can go beyond the limits of StringItemList
+ &apos; It can contain multiple values even if the listbox is not multiselect
+ If oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;SelectedItems&quot;) _
+ And oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then
+ vSelection = _ControlModel.SelectedItems
+ vList = _ControlModel.StringItemList
+ If _ControlModel.MultiSelection Then vValues = Array()
+ For i = 0 To UBound(vSelection)
+ lIndex = vSelection(i)
+ If lIndex &gt;= 0 And lIndex &lt;= UBound(vList) Then
+ If Not _ControlModel.MultiSelection Then
+ vValues = vList(lIndex)
+ Exit For
+ End If
+ vValues = ScriptForge.SF_Array.Append(vValues, vList(lIndex))
+ End If
+ Next i
+ vGet = vValues
+ Else
+ vGet = &quot;&quot;
+ End If
+ Case CTLPROGRESSBAR &apos;Numeric
+ If oSession.HasUnoProperty(_ControlModel, &quot;ProgressValue&quot;) Then vGet = _ControlModel.ProgressValue Else vGet = 0
+ Case CTLRADIOBUTTON &apos;Boolean
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then vGet = ( _ControlModel.State = 1 ) Else vGet = False
+ Case CTLSCROLLBAR &apos;Numeric
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValue&quot;) Then vGet = _ControlModel.ScrollValue Else vGet = 0
+ Case CTLTABLECONTROL
+ vGet = Array() &apos; Default value when no row selected, no data, multiselection
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectionModel&quot;) _
+ And oSession.HasUNOProperty(_ControlView, &quot;CurrentRow&quot;) Then
+ &apos; Other selection types (multi, range) not supported
+ If _ControlModel.SelectionModel = com.sun.star.view.SelectionType.SINGLE Then
+ lIndex = _ControlView.CurrentRow
+ If lIndex &lt; 0 And oSession.HasUNOProperty(_ControlView, &quot;SelectedRows&quot;) Then
+ If UBound(_ControlView.SelectedRows) &gt;= 0 Then lIndex = _ControlView.SelectedRows(0)
+ End If
+ If lIndex &gt;= 0 Then vGet = _GridDataModel.getRowData(lIndex)
+ End If
+ End If
+ Case CTLTIMEFIELD
+ vGet = CDate(0)
+ If oSession.HasUnoProperty(_ControlModel, &quot;Time&quot;) Then
+ If VarType(_ControlModel.Time) = ScriptForge.V_OBJECT Then &apos; com.sun.star.Util.Time
+ Set vDate = _ControlModel.Time
+ vGet = TimeSerial(vDate.Hours, vDate.Minutes, vDate.Seconds)
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ _PropertyGet = vGet
+ Case UCase(&quot;Visible&quot;)
+ If oSession.HasUnoMethod(_ControlView, &quot;isVisible&quot;) Then _PropertyGet = CBool(_ControlView.isVisible())
+ Case UCase(&quot;XControlModel&quot;)
+ Set _PropertyGet = _ControlModel
+ Case UCase(&quot;XControlView&quot;)
+ Set _PropertyGet = _ControlView
+ Case UCase(&quot;XGridColumnModel&quot;)
+ Set _PropertyGet = _GridColumnModel
+ Case UCase(&quot;XGridDataModel&quot;)
+ Set _PropertyGet = _GridDataModel
+ Case UCase(&quot;XTreeDataModel&quot;)
+ Set _PropertyGet = _TreeDataModel
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(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
+
+Dim bSet As Boolean &apos; Return value
+Static oSession As Object &apos; Alias of SF_Session
+Dim vSet As Variant &apos; Value to set in UNO model or view property
+Dim vFormats As Variant &apos; Format property: output of _FormatsList()
+Dim iFormat As Integer &apos; Format property: index in vFormats
+Dim vSelection As Variant &apos; Alias of Model.SelectedItems
+Dim vList As Variant &apos; Alias of Model.StringItemList
+Dim lIndex As Long &apos; Index in StringItemList
+Dim sItem As String &apos; A single item
+Dim vCtlTypes As Variant &apos; Array of allowed control types
+Dim i As Long
+Dim cstThisSub As String
+Const cstSubArgs = &quot;Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSet = False
+
+ cstThisSub = &quot;SFDialogs.DialogControl.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Cancel&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Cancel&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUNOProperty(_ControlModel, &quot;PushButtonType&quot;) Then
+ If pvValue Then vSet = com.sun.star.awt.PushButtonType.CANCEL Else vSet = com.sun.star.awt.PushButtonType.STANDARD
+ _ControlModel.PushButtonType = vSet
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Caption&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLCHECKBOX, CTLFIXEDLINE, CTLFIXEDTEXT, CTLGROUPBOX, CTLRADIOBUTTON
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Caption&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUNOProperty(_ControlModel, &quot;Label&quot;) Then _ControlModel.Label = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;CurrentNode&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Selection&quot;, ScriptForge.V_OBJECT) Then GoTo Finally
+ If oSession.UnoObjectType(pvValue) &lt;&gt; &quot;toolkit.MutableTreeNode&quot; Then GoTo CatchType
+ With _ControlView
+ .clearSelection()
+ If Not IsNull(pvValue) Then
+ .addSelection(pvValue)
+ &apos; Suspending temporarily the expansion listener avoids conflicts
+ If Len(_OnNodeExpanded) &gt; 0 Then _ControlView.removeTreeExpansionListener(_ExpandListener)
+ .makeNodeVisible(pvValue) &apos; Expand parent nodes and put node in the display area
+ If Len(_OnNodeExpanded) &gt; 0 Then _ControlView.addTreeExpansionListener(_ExpandListener)
+ End If
+ End With
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Default&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Default&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultButton&quot;) Then _ControlModel.DefaultButton = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Enabled&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Enabled&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Enabled&quot;) Then _ControlModel.Enabled = pvValue
+ Case UCase(&quot;Format&quot;)
+ Select Case _ControlType
+ Case CTLDATEFIELD, CTLTIMEFIELD
+ vFormats = _FormatsList()
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Format&quot;, V_STRING, vFormats) Then GoTo Finally
+ iFormat = ScriptForge.SF_Array.IndexOf(vFormats, pvValue, CaseSensitive := False)
+ If oSession.HasUNOProperty(_ControlModel, &quot;DateFormat&quot;) Then
+ _ControlModel.DateFormat = iFormat
+ ElseIf oSession.HasUNOProperty(_ControlModel, &quot;TimeFormat&quot;) Then
+ _ControlModel.TimeFormat = iFormat
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListIndex&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;ListIndex&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ Select Case _ControlType
+ Case CTLCOMBOBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;Text&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ _ControlModel.Text = _ControlModel.StringItemList(CInt(pvValue))
+ End If
+ Case CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectedItems&quot;) Then _ControlModel.SelectedItems = Array(CInt(pvValue))
+ Case CTLTABLECONTROL
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectionModel&quot;) _
+ And oSession.HasUNOMethod(_ControlView, &quot;selectRow&quot;) Then
+ &apos; Other selection types (multi, range) not supported
+ If _ControlModel.SelectionModel = com.sun.star.view.SelectionType.SINGLE _
+ And pvValue &gt;= 0 And pvValue &lt;= _GridDataModel.RowCount - 1 Then
+ _ControlView.selectRow(pvValue)
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Locked&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLCURRENCYFIELD, CTLDATEFIELD, CTLFILECONTROL, CTLFORMATTEDFIELD, CTLLISTBOX _
+ , CTLNUMERICFIELD, CTLPATTERNFIELD, CTLTEXTFIELD, CTLTIMEFIELD
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Locked&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ReadOnly&quot;) Then _ControlModel.ReadOnly = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;MultiSelect&quot;)
+ Select Case _ControlType
+ Case CTLLISTBOX
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;MultiSelect&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then _ControlModel.MultiSelection = pvValue
+ If oSession.HasUnoProperty(_ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then _ControlModel.MultiSelectionSimpleMode = pvValue
+ If oSession.HasUnoProperty(_ControlModel, &quot;SelectedItems&quot;) Then
+ If Not pvValue And UBound(_ControlModel.SelectedItems) &gt; 0 Then &apos; Cancel selections when MultiSelect becomes False
+ lIndex = _ControlModel.SelectedItems(0)
+ _ControlModel.SelectedItems = Array(lIndex)
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;OnNodeExpanded&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ If Not ScriptForge.SF_Utils._Validate(pvValue, psProperty, V_STRING) Then GoTo Finally
+ &apos; If the listener was already set, then stop it
+ If Len(_OnNodeExpanded) &gt; 0 Then
+ _ControlView.removeTreeExpansionListener(_ExpandListener)
+ Set _ExpandListener = Nothing
+ _OnNodeExpanded = &quot;&quot;
+ End If
+ &apos; Setup a new fresh listener
+ If Len(pvValue) &gt; 0 Then
+ Set _ExpandListener = CreateUnoListener(&quot;_SFEXP_&quot;, &quot;com.sun.star.awt.tree.XTreeExpansionListener&quot;)
+ _ControlView.addTreeExpansionListener(_ExpandListener)
+ _OnNodeExpanded = pvValue
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;OnNodeSelected&quot;)
+ Select Case _ControlType
+ Case CTLTREECONTROL
+ If Not ScriptForge.SF_Utils._Validate(pvValue, psProperty, V_STRING) Then GoTo Finally
+ &apos; If the listener was already set, then stop it
+ If Len(_OnNodeSelected) &gt; 0 Then
+ _ControlView.removeSelectionChangeListener(_SelectListener)
+ Set _SelectListener = Nothing
+ _OnNodeSelected = &quot;&quot;
+ End If
+ &apos; Setup a new fresh listener
+ If Len(pvValue) &gt; 0 Then
+ Set _SelectListener = CreateUnoListener(&quot;_SFSEL_&quot;, &quot;com.sun.star.view.XSelectionChangeListener&quot;)
+ _ControlView.addSelectionChangeListener(_SelectListener)
+ _OnNodeSelected = pvValue
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Page&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Page&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Step&quot;) Then _ControlModel.Step = CLng(pvValue)
+ Case UCase(&quot;Picture&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLIMAGECONTROL
+ If Not ScriptForge.SF_Utils._ValidateFile(pvValue, &quot;Picture&quot;) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ImageURL&quot;) Then _ControlModel.ImageURL = ScriptForge.SF_FileSystem._ConvertToUrl(pvValue)
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;RowSource&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If Not IsArray(pvValue) Then
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;RowSource&quot;, V_STRING) Then GoTo Finally
+ pvArray = Array(pvArray)
+ ElseIf Not ScriptForge.SF_Utils._ValidateArray(pvValue, &quot;RowSource&quot;, 1, V_STRING, True) Then
+ GoTo Finally
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) Then _ControlModel.StringItemList = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;TipText&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;TipText&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;HelpText&quot;) Then _ControlModel.HelpText = pvValue
+ Case UCase(&quot;TripleState&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;TripleState&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;TriState&quot;) Then _ControlModel.TriState = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Value&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON &apos;Boolean, toggle buttons only
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Toggle&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then
+ _ControlModel.State = Iif(pvValue, 1, 0)
+ End If
+ Case CTLCHECKBOX &apos;0 = Not checked, 1 = Checked, 2 = Don&apos;t know
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, Array(ScriptForge.V_BOOLEAN, ScriptForge.V_NUMERIC), Array(0, 1, 2, True, False)) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then
+ If VarType(pvValue) = ScriptForge.V_BOOLEAN Then pvValue = Iif(pvValue, 1, 0)
+ _ControlModel.State = pvValue
+ End If
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD &apos;String
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then _ControlModel.Text = pvValue
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD &apos;Numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Value&quot;) Then _ControlModel.Value = pvValue
+ Case CTLDATEFIELD &apos;Date
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_DATE) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Date&quot;) Then
+ Set vSet = New com.sun.star.util.Date
+ vSet.Year = Year(pvValue)
+ vSet.Month = Month(pvValue)
+ vSet.Day = Day(pvValue)
+ _ControlModel.Date = vSet
+ End If
+ Case CTLFORMATTEDFIELD &apos;String or numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;EffectiveValue&quot;) Then _ControlModel.EffectiveValue = pvValue
+ Case CTLLISTBOX &apos;String or array of strings depending on MultiSelection
+ &apos; StringItemList is the list of the items displayed in the box
+ &apos; SelectedItems is the list of the indexes in StringItemList of the selected items
+ &apos; It can go beyond the limits of StringItemList
+ &apos; It can contain multiple values even if the listbox is not multiselect
+ If oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;SelectedItems&quot;) _
+ And oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then
+ vSelection = Array()
+ If _ControlModel.MultiSelection Then
+ If Not ScriptForge.SF_Utils._ValidateArray(pvValue, &quot;Value&quot;, 1, V_STRING, True) Then GoTo Finally
+ vList = _ControlModel.StringItemList
+ For i = LBound(pvValue) To UBound(pvValue)
+ sItem = pvValue(i)
+ lIndex = ScriptForge.SF_Array.IndexOf(vList, sItem)
+ If lIndex &gt;= 0 Then vSelection = ScriptForge.SF_Array.Append(vSelection, lIndex)
+ Next i
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Finally
+ lIndex = ScriptForge.SF_Array.IndexOf(_ControlModel.StringItemList, pvValue)
+ If lIndex &gt;= 0 Then vSelection = Array(lIndex)
+ End If
+ _ControlModel.SelectedItems = vSelection
+ End If
+ Case CTLPROGRESSBAR &apos;Numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ProgressValueMin&quot;) Then
+ If pvValue &lt; _ControlModel.ProgressValueMin Then pvValue = _ControlModel.ProgressValueMin
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;ProgressValueMax&quot;) Then
+ If pvValue &gt; _ControlModel.ProgressValueMax Then pvValue = _ControlModel.ProgressValueMax
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;ProgressValue&quot;) Then _ControlModel.ProgressValue = pvValue
+ Case CTLRADIOBUTTON &apos;Boolean
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then _ControlModel.State = Iif(pvValue, 1, 0)
+ Case CTLSCROLLBAR &apos;Numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValueMin&quot;) Then
+ If pvValue &lt; _ControlModel.ScrollValueMin Then pvValue = _ControlModel.ScrollValueMin
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValueMax&quot;) Then
+ If pvValue &gt; _ControlModel.ScrollValueMax Then pvValue = _ControlModel.ScrollValueMax
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValue&quot;) Then _ControlModel.ScrollValue = pvValue
+ Case CTLTIMEFIELD
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_DATE) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Time&quot;) Then
+ Set vSet = New com.sun.star.util.Time
+ vSet.Hours = Hour(pvValue)
+ vSet.Minutes = Minute(pvValue)
+ vSet.Seconds = Second(pvValue)
+ _ControlModel.Time = vSet
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Visible&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Visible&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoMethod(_ControlView, &quot;setVisible&quot;) Then
+ If pvValue Then
+ If oSession.HasUnoProperty(_ControlModel, &quot;EnableVisible&quot;) Then _ControlModel.EnableVisible = True
+ End If
+ _ControlView.setVisible(pvValue)
+ End If
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ ScriptForge.SF_Exception.RaiseFatal(CONTROLTYPEERROR, _Name, _DialogName, _ControlType, psProperty)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_DialogControl._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[DIALOGCONTROL]: Name, Type (dialogname)
+ _Repr = &quot;[DIALOGCONTROL]: &quot; &amp; _Name &amp; &quot;, &quot; &amp; _ControlType &amp; &quot; (&quot; &amp; _DialogName &amp; &quot;)&quot;
+
+End Function &apos; SFDialogs.SF_DialogControl._Repr
+
+REM ============================================ END OF SFDIALOGS.SF_DIALOGCONTROL
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdialogs/SF_DialogListener.xba b/wizards/source/sfdialogs/SF_DialogListener.xba
new file mode 100644
index 000000000..0f324b609
--- /dev/null
+++ b/wizards/source/sfdialogs/SF_DialogListener.xba
@@ -0,0 +1,113 @@
+<?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_DialogListener" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDialogs 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_Listener
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; The current module is dedicated to the management of dialog control events, triggered by user actions,
+&apos;&apos;&apos; which cannot be defined with the Basic IDE
+&apos;&apos;&apos;
+&apos;&apos;&apos; Concerned events:
+&apos;&apos;&apos; TreeControl control type
+&apos;&apos;&apos; -----------
+&apos;&apos;&apos; The OnNodeSelected event, triggered when a user selects a node
+&apos;&apos;&apos; A typical action is to display additional info about the selected item elsewhere in the dialog
+&apos;&apos;&apos; The OnNodeExpanded event, triggered when a user clicks on the expansion symbol
+&apos;&apos;&apos; A typical action is to create dynamically a subnode or a subtree below the expanded item
+&apos;&apos;&apos;
+&apos;&apos;&apos; The described events are processed thru UNO listeners
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ================================================================= DEFINITIONS
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Sub _SFEXP_requestChildNodes(Optional ByRef poEvent As Object)
+&apos;&apos;&apos; Triggered by the OnNodeExpanded event of a tree control
+&apos;&apos;&apos; The event is triggered thru a com.sun.star.view.XTreeExpansionListener
+&apos;&apos;&apos; The argument is passed to a user routine sstored in the SF_DialogControl instance
+&apos;&apos;&apos; as a scripting framework URI
+
+Dim oControl As Object &apos; The SF_DialogControl object having triggered the event
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Check:
+ &apos; Ensure there is a node
+ If IsNull(poEvent) Or IsMissing(poEvent) Then Exit Sub
+ If IsNull(poEvent.Node) Then Exit Sub
+
+Try:
+ Set oControl = ScriptForge.SF_Services.CreateScriptService(&quot;SFDialogs.DialogEvent&quot;, poEvent)
+ ScriptForge.SF_Session._ExecuteScript(oControl.OnNodeExpanded, poEvent)
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub
+
+Sub _SFEXP_disposing(ByRef poEvent As Object)
+End Sub
+
+Sub _SFEXP_treeExpanding(Optional ByRef poEvent As Object)
+End Sub
+
+Sub _SFEXP_treeCollapsing(ByRef poEvent As Object)
+End Sub
+
+Sub _SFEXP_treeExpanded(ByRef poEvent As Object)
+End Sub
+
+Sub _SFEXP_treeCollapsed(ByRef poEvent As Object)
+End Sub
+
+REM -----------------------------------------------------------------------------
+Public Sub _SFSEL_selectionChanged(Optional ByRef poEvent As Object)
+&apos;&apos;&apos; Triggered by the OnNodeSelected event of a tree control
+&apos;&apos;&apos; The event is triggered thru a com.sun.star.view.XSelectionChangeListener
+&apos;&apos;&apos; The argument is passed to a user routine sstored in the SF_DialogControl instance
+&apos;&apos;&apos; as a scripting framework URI
+&apos;&apos;&apos;
+&apos;&apos;&apos; Nothing happens if there are several selected nodes or none
+
+Dim vSelection As Variant &apos; Variant, not object !!
+Dim oControl As Object &apos; The SF_DialogControl object having triggered the event
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Check:
+ &apos; Ensure there is a selection
+ If IsNull(poEvent) Or IsMissing(poEvent) Then Exit Sub
+ vSelection = poEvent.Source.getSelection()
+ If IsEmpty(vSelection) Or IsArray(vSelection) Then Exit Sub
+
+Try:
+ Set oControl = ScriptForge.SF_Services.CreateScriptService(&quot;SFDialogs.DialogEvent&quot;, poEvent)
+ ScriptForge.SF_Session._ExecuteScript(oControl.OnNodeSelected, poEvent)
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub
+
+Sub _SFSEL_disposing(ByRef poEvent As Object)
+End Sub
+
+REM ============================================================= PRIVATE METHODS
+
+REM ============================================ END OF SFDIALOGS.SF_DIALOGLISTENER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdialogs/SF_Register.xba b/wizards/source/sfdialogs/SF_Register.xba
new file mode 100644
index 000000000..e81dbb069
--- /dev/null
+++ b/wizards/source/sfdialogs/SF_Register.xba
@@ -0,0 +1,348 @@
+<?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 SFDialogs 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 ================================================================= DEFINITIONS
+
+&apos;&apos;&apos; Event management of dialogs requires to being able to rebuild a Dialog object
+&apos;&apos;&apos; from its com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl UNO instance
+&apos;&apos;&apos; For that purpose, the started dialogs are buffered in a global array of _DialogCache types
+
+Type _DialogCache
+ Terminated As Boolean
+ XUnoDialog As Object
+ BasicDialog As Object
+End Type
+
+REM ================================================================== EXCEPTIONS
+
+Private Const DIALOGNOTFOUNDERROR = &quot;DIALOGNOTFOUNDERROR&quot;
+
+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;Dialog&quot;, &quot;SFDialogs.SF_Register._NewDialog&quot;) &apos; Reference to the function initializing the service
+ .RegisterEventManager(&quot;DialogEvent&quot;, &quot;SFDialogs.SF_Register._EventManager&quot;) &apos; Reference to the events manager
+ &apos;TODO
+ End With
+
+End Sub &apos; SFDialogs.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _AddDialogToCache(ByRef pvUnoDialog As Object _
+ , ByRef pvBasicDialog As Object _
+ ) As Long
+&apos;&apos;&apos; Add a new entry in the cache array with the references of the actual dialog
+&apos;&apos;&apos; If relevant, the last entry of the cache is reused.
+&apos;&apos;&apos; The cache is located in the global _SF_ variable
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvUnoDialog: the com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl of the dialog box
+&apos;&apos;&apos; pvBasicDialog: its corresponding Basic object
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The index of the new or modified entry
+
+Dim vCache As New _DialogCache &apos; Entry to be added
+Dim lIndex As Long &apos; UBound of _SF_.SFDialogs
+Dim vCacheArray As Variant &apos; Alias of _SF_.SFDialogs
+
+Try:
+ vCacheArray = _SF_.SFDialogs
+
+ If IsEmpty(vCacheArray) Then vCacheArray = Array()
+ lIndex = UBound(vCacheArray)
+ If lIndex &lt; LBound(vCacheArray) Then
+ ReDim vCacheArray(0 To 0)
+ lIndex = 0
+ ElseIf Not vCacheArray(lIndex).Terminated Then &apos; Often last entry can be reused
+ lIndex = lIndex + 1
+ ReDim Preserve vCacheArray(0 To lIndex)
+ End If
+
+ With vCache
+ .Terminated = False
+ Set .XUnoDialog = pvUnoDialog
+ Set .BasicDialog = pvBasicDialog
+ End With
+ vCacheArray(lIndex) = vCache
+
+ _SF_.SFDialogs = vCacheArray
+
+Finally:
+ _AddDialogToCache = lIndex
+ Exit Function
+End Function &apos; SFDialogs.SF_Register._AddDialogToCache
+
+REM -----------------------------------------------------------------------------
+Private Sub _CleanCacheEntry(ByVal plIndex As Long)
+&apos;&apos;&apos; Clean the plIndex-th entry in the dialogs cache
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; plIndex: must fit within the actual boundaries of the cache, otherwise the request is ignored
+
+Dim vCache As New _DialogCache &apos; Cleaned entry
+
+ With _SF_
+ If Not IsArray(.SFDialogs) Then Exit Sub
+ If plIndex &lt; LBound(.SFDialogs) Or plIndex &gt; UBound(.SFDialogs) Then Exit Sub
+
+ With vCache
+ .Terminated = True
+ Set .XUnoDialog = Nothing
+ Set .BasicDialog = Nothing
+ End With
+ .SFDialogs(plIndex) = vCache
+ End With
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDialogs.SF_Register._CleanCacheEntry
+
+REM -----------------------------------------------------------------------------
+Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
+&apos;&apos;&apos; Returns a Dialog or DialogControl object corresponding with the Basic dialog
+&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.xxx
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the output of a Dialog or DialogControl service or Nothing
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Sub TriggeredByEvent(ByRef poEvent As Object)
+&apos;&apos;&apos; Dim oDlg As Object
+&apos;&apos;&apos; Set oDlg = CreateScriptService(&quot;SFDialogs.DialogEvent&quot;, poEvent)
+&apos;&apos;&apos; If Not IsNull(oDlg) Then
+&apos;&apos;&apos; &apos; ... (a valid dialog or one of its controls has been identified)
+&apos;&apos;&apos; End Sub
+
+Dim oSource As Object &apos; Return value
+Dim oEventSource As Object &apos; Event UNO source
+Dim vEvent As Variant &apos; Alias of pvArgs(0)
+Dim sSourceType As String &apos; Implementation name of event source
+Dim oDialog As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
+Dim bControl As Boolean &apos; True when control event
+
+ &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 vEvent = Empty
+ If VarType(vEvent) &lt;&gt; ScriptForge.V_OBJECT Then GoTo Finally
+ If Not ScriptForge.SF_Session.HasUnoProperty(vEvent, &quot;Source&quot;) Then GoTo Finally
+
+Try:
+ Set oEventSource = vEvent.Source
+ sSourceType = ScriptForge.SF_Session.UnoObjectType(oEventSource)
+
+ Set oDialog = Nothing
+ Select Case True
+ Case sSourceType = &quot;stardiv.Toolkit.UnoDialogControl&quot; &apos; A dialog
+ &apos; Search the dialog in the cache
+ Set oDialog = _FindDialogInCache(oEventSource)
+ bControl = False
+ Case Left(sSourceType, 16) = &quot;stardiv.Toolkit.&quot; &apos; A dialog control
+ Set oDialog = _FindDialogInCache(oEventSource.Context)
+ bControl = True
+ Case Else
+ End Select
+
+ If Not IsNull(oDialog) Then
+ If bControl Then Set oSource = oDialog.Controls(oEventSource.Model.Name) Else Set oSource = oDialog
+ End If
+
+Finally:
+ Set _EventManager = oSource
+ Exit Function
+End Function &apos; SFDialogs.SF_Register._EventManager
+
+REM -----------------------------------------------------------------------------
+Private Function _FindDialogInCache(ByRef poDialog As Object) As Object
+&apos;&apos;&apos; Find the dialog based on its XUnoDialog
+&apos;&apos;&apos; The dialog must not be terminated
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The corresponding Basic dialog part or Nothing
+
+Dim oBasicDialog As Object &apos; Return value
+Dim oCache As _DialogCache &apos; Entry in the cache
+
+ Set oBasicDialog = Nothing
+
+Try:
+ For Each oCache In _SF_.SFDialogs
+ If EqualUnoObjects(poDialog, oCache.XUnoDialog) And Not oCache.Terminated Then
+ Set oBasicDialog = oCache.BasicDialog
+ Exit For
+ End If
+ Next oCache
+
+Finally:
+ Set _FindDialogInCache = oBasicDialog
+ Exit Function
+End Function &apos; SFDialogs.SF_Register._FindDialogInCache
+
+REM -----------------------------------------------------------------------------
+Public Function _NewDialog(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the SF_Dialog class
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Container: either &quot;GlobalScope&quot; or a WindowName. Default = the active window
+&apos;&apos;&apos; see the definition of WindowName in the description of the UI service
+&apos;&apos;&apos; Library: the name of the library hosting the dialog. Default = &quot;Standard&quot;
+&apos;&apos;&apos; DialogName: The name of the dialog
+&apos;&apos;&apos; Library and dialog names are case-sensitive
+&apos;&apos;&apos; Context: When called from Python, the context must be provided : XSCRIPTCONTEXT
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oDialog As Object &apos; Return value
+Dim vContainer As Variant &apos; Alias of pvArgs(0)
+Dim vLibrary As Variant &apos; Alias of pvArgs(1)
+Dim vDialogName As Variant &apos; Alias of pvArgs(2)
+Dim oLibraries As Object &apos; com.sun.star.comp.sfx2.DialogLibraryContainer
+Dim vContext As Variant &apos; com.sun.star.uno.XComponentContext
+Dim oDialogProvider As Object &apos; com.sun.star.io.XInputStreamProvider
+Dim oEnum As Object &apos; com.sun.star.container.XEnumeration
+Dim oComp As Object &apos; com.sun.star.lang.XComponent
+Dim oDialogControl As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
+Dim vWindow As Window &apos; A single component
+Dim sScope As String &apos; &quot;application&quot; or &quot;document&quot;
+Dim sURI As String &apos; URI of the targeted dialog
+Dim oUi As Object &apos; &quot;UI&quot; service
+Dim bFound As Boolean &apos; True if WindowName is found on the desktop
+Const cstService = &quot;SFDialogs.Dialog&quot;
+Const cstGlobal = &quot;GlobalScope&quot;
+
+ 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 _NewDialog called from _EventManager
+ If UBound(pvArgs) &gt;= 0 Then vContainer = pvArgs(0) Else vContainer = &quot;&quot;
+ If UBound(pvArgs) &gt;= 1 Then vLibrary = pvArgs(1)
+ If IsEmpty(vLibrary) Then vLibrary = &quot;Standard&quot;
+ If UBound(pvArgs) &gt;= 2 Then vDialogName = pvArgs(2) Else vDialogName = Empty &apos; Use Empty to force mandatory status
+ If Not ScriptForge.SF_Utils._Validate(vContainer, &quot;Container&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vLibrary, &quot;Library&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vDialogName, &quot;DialogName&quot;, V_STRING) Then GoTo Finally
+ If UBound(pvArgs) &gt;= 3 Then vContext = pvArgs(3) Else vContext = Nothing
+ If Not ScriptForge.SF_Utils._Validate(vContext, &quot;DialogName&quot;, V_OBJECT) Then GoTo Finally
+ Set oDialog = Nothing
+
+Try:
+ &apos; Determine the library container hosting the dialog
+ Set oUi = ScriptForge.SF_Register.CreateScriptService(&quot;UI&quot;)
+ Set oComp = Nothing
+ If VarType(vContainer) = V_STRING Then
+ bFound = ( UCase(vContainer) = UCase(cstGlobal) )
+ End If
+ If Not bFound Then
+ Select Case VarType(vContainer)
+ Case V_STRING
+ If Len(vContainer) &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(vContainer)) _
+ Or (Len(.WindowName) &gt; 0 And .WindowName = vContainer) _
+ Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = vContainer) Then
+ bFound = True
+ Exit Do
+ End If
+ End With
+ Loop
+ Else
+ bFound = True
+ Set oComp = StarDesktop.CurrentComponent
+ vWindow = oUi._IdentifyWindow(oComp)
+ End If
+ Case V_OBJECT &apos; com.sun.star.lang.XComponent
+ bFound = True
+ vWindow = oUi._IdentifyWindow(vContainer)
+ Set oComp = vContainer
+ End Select
+ If Not bFound Then GoTo CatchNotFound
+ If Len(vWindow.DocumentType) = 0 Then GoTo CatchNotFound
+ End If
+
+ &apos; Determine the dialog provider
+ Select Case True
+ Case IsNull(vContext) And IsNull(oComp) &apos; Basic and GlobalScope
+ Set oDialogProvider = GetProcessServiceManager.createInstance(&quot;com.sun.star.awt.DialogProvider&quot;)
+ Case IsNull(vContext) And Not IsNull(oComp) &apos; Basic and Document
+ Set oDialogProvider = GetProcessServiceManager.createInstanceWithArguments(&quot;com.sun.star.awt.DialogProvider&quot;, Array(oComp))
+ Case Not IsNull(vContext) And IsNull(oComp) &apos; Python and GlobalScope
+ Set oDialogProvider = vContext.getServiceManager().createInstanceWithContext(&quot;com.sun.star.awt.DialogProvider&quot;, vContext)
+ Case Not IsNull(vContext) And Not IsNull(oComp) &apos; Python and Document
+ Set oDialogProvider = vContext.getServiceManager().createInstanceWithArguments(&quot;com.sun.star.awt.DialogProvider&quot;, Array(oComp))
+ End Select
+
+ &apos; Create the graphical interface
+ sScope = Iif(IsNull(oComp), &quot;application&quot;, &quot;document&quot;)
+ sURI = &quot;vnd.sun.star.script:&quot; &amp; vLibrary &amp; &quot;.&quot; &amp; vDialogName &amp; &quot;?location=&quot; &amp; sScope
+ On Local Error GoTo CatchNotFound
+ Set oDialogControl = oDialogProvider.createDialog(sURI)
+
+ &apos; Initialize the basic SF_Dialog instance to return to the user script
+ Set oDialog = New SF_Dialog
+ With oDialog
+ Set .[Me] = oDialog
+ If VarType(vContainer) = V_STRING Then ._Container = vContainer Else ._Container = vWindow.WindowName
+ ._Library = vLibrary
+ ._Name = vDialogName
+ Set ._DialogProvider = oDialogProvider
+ Set ._DialogControl = oDialogControl
+ ._Initialize()
+ End With
+
+Finally:
+ Set _NewDialog = oDialog
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Exception.RaiseFatal(DIALOGNOTFOUNDERROR, &quot;Service&quot;, cstService _
+ , &quot;Container&quot;, vContainer, &quot;Library&quot;, vLibrary, &quot;DialogName&quot;, vDialogName)
+ GoTo Finally
+End Function &apos; SFDialogs.SF_Register._NewDialog
+
+REM ============================================== END OF SFDIALOGS.SF_REGISTER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdialogs/__License.xba b/wizards/source/sfdialogs/__License.xba
new file mode 100644
index 000000000..e98be710e
--- /dev/null
+++ b/wizards/source/sfdialogs/__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-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDialogs 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/sfdialogs/dialog.xlb b/wizards/source/sfdialogs/dialog.xlb
new file mode 100644
index 000000000..be8e58d45
--- /dev/null
+++ b/wizards/source/sfdialogs/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="SFDialogs" library:readonly="false" library:passwordprotected="false"/> \ No newline at end of file
diff --git a/wizards/source/sfdialogs/script.xlb b/wizards/source/sfdialogs/script.xlb
new file mode 100644
index 000000000..6dff54d87
--- /dev/null
+++ b/wizards/source/sfdialogs/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="SFDialogs" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="__License"/>
+ <library:element library:name="SF_Register"/>
+ <library:element library:name="SF_Dialog"/>
+ <library:element library:name="SF_DialogControl"/>
+ <library:element library:name="SF_DialogListener"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Base.xba b/wizards/source/sfdocuments/SF_Base.xba
new file mode 100644
index 000000000..1e6395dbf
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Base.xba
@@ -0,0 +1,993 @@
+<?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 mainly to block parent properties that are NOT applicable to Base documents
+&apos;&apos;&apos; In addition, it provides methods to identify form documents and access their internal forms
+&apos;&apos;&apos; (read more elsewhere (the &quot;SFDocuments.Form&quot; service) about this subject)
+&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; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_base.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const DBCONNECTERROR = &quot;DBCONNECTERROR&quot;
+Private Const FORMDEADERROR = &quot;FORMDEADERROR&quot;
+Private Const BASEFORMNOTFOUNDERROR = &quot;BASEFORMNOTFOUNDERROR&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; UNO references
+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
+Private _FormDocuments As Object
+
+REM ============================================================ MODULE CONSTANTS
+
+Const ISBASEFORM = 3 &apos; Form is stored in a Base document
+Const cstToken = &quot;//&quot; &apos; Form names accept special characters but not slashes
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+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
+ Set _FormDocuments = 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 _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, ScriptForge.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 CloseFormDocument(Optional ByVal FormDocument As Variant) As Boolean
+&apos;&apos;&apos; Close the given form document
+&apos;&apos;&apos; Nothing happens if the form document is not open
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FormDocument: a valid document form name as a case-sensitive string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if closure is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; oDoc.CloseFormDocument(&quot;Folder1/myFormDocument&quot;)
+
+Dim bClose As Boolean &apos; Return value
+Dim oMainForm As Object &apos; com.sun.star.comp.sdb.Content
+Dim vFormNames As Variant &apos; Array of all document form names present in the document
+
+Const cstThisSub = &quot;SFDocuments.Base.CloseFormDocument&quot;
+Const cstSubArgs = &quot;FormDocument&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bClose = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormNames = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+ If Not ScriptForge.SF_Utils._Validate(FormDocument, &quot;FormDocument&quot;, V_STRING, vFormNames) Then GoTo Finally
+ End If
+ If Not IsLoaded(FormDocument) Then GoTo Finally
+
+Try:
+ Set oMainForm = _FormDocuments.getByHierarchicalName(FormDocument)
+ bClose = oMainForm.close()
+
+Finally:
+ CloseFormDocument = bClose
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Base.CloseFormDocument
+
+REM -----------------------------------------------------------------------------
+Public Function FormDocuments() As Variant
+&apos;&apos;&apos; Return the list of the FormDocuments contained in the Base document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-base array of strings
+&apos;&apos;&apos; Each entry is the full path name of a form document. The path separator is the slash (&quot;/&quot;)
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myForm As Object, myList As Variant
+&apos;&apos;&apos; myList = oDoc.FormDocuments()
+
+Dim vFormNames As Variant &apos; Array of all form names present in the document
+Const cstThisSub = &quot;SFDocuments.Base.FormDocuments&quot;
+Const cstSubArgs = &quot;&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
+ End If
+
+Try:
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormNames = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+
+Finally:
+ FormDocuments = vFormNames
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Base.FormDocuments
+
+REM -----------------------------------------------------------------------------
+Public Function Forms(Optional ByVal FormDocument As Variant _
+ , Optional ByVal Form As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the Forms contained in the form document
+&apos;&apos;&apos; - a SFDocuments.Form object based on its name or its index
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FormDocument: a valid document form name as a case-sensitive string
+&apos;&apos;&apos; Form: a form stored in the Base document given by its name or its index
+&apos;&apos;&apos; When absent, the list of available forms is returned
+&apos;&apos;&apos; To get the first (unique ?) form stored in the form document, set Form = 0
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based array of strings if Form is absent
+&apos;&apos;&apos; An instance of the SF_Form class if Form exists
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FORMDEADERROR The form is not open
+&apos;&apos;&apos; BASEFORMNOTFOUNDERROR FormDocument OK but Form not found
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myForm As Object, myList As Variant
+&apos;&apos;&apos; myList = oDoc.Forms(&quot;Folder1/myFormDocument&quot;)
+&apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;Folder1/myFormDocument&quot;, 0)
+
+Dim oForm As Object &apos; The new Form class instance
+Dim oFormDocument As Object &apos; com.sun.star.comp.sdb.Content
+Dim oXForm As Object &apos; com.sun.star.form.XForm
+Dim vFormDocuments As Variant &apos; Array of form documents
+Dim vFormNames As Variant &apos; Array of form names
+Dim oForms As Object &apos; Forms collection
+Const cstDrawPage = 0 &apos; Only 1 drawpage in a Base document
+
+Const cstThisSub = &quot;SFDocuments.Base.Forms&quot;
+Const cstSubArgs = &quot;FormDocument, [Form=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Form) Or IsEmpty(Form) Then Form = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormDocuments = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+ If Not ScriptForge.SF_Utils._Validate(FormDocument, &quot;FormDocument&quot;, V_STRING, vFormDocuments) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ End If
+ If Not IsLoaded(FormDocument) Then GoTo CatchClosed
+
+Try:
+ &apos; Start from the form document and go down to forms
+ Set oFormDocument = _FormDocuments.getByHierarchicalName(FormDocument)
+ Set oForms = oFormDocument.Component.DrawPages(cstDrawPage).Forms
+ vFormNames = oForms.getElementNames()
+
+ If Len(Form) = 0 Then &apos; Return the list of valid form names
+ Forms = vFormNames
+ Else
+ If VarType(Form) = V_STRING Then &apos; Find the form by name
+ If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, V_STRING, vFormNames) Then GoTo Finally
+ Set oXForm = oForms.getByName(Form)
+ Else &apos; Find the form by index
+ If Form &lt; 0 Or Form &gt;= oForms.Count Then GoTo CatchNotFound
+ Set oXForm = oForms.getByIndex(Form)
+ End If
+ &apos; Create the new Form class instance
+ Set oForm = New SF_Form
+ With oForm
+ ._Name = oXForm.Name
+ Set .[Me] = oForm
+ Set .[_Parent] = [Me]
+ Set ._Component = _Component
+ ._FormDocumentName = FormDocument
+ Set ._FormDocument = oFormDocument
+ ._FormType = ISBASEFORM
+ Set ._Form = oXForm
+ ._Initialize()
+ End With
+ Set Forms = oForm
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchClosed:
+ ScriptForge.SF_Exception.RaiseFatal(FORMDEADERROR, FormDocument, _FileIdent())
+CatchNotFound:
+ ScriptForge.SF_Exception.RaiseFatal(BASEFORMNOTFOUNDERROR, Form, FormDocument, _FileIdent())
+End Function &apos; SFDocuments.SF_Base.Forms
+
+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 _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 IsLoaded(Optional ByVal FormDocument As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given FormDocument is open for the user
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FormDocument: a valid document form name as a case-sensitive string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the form document is currently open, otherwise False
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; Form name is invalid
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox oDoc.IsLoaded(&quot;Folder1/myFormDocument&quot;)
+
+Dim bLoaded As Boolean &apos; Return value
+Dim vFormNames As Variant &apos; Array of all document form names present in the document
+Dim oMainForm As Object &apos; com.sun.star.comp.sdb.Content
+Const cstThisSub = &quot;SFDocuments.Base.IsLoaded&quot;
+Const cstSubArgs = &quot;FormDocument&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bLoaded = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormNames = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+ If Not ScriptForge.SF_Utils._Validate(FormDocument, &quot;FormDocument&quot;, V_STRING, vFormNames) Then GoTo Finally
+ End If
+
+Try:
+ Set oMainForm = _FormDocuments.getByHierarchicalName(FormDocument)
+ &apos; A document form that has never been opened has no component
+ &apos; If ever opened and closed afterwards, it keeps the Component but loses its Controller
+ bLoaded = Not IsNull(oMainForm.Component)
+ If bLoaded Then bLoaded = Not IsNull(oMainForm.Component.CurrentController)
+
+Finally:
+ IsLoaded = bLoaded
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Base.IsLoaded
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Base class as an array
+
+ Methods = Array( _
+ &quot;CloseFormDocument&quot; _
+ , &quot;FormDocuments&quot; _
+ , &quot;Forms&quot; _
+ , &quot;GetDatabase&quot; _
+ , &quot;IsLoaded&quot; _
+ , &quot;OpenFormDocument&quot; _
+ , &quot;PrintOut&quot; _
+ , &quot;SetPrinter&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Base.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function OpenFormDocument(Optional ByVal FormDocument As Variant _
+ , Optional ByVal DesignMode As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Open the FormDocument given by its hierarchical name either in normal or in design mode
+&apos;&apos;&apos; If the form document is already open, the form document is made active without changing its mode
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FormDocument: a valid document form name as a case-sensitive string
+&apos;&apos;&apos; DesignMode: when True the form document is opened in design mode (Default = False)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the form document could be opened, otherwise False
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; Form name is invalid
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; oDoc.OpenFormDocument(&quot;Folder1/myFormDocument&quot;)
+
+Dim bOpen As Boolean &apos; Return value
+Dim vFormNames As Variant &apos; Array of all document form names present in the document
+Dim oContainer As Object &apos; com.sun.star.awt.XWindow
+Dim oNewForm As Object &apos; Output of loadComponent()
+Const cstThisSub = &quot;SFDocuments.Base.OpenFormDocument&quot;
+Const cstSubArgs = &quot;FormDocument, [DesignMode=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bOpen = False
+
+Check:
+ If IsMissing(DesignMode) Or IsEmpty(DesignMode) Then DesignMode = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormNames = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+ If Not ScriptForge.SF_Utils._Validate(FormDocument, &quot;FormDocument&quot;, V_STRING, vFormNames) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DesignMode, &quot;DesignMode&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ With _Component.CurrentController
+ If Not .IsConnected Then .connect()
+ &apos; loadComponent activates the form when already loaded
+ Set oNewForm = .loadComponent(com.sun.star.sdb.application.DatabaseObject.FORM, FormDocument, DesignMode)
+ &apos; When user opened manually the form in design mode and closed it, the next execution in normal mode needs to be confirmed as below
+ With oNewForm.CurrentController
+ If .isFormDesignMode() &lt;&gt; DesignMode Then .setFormDesignMode(DesignMode)
+ End With
+ End With
+ bOpen = True
+
+Finally:
+ OpenFormDocument = bOpen
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Base.OpenFormDocument
+
+REM -----------------------------------------------------------------------------
+Public Function PrintOut(Optional ByVal FormDocument As Variant _
+ , Optional ByVal Pages As Variant _
+ , Optional ByVal Copies As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Send the content of the given form document to the printer.
+&apos;&apos;&apos; The printer might be defined previously by default, by the user or by the SetPrinter() method
+&apos;&apos;&apos; The given form document must be open. It is activated by the method.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FormDocument: a valid document form name as a case-sensitive string
+&apos;&apos;&apos; Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
+&apos;&apos;&apos; Copies: the number of copies
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FORMDEADERROR The form is not open
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.PrintOut(&quot;myForm&quot;, &quot;1-4;10;15-18&quot;, Copies := 2)
+
+Dim bPrint As Boolean &apos; Return value
+Dim vFormNames As Variant &apos; Array of all document form names present in the document
+Dim oFormDocument As Object &apos; com.sun.star.comp.sdb.Content
+
+Const cstThisSub = &quot;SFDocuments.Base.PrintOut&quot;
+Const cstSubArgs = &quot;FormDocument, [Pages=&quot;&quot;&quot;&quot;], [Copies=1]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrint = False
+
+Check:
+ If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
+ If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormNames = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+ If Not ScriptForge.SF_Utils._Validate(FormDocument, &quot;FormDocument&quot;, V_STRING, vFormNames) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Copies, &quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+ If Not IsLoaded(FormDocument) Then GoTo CatchClosed
+
+Try:
+ Set oFormDocument = _FormDocuments.getByHierarchicalName(FormDocument)
+ bPrint = [_Super].PrintOut(Pages, Copies, oFormDocument.Component)
+
+Finally:
+ PrintOut = bPrint
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchClosed:
+ ScriptForge.SF_Exception.RaiseFatal(FORMDEADERROR, FormDocument, _FileIdent())
+End Function &apos; SFDocuments.SF_Base.PrintOut
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Base 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 SetPrinter(Optional ByVal FormDocument As Variant _
+ , Optional ByVal Printer As Variant _
+ , Optional ByVal Orientation As Variant _
+ , Optional ByVal PaperFormat As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Define the printer options for a form document. The form document must be open.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FormDocument: a valid document form name as a case-sensitive string
+&apos;&apos;&apos; Printer: the name of the printer queue where to print to
+&apos;&apos;&apos; When absent or space, the default printer is set
+&apos;&apos;&apos; Orientation: either &quot;PORTRAIT&quot; or &quot;LANDSCAPE&quot;. Left unchanged when absent
+&apos;&apos;&apos; PaperFormat: one of next values
+&apos;&apos;&apos; &quot;A3&quot;, &quot;A4&quot;, &quot;A5&quot;, &quot;B4&quot;, &quot;B5&quot;, &quot;LETTER&quot;, &quot;LEGAL&quot;, &quot;TABLOID&quot;
+&apos;&apos;&apos; Left unchanged when absent
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SetPrinter(&quot;myForm&quot;, Orientation := &quot;PORTRAIT&quot;)
+
+Dim bPrinter As Boolean &apos; Return value
+Dim vFormDocuments As Variant &apos; Array of form documents
+Dim oFormDocument As Object &apos; com.sun.star.comp.sdb.Content
+
+Const cstThisSub = &quot;SFDocuments.Base.SetPrinter&quot;
+Const cstSubArgs = &quot;FormDocument, [Printer=&quot;&quot;&quot;&quot;], [Orientation=&quot;&quot;PORTRAIT&quot;&quot;|&quot;&quot;LANDSCAPE&quot;&quot;]&quot; _
+ &amp; &quot;, [PaperFormat=&quot;&quot;A3&quot;&quot;|&quot;&quot;A4&quot;&quot;|&quot;&quot;A5&quot;&quot;|&quot;&quot;B4&quot;&quot;|&quot;&quot;B5&quot;&quot;|&quot;&quot;LETTER&quot;&quot;|&quot;&quot;LEGAL&quot;&quot;|&quot;&quot;TABLOID&quot;&quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrinter = False
+
+Check:
+ If IsMissing(Printer) Or IsEmpty(Printer) Then Printer = &quot;&quot;
+ If IsMissing(Orientation) Or IsEmpty(Orientation) Then Orientation = &quot;&quot;
+ If IsMissing(PaperFormat) Or IsEmpty(PaperFormat) Then PaperFormat = &quot;&quot;
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ &apos; Build list of available FormDocuments recursively with _CollectFormDocuments
+ If IsNull(_FormDocuments) Then Set _FormDocuments = _Component.getFormDocuments()
+ vFormDocuments = Split(_CollectFormDocuments(_FormDocuments), cstToken)
+ If Not ScriptForge.SF_Utils._Validate(FormDocument, &quot;FormDocument&quot;, V_STRING, vFormDocuments) Then GoTo Finally
+ End If
+ If Not IsLoaded(FormDocument) Then GoTo CatchClosed
+
+Try:
+ Set oFormDocument = _FormDocuments.getByHierarchicalName(FormDocument)
+ bPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat, oFormDocument.Component)
+
+Finally:
+ SetPrinter = bPrinter
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchClosed:
+ ScriptForge.SF_Exception.RaiseFatal(FORMDEADERROR, FormDocument, _FileIdent())
+End Function &apos; SFDocuments.SF_Base.SetPrinter
+
+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_Base.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 Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ ) As Object
+ Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function &apos; SFDocuments.SF_Base.CreateMenu
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function &apos; SFDocuments.SF_Base.RemoveMenu
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant _
+ , ParamArray Args As Variant _
+ )
+ [_Super].RunCommand(Command, Args)
+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 _CollectFormDocuments(ByRef poContainer As Object) As String
+&apos;&apos;&apos; Returns a token-separated string of all hierarchical formdocument names
+&apos;&apos;&apos; depending on the formdocuments container in argument
+&apos;&apos;&apos; The function traverses recursively the whole tree below the container
+&apos;&apos;&apos; The initial call starts from the container _Component.getFormDocuments
+&apos;&apos;&apos; The list contains closed and open forms
+
+Dim sCollectNames As String &apos; Return value
+Dim oSubItem As Object &apos; com.sun.star.container.XNameAccess (folder) or com.sun.star.ucb.XContent (form)
+Dim i As Long
+Const cstFormType = &quot;application/vnd.oasis.opendocument.text&quot;
+ &apos; Identifies forms. Folders have a zero-length content type
+
+ On Local Error GoTo Finally
+
+Try:
+ sCollectNames = &quot;&quot;
+ With poContainer
+ For i = 0 To .Count - 1
+ Set oSubItem = .getByIndex(i)
+ If oSubItem.ContentType = cstFormType Then &apos; Add the form to the list
+ sCollectNames = sCollectNames &amp; cstToken &amp; oSubItem.HierarchicalName
+ Else
+ sCollectNames = sCollectNames &amp; cstToken &amp; _CollectFormDocuments(oSubItem)
+ End If
+ Next i
+ End With
+
+Finally:
+ _CollectFormDocuments = Mid(sCollectNames, Len(cstToken) + 1) &apos; Skip the initial token
+ Exit Function
+End Function &apos; SFDocuments.SF_Base._CollectFormDocuments
+
+REM -----------------------------------------------------------------------------
+Private Function _FileIdent() As String
+&apos;&apos;&apos; Returns a file identification from the information that is currently available
+&apos;&apos;&apos; Useful e.g. for display in error messages
+
+ _FileIdent = [_Super]._FileIdent()
+
+End Function &apos; SFDocuments.SF_Base._FileIdent
+
+REM -----------------------------------------------------------------------------
+Private Function _FindByPersistentName(ByRef poContainer As Object _
+ , psPersistent As String _
+ ) As Object
+&apos;&apos;&apos; The FormDocuments property of a Base component has strangely
+&apos;&apos;&apos; a getByHierarchical() method but no access to the same com.sun.star.comp.sdb.Content
+&apos;&apos;&apos; object via its persistent/ODF name
+&apos;&apos;&apos; This method returns the object having the given persistent name
+&apos;&apos;&apos; The function traverses recursively the whole tree below the container until found
+&apos;&apos;&apos; The initial call starts from the container _Component.getFormDocuments
+&apos;&apos;&apos; The list contains closed and open forms
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poContainer: the actual top of the free, initially _FormDocuments
+&apos;&apos;&apos; psPersistent: a name like &quot;Obj...&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A com.sun.star.comp.sdb.Content object (object found, the process stops)
+&apos;&apos;&apos; or Nothing (object not found, the process continues)
+
+Dim oMainForm As Object &apos; Return value
+Dim oSubItem As Object &apos; com.sun.star.container.XNameAccess (folder) or com.sun.star.ucb.XContent (form)
+Dim i As Long
+Const cstFormType = &quot;application/vnd.oasis.opendocument.text&quot;
+ &apos; Identifies forms. Folders have a zero-length content type
+
+ On Local Error GoTo Finally
+
+Try:
+ Set oMainForm = Nothing
+ With poContainer
+ For i = 0 To .Count - 1
+ Set oSubItem = .getByIndex(i)
+ If oSubItem.ContentType = cstFormType Then &apos; Examine its persistent name
+ If oSubItem.PersistentName = psPersistent Then
+ Set oMainForm = oSubItem
+ Exit For
+ End If
+ Else
+ Set oMainForm = _FindByPersistentName(oSubItem, psPersistent)
+ End If
+ Next i
+ End With
+
+Finally:
+ Set _FindByPersistentName = oMainForm
+ Exit Function
+End Function &apos; SFDocuments.SF_Base.FindByPersistentName
+
+REM -----------------------------------------------------------------------------
+Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
+ , Optional ByVal pbError As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the document has not been closed manually or incidentally since the last use
+&apos;&apos;&apos; If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbForUpdate: if True (default = False), check additionally if document is open for editing
+&apos;&apos;&apos; pbError: if True (default), raise a fatal error
+
+Dim bAlive As Boolean &apos; Return value
+
+ If IsMissing(pbForUpdate) Then pbForUpdate = False
+ If IsMissing(pbError) Then pbError = True
+
+Try:
+ bAlive = [_Super]._IsStillAlive(pbForUpdate, pbError)
+
+Finally:
+ _IsStillAlive = bAlive
+ Exit Function
+End Function &apos; SFDocuments.SF_Base._IsStillAlive
+
+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 _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 000000000..0b7b88ae8
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -0,0 +1,4501 @@
+<?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; managing and manipulating LibreOffice documents
+&apos;&apos;&apos;
+&apos;&apos;&apos; Some methods are generic for all types of documents: they are combined in the SF_Document module.
+&apos;&apos;&apos; Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Base, ...
+&apos;&apos;&apos;
+&apos;&apos;&apos; To workaround the absence of class inheritance in LibreOffice Basic, some redundancy is necessary
+&apos;&apos;&apos; Each subclass MUST implement also the generic methods and properties, even if they only call
+&apos;&apos;&apos; the parent methods and properties.
+&apos;&apos;&apos; They should also duplicate some generic private members as a subset of their own set of members
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SF_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; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_calc.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const 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;
+Private Const CALCFORMNOTFOUNDERROR = &quot;CALCFORMNOTFOUNDERROR&quot;
+Private Const DUPLICATECHARTERROR = &quot;DUPLICATECHARTERROR&quot;
+Private Const RANGEEXPORTERROR = &quot;RANGEEXPORTERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] 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;
+ ServiceName As String &apos; Must be &quot;SFDocuments.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
+
+Private _LastParsedAddress As Object &apos; _Address type - parsed ranges are cached
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const cstSHEET = 1
+Private Const cstRANGE = 2
+
+Private Const MAXCOLS = 2^10 &apos; Max number of columns 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
+Private Const SERVICEREFERENCE = &quot;SFDocuments.CalcReference&quot;
+ &apos; Service name of _Address (used in Python)
+
+Private Const ISCALCFORM = 2 &apos; Form is stored in a Calc document
+
+Private Const cstSPECIALCHARS = &quot; `~!@#$%^&amp;()-_=+{}|;:,&lt;.&gt;&quot;&quot;&quot;
+ &apos; Presence of a special character forces surrounding the sheet name with single quotes in absolute addresses
+
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Super] = Nothing
+ ObjectType = &quot;CALC&quot;
+ ServiceName = &quot;SFDocuments.Calc&quot;
+ Set _Component = Nothing
+ Set _LastParsedAddress = 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 _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 FirstCell(Optional ByVal RangeName As Variant) As String
+&apos;&apos;&apos; Returns the First used cell in a given range or sheet
+&apos;&apos;&apos; When the argument is a sheet it will always return the &quot;sheet.$A$1&quot; cell
+ FirstCell = _PropertyGet(&quot;FirstCell&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.FirstCell
+
+REM -----------------------------------------------------------------------------
+Property Get FirstColumn(Optional ByVal RangeName As Variant) As Long
+&apos;&apos;&apos; Returns the leftmost column in a given sheet or range
+&apos;&apos;&apos; When the argument is a sheet it will always return 1
+ FirstColumn = _PropertyGet(&quot;FirstColumn&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.FirstColumn
+
+REM -----------------------------------------------------------------------------
+Property Get FirstRow(Optional ByVal RangeName As Variant) As Long
+&apos;&apos;&apos; Returns the First used column in a given range
+&apos;&apos;&apos; When the argument is a sheet it will always return 1
+ FirstRow = _PropertyGet(&quot;FirstRow&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.FirstRow
+
+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 RangeName As Variant) As String
+&apos;&apos;&apos; Returns the last used cell in a given sheet or range
+ LastCell = _PropertyGet(&quot;LastCell&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.LastCell
+
+REM -----------------------------------------------------------------------------
+Property Get LastColumn(Optional ByVal RangeName As Variant) As Long
+&apos;&apos;&apos; Returns the last used column in a given sheet
+ LastColumn = _PropertyGet(&quot;LastColumn&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.LastColumn
+
+REM -----------------------------------------------------------------------------
+Property Get LastRow(Optional ByVal RangeName As Variant) As Long
+&apos;&apos;&apos; Returns the last used column in a given sheet
+ LastRow = _PropertyGet(&quot;LastRow&quot;, RangeName)
+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 Region(Optional ByVal RangeName As Variant) As String
+&apos;&apos;&apos; Returns the smallest area as a range string that contains the given range
+&apos;&apos;&apos; and which is completely surrounded with empty cells
+ Region = _PropertyGet(&quot;Region&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.Region
+
+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 SheetName(Optional ByVal RangeName As Variant) As String
+&apos;&apos;&apos; Returns the sheet name part of a range
+ SheetName = _PropertyGet(&quot;SheetName&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.SheetName
+
+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 XSheetCellCursor(Optional ByVal RangeName As Variant) As Variant
+&apos;&apos;&apos; Returns a UNO object of type com.sun.star.sheet.XSheetCellCursor
+&apos;&apos; After having moved the cursor (gotoNext(), ...) the resulting range can be got
+&apos;&apos;&apos; back as a string with the cursor.AbsoluteName UNO property.
+ XSheetCellCursor = _PropertyGet(&quot;XSheetCellCursor&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.XSheetCellCursor
+
+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 A1Style(Optional ByVal Row1 As Variant _
+ , Optional ByVal Column1 As Variant _
+ , Optional ByVal Row2 As Variant _
+ , Optional ByVal Column2 As Variant _
+ , Optional ByVal SheetName As Variant _
+ ) As String
+&apos;&apos;&apos; Returns a range expressed in A1-style as defined by its coordinates
+&apos;&apos;&apos; If only one pair of coordinates is given, the range will embrace only a single cell
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Row1 : the row number of the first coordinate
+&apos;&apos;&apos; Column1 : the column number of the first coordinates
+&apos;&apos;&apos; Row2 : the row number of the second coordinate
+&apos;&apos;&apos; Column2 : the column number of the second coordinates
+&apos;&apos;&apos; SheetName: Default = the current sheet. If present, the sheet must exist.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A range as a string
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; range = oDoc.A1Style(5, 2, 10, 4, &quot;SheetX&quot;) &apos; &quot;&apos;$SheetX&apos;.$E$2:$J$4&quot;
+
+Dim sA1Style As String &apos; Return value
+Dim vSheetName As Variant &apos; Alias of SheetName - necessary see [Bug 145279]
+Dim lTemp As Long &apos; To switch 2 values
+Dim i As Long
+
+Const cstThisSub = &quot;SFDocuments.Calc.A1Style&quot;
+Const cstSubArgs = &quot;Row1, Column1, [Row2], [Column2], [SheetName]=&quot;&quot;&quot;&quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sA1Style = &quot;&quot;
+
+Check:
+ If IsMissing(Row2) Or IsEmpty(Row2) Then Row2 = 0
+ If IsMissing(Column2) Or IsEmpty(Column2) Then Column2 = 0
+ If IsMissing(SheetName) Or IsEmpty(SheetName) Then SheetName = &quot;~&quot;
+ vSheetName = SheetName
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Row1, &quot;Row1&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Column1, &quot;Column1&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Row2, &quot;Row2&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Column2, &quot;Column2&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not _ValidateSheet(vSheetName, &quot;SheetName&quot;, , True, True, , , True) Then GoTo Finally
+ End If
+
+ If Row1 &gt; MAXROWS Then Row1 = MAXROWS
+ If Row2 &gt; MAXROWS Then Row2 = MAXROWS
+ If Column1 &gt; MAXCOLS Then Column1 = MAXCOLS
+ If Column2 &gt; MAXCOLS Then Column2 = MAXCOLS
+
+ If Row2 &gt; 0 And Row2 &lt; Row1 Then
+ lTemp = Row2 : Row2 = Row1 : Row1 = lTemp
+ End If
+ If Column2 &gt; 0 And Column2 &lt; Column1 Then
+ lTemp = Column2 : Column2 = Column1 : Column1 = lTemp
+ End If
+
+Try:
+ &apos; Surround the sheet name with single quotes when required by the presence of special characters
+ vSheetName = _QuoteSheetName(vSheetName)
+ &apos; Define the new range string
+ sA1Style = &quot;$&quot; &amp; vSheetName &amp; &quot;.&quot; _
+ &amp; &quot;$&quot; &amp; _GetColumnName(Column1) &amp; &quot;$&quot; &amp; CLng(Row1) _
+ &amp; Iif(Row2 &gt; 0 And Column2 &gt; 0, &quot;:$&quot; &amp; _GetColumnName(Column2) &amp; &quot;$&quot; &amp; CLng(Row2), &quot;&quot;)
+
+Finally:
+ A1Style = sA1Style
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.A1Style
+
+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 _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 Function Charts(Optional ByVal SheetName As Variant _
+ , Optional ByVal ChartName As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return either the list of charts present in the given sheet or a chart object
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: The name of an existing sheet
+&apos;&apos;&apos; ChartName: The user-defined name of the targeted chart or the zero-length string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; When ChartName = &quot;&quot;, return the list of the charts present in the sheet,
+&apos;&apos;&apos; otherwise, return a new chart service instance
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim oChart As Object
+&apos;&apos;&apos; Set oChart = oDoc.Charts(&quot;SheetX&quot;, &quot;myChart&quot;)
+
+Dim vCharts As Variant &apos; Return value when array of chart names
+Dim oChart As Object &apos; Return value when new chart instance
+Dim oSheet As Object &apos; Alias of SheetName as reference
+Dim oDrawPage As Object &apos; com.sun.star.drawing.XDrawPage
+Dim oNextShape As Object &apos; com.sun.star.drawing.XShape
+Dim sChartName As String &apos; Some chart name
+Dim lCount As Long &apos; Counter for charts among all drawing objects
+Dim i As Long
+Const cstChartShape = &quot;com.sun.star.drawing.OLE2Shape&quot;
+
+Const cstThisSub = &quot;SFDocuments.Calc.Charts&quot;
+Const cstSubArgs = &quot;SheetName, [ChartName=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vCharts = Array()
+
+Check:
+ If IsMissing(ChartName) Or IsEmpty(ChartName) Then ChartName = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ChartName, &quot;ChartName&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Because the user can change it constantly, the list of valid charts has to be rebuilt at each time
+ &apos; Explore charts starting from the draw page
+ Set oSheet = _Component.getSheets.getByName(SheetName)
+ Set oDrawPage = oSheet.getDrawPage()
+ vCharts = Array()
+ Set oChart = Nothing
+ lCount = -1
+ For i = 0 To oDrawPage.Count - 1
+ Set oNextShape = oDrawPage.getByIndex(i)
+ if oNextShape.supportsService(cstChartShape) Then &apos; Ignore other shapes
+ sChartName = oNextShape.Name &apos; User-defined name
+ If Len(sChartName) = 0 Then sChartName = oNextShape.PersistName &apos; Internal name
+ &apos; Is chart found ?
+ If Len(ChartName) &gt; 0 Then
+ If ChartName = sChartName Then
+ Set oChart = New SF_Chart
+ With oChart
+ Set .[Me] = oChart
+ Set .[_Parent] = [Me]
+ ._SheetName = SheetName
+ ._DrawIndex = i
+ ._ChartName = ChartName
+ ._PersistentName = oNextShape.PersistName
+ Set ._Shape = oNextShape
+ Set ._Chart = oSheet.getCharts().getByName(._PersistentName)
+ Set ._ChartObject = ._Chart.EmbeddedObject
+ Set ._Diagram = ._ChartObject.Diagram
+ End With
+ Exit For
+ End If
+ End If
+ &apos; Build stack of chart names
+ lCount = lCount + 1
+ If UBound(vCharts) &lt; 0 Then
+ vCharts = Array(sChartName)
+ Else
+ ReDim Preserve vCharts(0 To UBound(vCharts) + 1)
+ vCharts(lCount) = sChartName
+ End If
+ End If
+ Next i
+
+ &apos; Raise error when chart not found
+ If Len(ChartName) &gt; 0 And IsNull(oChart) Then
+ If Not ScriptForge.SF_Utils._Validate(ChartName, &quot;ChartName&quot;, V_STRING, vCharts) Then GoTo Finally
+ End If
+
+Finally:
+ If Len(ChartName) = 0 Then Charts = vCharts Else Set Charts = oChart
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.Charts
+
+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 _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 _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 _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 CompactLeft(Optional ByVal Range As Variant _
+ , Optional ByVal WholeColumn As Variant _
+ , Optional ByVal FilterFormula As Variant _
+ ) As String
+&apos;&apos;&apos; Delete the columns of a specified range matching a filter expressed as a formula
+&apos;&apos;&apos; applied on each column.
+&apos;&apos;&apos; The deleted cells can span whole columns or be limited to the height of the range
+&apos;&apos;&apos; The execution of the method has no effect on the current selection
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
+&apos;&apos;&apos; WholeColumn: when True (default = False), erase whole columns
+&apos;&apos;&apos; FilterFormula: the formula to be applied on each column.
+&apos;&apos;&apos; The column is erased when the formula results in True,
+&apos;&apos;&apos; The formula shall probably involve one or more cells of the first column of the range..
+&apos;&apos;&apos; By default, a column is erased when all the cells of the column are empty,
+&apos;&apos;&apos; i.e. suppose the range is &quot;A1:J200&quot; (height = 0) the default value becomes
+&apos;&apos;&apos; &quot;=(COUNTBLANK(A1:A200)=200)&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the location of the initial range after compaction,
+&apos;&apos;&apos; or the zero-length string if the whole range has been deleted
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; newrange = oDoc.CompactLeft(&quot;SheetX.G1:L10&quot;) &apos; All empty columns of the range are suppressed
+&apos;&apos;&apos; newrange = oDoc.CompactLeft(&quot;SheetX.G1:L10&quot;, WholeColumn := True, FilterFormula := &quot;=(G$7=&quot;&quot;X&quot;&quot;)&quot;)
+&apos;&apos;&apos; &apos; The columns having a &quot;X&quot; in row 7 are completely suppressed
+
+Dim sCompact As String &apos; Return value
+Dim oSourceAddress As Object &apos; Alias of Range as _Address
+Dim lLastRow As Long &apos; Last used row number in the sheet containing Range
+Dim sFormulaRange As String &apos; Range, as a string, where the FilterFormula must be stored
+Dim vCompact As Variant &apos; Array of Boolean values indicating which columns should be erased
+Dim lCountDeleted As Long &apos; Count the deleted columns
+Dim lCountToDelete As Long &apos; Count contiguous columns to be deleted at once
+Dim sPartialRange As String &apos; Contiguous columns to be deleted
+Dim i As Long
+
+Const cstThisSub = &quot;SFDocuments.Calc.CompactLeft&quot;
+Const cstSubArgs = &quot;Range, [WholeColumn=False], [FilterFormula=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sCompact = &quot;&quot;
+
+Check:
+ If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = False
+ If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then FilterFormula = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(WholeColumn, &quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(FilterFormula, &quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Range)
+
+ With oSourceAddress
+
+ &apos; Set the default formula =&gt; all cells are blank
+ If FilterFormula = &quot;&quot; Then FilterFormula = Printf(&quot;=(COUNTBLANK(%C1%R1:%C1%R2)-&quot; &amp; .Height &amp; &quot;=0)&quot;, Range)
+ &apos; Compute the range where to apply the formula
+ lLastRow = LastRow(.SheetName)
+ sFormulaRange = Offset(Range, lLastRow - .XCellRange.RangeAddress.StartColumn + 1, , 1)
+ SetFormula(sFormulaRange, FilterFormula)
+ &apos; Get the columns to compact: 0 = False, 1 = True
+ vCompact = GetValue(sFormulaRange)
+ If Not IsArray(vCompact) Then vCompact = Array(vCompact)
+ ClearAll(sFormulaRange)
+
+ &apos; Iterates from the last to the first column of the range and remove the columns that match the filter
+ &apos; by groups of contiguous columns
+ lCountDeleted = 0
+ lCountToDelete = 0
+ For i = UBound(vCompact) To 0 Step -1
+ If vCompact(i) = 1 Then lCountToDelete = lCountToDelete + 1
+ If i &gt; 0 And vCompact(i) = 1 Then
+ &apos; Do nothing
+ ElseIf lCountToDelete &gt; 0 Then &apos; The current column must be kept but columns at the left must be removed
+ &apos; Do not forget when the 1st column must be removed
+ sPartialRange = Offset(Range, , Iif(i = 0 And vCompact(i) = 1, 0, i + 1), , lCountToDelete)
+ ShiftLeft(sPartialRange, WholeColumn)
+ lCountDeleted = lCountDeleted + lCountToDelete
+ lCountToDelete = 0
+ End If
+ Next i
+
+ &apos; Compute the final range position
+ If lCountDeleted &lt; .Width Then sCompact = Offset(Range, 0, 0, , .Width - lCountDeleted)
+
+ &apos; Push rightwards the cells that migrated leftwards irrelevantly
+ If Not WholeColumn Then
+ If Len(sCompact) &gt; 0 Then
+ sPartialRange = Offset(sCompact, 0, .Width - lCountDeleted, , lCountDeleted)
+ Else
+ sPartialRange = .RangeName
+ End If
+ ShiftRight(sPartialRange, WholeColumn := False)
+ End If
+
+ End With
+
+Finally:
+ CompactLeft = sCompact
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ &apos; When error, return the original range
+ If Not IsNull(oSourceAddress) Then sCompact = oSourceAddress.RangeName
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CompactLeft
+
+REM -----------------------------------------------------------------------------
+Public Function CompactUp(Optional ByVal Range As Variant _
+ , Optional ByVal WholeRow As Variant _
+ , Optional ByVal FilterFormula As Variant _
+ ) As String
+&apos;&apos;&apos; Delete the rows of a specified range matching a filter expressed as a formula
+&apos;&apos;&apos; applied on each row.
+&apos;&apos;&apos; The deleted cells can span whole rows or be limited to the width of the range
+&apos;&apos;&apos; The execution of the method has no effect on the current selection
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
+&apos;&apos;&apos; WholeRow: when True (default = False), erase whole rows
+&apos;&apos;&apos; FilterFormula: the formula to be applied on each row.
+&apos;&apos;&apos; The row is erased when the formula results in True,
+&apos;&apos;&apos; The formula shall probably involve one or more cells of the first row of the range..
+&apos;&apos;&apos; By default, a row is erased when all the cells of the row are empty,
+&apos;&apos;&apos; i.e. suppose the range is &quot;A1:J200&quot; (width = 10) the default value becomes
+&apos;&apos;&apos; &quot;=(COUNTBLANK(A1:J1)=10)&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the location of the initial range after compaction,
+&apos;&apos;&apos; or the zero-length string if the whole range has been deleted
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; newrange = oDoc.CompactUp(&quot;SheetX.G1:L10&quot;) &apos; All empty rows of the range are suppressed
+&apos;&apos;&apos; newrange = oDoc.CompactUp(&quot;SheetX.G1:L10&quot;, WholeRow := True, FilterFormula := &quot;=(G1=&quot;&quot;X&quot;&quot;)&quot;)
+&apos;&apos;&apos; &apos; The rows having a &quot;X&quot; in column G are completely suppressed
+
+Dim sCompact As String &apos; Return value
+Dim oSourceAddress As Object &apos; Alias of Range as _Address
+Dim lLastCol As Long &apos; Last used column number in the sheet containing Range
+Dim sFormulaRange As String &apos; Range, as a string, where the FilterFormula must be stored
+Dim vCompact As Variant &apos; Array of Boolean values indicating which rows should be erased
+Dim lCountDeleted As Long &apos; Count the deleted rows
+Dim lCountToDelete As Long &apos; Count contiguous rows to be deleted at once
+Dim sPartialRange As String &apos; Contiguous rows to be deleted
+Dim i As Long
+
+Const cstThisSub = &quot;SFDocuments.Calc.CompactUp&quot;
+Const cstSubArgs = &quot;Range, [WholeRow=False], [FilterFormula=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sCompact = &quot;&quot;
+
+Check:
+ If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
+ If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then FilterFormula = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(WholeRow, &quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(FilterFormula, &quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Range)
+
+ With oSourceAddress
+
+ &apos; Set the default formula =&gt; all cells are blank
+ If FilterFormula = &quot;&quot; Then FilterFormula = Printf(&quot;=(COUNTBLANK(%C1%R1:%C2%R1)-&quot; &amp; .Width &amp; &quot;=0)&quot;, Range)
+ &apos; Compute the range where to apply the formula
+ lLastCol = LastColumn(.SheetName)
+ sFormulaRange = Offset(Range, , lLastCol - .XCellRange.RangeAddress.StartRow + 1, , 1)
+ SetFormula(sFormulaRange, FilterFormula)
+ &apos; Get the rows to compact: 0 = False, 1 = True
+ vCompact = GetValue(sFormulaRange)
+ If Not IsArray(vCompact) Then vCompact = Array(vCompact)
+ ClearAll(sFormulaRange)
+
+ &apos; Iterates from the last to the first row of the range and remove the rows that match the filter
+ &apos; by groups of contiguous rows
+ lCountDeleted = 0
+ lCountToDelete = 0
+ For i = UBound(vCompact) To 0 Step -1
+ If vCompact(i) = 1 Then lCountToDelete = lCountToDelete + 1
+ If i &gt; 0 And vCompact(i) = 1 Then
+ &apos; Do nothing
+ ElseIf lCountToDelete &gt; 0 Then &apos; The current row must be kept but rows below must be removed
+ &apos; Do not forget when the 1st row must be removed
+ sPartialRange = Offset(Range, Iif(i = 0 And vCompact(i) = 1, 0, i + 1), , lCountToDelete)
+ ShiftUp(sPartialRange, WholeRow)
+ lCountDeleted = lCountDeleted + lCountToDelete
+ lCountToDelete = 0
+ End If
+ Next i
+
+ &apos; Compute the final range position
+ If lCountDeleted &lt; .Height Then sCompact = Offset(Range, 0, 0, .Height - lCountDeleted)
+
+ &apos; Push downwards the cells that migrated upwards irrelevantly
+ If Not WholeRow Then
+ If Len(sCompact) &gt; 0 Then
+ sPartialRange = Offset(sCompact, .Height - lCountDeleted, 0, lCountDeleted)
+ Else
+ sPartialRange = .RangeName
+ End If
+ ShiftDown(sPartialRange, WholeRow := False)
+ End If
+
+ End With
+
+Finally:
+ CompactUp = sCompact
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ &apos; When error, return the original range
+ If Not IsNull(oSourceAddress) Then sCompact = oSourceAddress.RangeName
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CompactUp
+
+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 _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
+&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 _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 via 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 a range of cells, 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 _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 _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 CreateChart(Optional ByVal ChartName As Variant _
+ , Optional ByVal SheetName As Variant _
+ , Optional ByVal Range As Variant _
+ , Optional ColumnHeader As Variant _
+ , Optional RowHeader As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return a new chart instance initialized with default values
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ChartName: The user-defined name of the new chart
+&apos;&apos;&apos; SheetName: The name of an existing sheet
+&apos;&apos;&apos; Range: the cell or the range as a string that should be drawn
+&apos;&apos;&apos; ColumnHeader: when True, the topmost row of the range will be used to set labels for the category axis or the legend.
+&apos;&apos;&apos; Default = False
+&apos;&apos;&apos; RowHeader: when True, the leftmost column of the range will be used to set labels for the category axis or the legend.
+&apos;&apos;&apos; Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A new chart service instance
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATECHARTERROR A chart with the same name exists already in the given sheet
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim oChart As Object
+&apos;&apos;&apos; Set oChart = oDoc.CreateChart(&quot;myChart&quot;, &quot;SheetX&quot;, &quot;A1:C8&quot;, ColumnHeader := True)
+
+Dim oChart As Object &apos; Return value
+Dim vCharts As Variant &apos; List of pre-existing charts
+Dim oSheet As Object &apos; Alias of SheetName as reference
+Dim oRange As Object &apos; Alias of Range
+Dim oRectangle as new com.sun.star.awt.Rectangle &apos; Simple shape
+
+Const cstThisSub = &quot;SFDocuments.Calc.CreateChart&quot;
+Const cstSubArgs = &quot;ChartName, SheetName, Range, [ColumnHeader=False], [RowHeader=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oChart = Nothing
+
+Check:
+ If IsMissing(RowHeader) Or IsEmpty(RowHeader) Then Rowheader = False
+ If IsMissing(ColumnHeader) Or IsEmpty(ColumnHeader) Then ColumnHeader = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ChartName, &quot;ChartName&quot;, V_STRING) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ColumnHeader, &quot;ColumnHeader&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(RowHeader, &quot;RowHeader&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+
+ vCharts = Charts(SheetName)
+ If ScriptForge.SF_Array.Contains(vCharts, ChartName, CaseSensitive := True) Then GoTo CatchDuplicate
+
+Try:
+ &apos; The rectangular shape receives arbitrary values. User can Resize() it later
+ With oRectangle
+ .X = 0 : .Y = 0
+ .Width = 8000 : .Height = 6000
+ End With
+ &apos; Initialize sheet and range
+ Set oSheet = _Component.getSheets.getByName(SheetName)
+ Set oRange = _ParseAddress(Range)
+ &apos; Create the chart and get ihe corresponding chart instance
+ oSheet.getCharts.addNewByName(ChartName, oRectangle, Array(oRange.XCellRange.RangeAddress), ColumnHeader, RowHeader)
+ Set oChart = Charts(SheetName, ChartName)
+ oChart._Shape.Name = ChartName &apos; Both user-defined and internal names match ChartName
+ oChart._Diagram.Wall.FillColor = RGB(255, 255, 255) &apos; Align on background color set by the user interface by default
+
+Finally:
+ Set CreateChart = oChart
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchDuplicate:
+ ScriptForge.SF_Exception.RaiseFatal(DUPLICATECHARTERROR, &quot;ChartName&quot;, ChartName, &quot;SheetName&quot;, SheetName, &quot;Document&quot;, [_Super]._FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CreateChart
+
+REM -----------------------------------------------------------------------------
+Public Function CreatePivotTable(Optional ByVal PivotTableName As Variant _
+ , Optional ByVal SourceRange As Variant _
+ , Optional ByVal TargetCell As Variant _
+ , Optional ByRef DataFields As Variant _
+ , Optional ByRef RowFields As Variant _
+ , Optional ByRef ColumnFields As Variant _
+ , Optional ByVal FilterButton As Variant _
+ , Optional ByVal RowTotals As Variant _
+ , Optional ByVal ColumnTotals As Variant _
+ ) As String
+&apos;&apos;&apos; Create a new pivot table with the properties defined by the arguments.
+&apos;&apos;&apos; If a pivot table with the same name exists already in the targeted sheet, it will be erased without warning.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PivotTableName: The user-defined name of the new pivottable
+&apos;&apos;&apos; SourceRange: The range as a string containing the raw data.
+&apos;&apos;&apos; The first row of the range is presumed to contain the field names of the new pivot table
+&apos;&apos;&apos; TargetCell: the top left cell or the range as a string where to locate the pivot table.
+&apos;&apos;&apos; Only the top left cell of the range will be considered.
+&apos;&apos;&apos; DataFields: A single string or an array of field name + function to apply, formatted like:
+&apos;&apos;&apos; Array(&quot;FieldName[;Function]&quot;, ...)
+&apos;&apos;&apos; The allowed functions are: Sum, Count, Average, Max, Min, Product, CountNums, StDev, StDevP, Var, VarP and Median.
+&apos;&apos;&apos; The default function is: When the values are all numerical, Sum is used, otherwise Count
+&apos;&apos;&apos; RowFields: A single string or an array of the field names heading the pivot table rows
+&apos;&apos;&apos; ColumnFields: A single string or an array of the field names heading the pivot table columns
+&apos;&apos;&apos; FilterButton: When True (default), display a &quot;Filter&quot; button above the pivot table
+&apos;&apos;&apos; RowTotals: When True (default), display a separate column for row totals
+&apos;&apos;&apos; ColumnTotals: When True (default), display a separate row for column totals
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Return the range where the new pivot table is deployed.
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim vData As Variant, oDoc As Object, sTable As String, sPivot As String
+&apos;&apos;&apos; vData = Array(Array(&quot;Item&quot;, &quot;State&quot;, &quot;Team&quot;, &quot;2002&quot;, &quot;2003&quot;, &quot;2004&quot;), _
+&apos;&apos;&apos; Array(&quot;Books&quot;, &quot;Michigan&quot;, &quot;Jean&quot;, 14788, 30222, 23490), _
+&apos;&apos;&apos; Array(&quot;Candy&quot;, &quot;Michigan&quot;, &quot;Jean&quot;, 26388, 15641, 32849), _
+&apos;&apos;&apos; Array(&quot;Pens&quot;, &quot;Michigan&quot;, &quot;Jean&quot;, 16569, 32675, 25396), _
+&apos;&apos;&apos; Array(&quot;Books&quot;, &quot;Michigan&quot;, &quot;Volker&quot;, 21961, 21242, 29009), _
+&apos;&apos;&apos; Array(&quot;Candy&quot;, &quot;Michigan&quot;, &quot;Volker&quot;, 26142, 22407, 32841))
+&apos;&apos;&apos; Set oDoc = ui.CreateDocument(&quot;Calc&quot;)
+&apos;&apos;&apos; sTable = oDoc.SetArray(&quot;A1&quot;, vData)
+&apos;&apos;&apos; sPivot = oDoc.CreatePivotTable(&quot;PT1&quot;, sTable, &quot;H1&quot;, Array(&quot;2002&quot;, &quot;2003;count&quot;, &quot;2004;average&quot;), &quot;Item&quot;, Array(&quot;State&quot;, &quot;Team&quot;), False)
+
+Dim sPivotTable As String &apos; Return value
+Dim vData As Variant &apos; Alias of DataFields
+Dim vRows As Variant &apos; Alias of RowFields
+Dim vColumns As Variant &apos; Alias of ColumnFields
+Dim oSourceAddress As Object &apos; Source as an _Address
+Dim oTargetAddress As Object &apos; Target as an _Address
+Dim vHeaders As Variant &apos; Array of header fields in the source range
+Dim oPivotTables As Object &apos; com.sun.star.sheet.XDataPilotTables
+Dim oDescriptor As Object &apos; com.sun.star.sheet.DataPilotDescriptor
+Dim oFields As Object &apos; ScDataPilotFieldsObj - Collection of fields
+Dim oField As Object &apos; ScDataPilotFieldsObj - A single field
+Dim sField As String &apos; A single field name
+Dim sData As String &apos; A single data field name + function
+Dim vDataField As Variant &apos; A single vData element, split on semicolon
+Dim sFunction As String &apos; Function to apply on a data field (string)
+Dim iFunction As Integer &apos; Equivalent of sFunction as com.sun.star.sheet.GeneralFunction2 constant
+Dim oOutputRange As Object &apos; com.sun.star.table.CellRangeAddress
+Dim i As Integer
+
+Const cstThisSub = &quot;SFDocuments.Calc.CreatePivotTable&quot;
+Const cstSubArgs = &quot;PivotTableName, SourceRange, TargetCell, DataFields, [RowFields], [ColumnFields]&quot; _
+ &amp; &quot;, [FilterButton=True], [RowTotals=True], [ColumnTotals=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sPivotTable = &quot;&quot;
+
+Check:
+ If IsMissing(RowFields) Or IsEmpty(RowFields) Then RowFields = Array()
+ If IsMissing(ColumnFields) Or IsEmpty(ColumnFields) Then ColumnFields = Array()
+ If IsMissing(FilterButton) Or IsEmpty(FilterButton) Then FilterButton = True
+ If IsMissing(RowTotals) Or IsEmpty(RowTotals) Then RowTotals = True
+ If IsMissing(ColumnTotals) Or IsEmpty(ColumnTotals) Then ColumnTotals = True
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(PivotTableName, &quot;PivotTableName&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SourceRange, &quot;SourceRange&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(TargetCell, &quot;TargetCell&quot;, V_STRING) Then GoTo Finally
+ If IsArray(DataFields) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(DataFields, &quot;DataFields&quot;, 1, V_STRING, True) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(DataFields, &quot;DataFields&quot;, V_STRING) Then GoTo Finally
+ End If
+ If IsArray(RowFields) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(RowFields, &quot;RowFields&quot;, 1, V_STRING, True) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(RowFields, &quot;RowFields&quot;, V_STRING) Then GoTo Finally
+ End If
+ If IsArray(ColumnFields) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(ColumnFields, &quot;ColumnFields&quot;, 1, V_STRING, True) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(ColumnFields, &quot;ColumnFields&quot;, V_STRING) Then GoTo Finally
+ End If
+ If Not ScriptForge.SF_Utils._Validate(FilterButton, &quot;FilterButton&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(RowTotals, &quot;RowTotals&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ColumnTotals, &quot;ColumnTotals&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+ &apos; Next statements must be outside previous If-block to force their execution even in case of internal call
+ If IsArray(DataFields) Then vData = DataFields Else vData = Array(DataFields)
+ If IsArray(RowFields) Then vRows = RowFields Else vRows = Array(RowFields)
+ If IsArray(ColumnFields) Then vColumns = ColumnFields Else vColumns = Array(ColumnFields)
+
+Try:
+
+ Set oSourceAddress = _ParseAddress(SourceRange)
+ vHeaders = GetValue(Offset(SourceRange, 0, 0, 1)) &apos; Content of the first row of the source
+ Set oTargetAddress = _Offset(TargetCell, 0, 0, 1, 1) &apos; Retain the top left cell only
+ Set oPivotTables = oTargetAddress.XSpreadsheet.getDataPilotTables()
+
+ &apos; Initialize new pivot table
+ Set oDescriptor = oPivotTables.createDataPilotDescriptor()
+ oDescriptor.setSourceRange(oSourceAddress.XCellRange.RangeAddress)
+ Set oFields = oDescriptor.getDataPilotFields()
+
+ &apos; Set row fields
+ For i = 0 To UBound(vRows)
+ sField = vRows(i)
+ If Len(sField) &gt; 0 Then
+ If Not ScriptForge.SF_Utils._Validate(sField, &quot;RowFields&quot;, V_STRING, vHeaders) Then GoTo Finally
+ Set oField = oFields.getByName(sField)
+ oField.Orientation = com.sun.star.sheet.DataPilotFieldOrientation.ROW
+ End If
+ Next i
+
+ &apos; Set column fields
+ For i = 0 To UBound(vColumns)
+ sField = vColumns(i)
+ If Len(sField) &gt; 0 Then
+ If Not ScriptForge.SF_Utils._Validate(sField, &quot;ColumnFields&quot;, V_STRING, vHeaders) Then GoTo Finally
+ Set oField = oFields.getByName(sField)
+ oField.Orientation = com.sun.star.sheet.DataPilotFieldOrientation.COLUMN
+ End If
+ Next i
+
+ &apos; Set data fields
+ For i = 0 To UBound(vData)
+ sData = vData(i)
+ &apos; Minimal parsing
+ If Right(sData, 1) = &quot;;&quot; Then sData = Left(sData, Len(sData) - 1)
+ vDataField = Split(sData, &quot;;&quot;)
+ sField = vDataField(0)
+ If UBound(vDataField) &gt; 0 Then sFunction = vDataField(1) Else sFunction = &quot;&quot;
+ &apos; Define field properties
+ If Len(sField) &gt; 0 Then
+ If Not ScriptForge.SF_Utils._Validate(sField, &quot;DataFields&quot;, V_STRING, vHeaders) Then GoTo Finally
+ Set oField = oFields.getByName(sField)
+ oField.Orientation = com.sun.star.sheet.DataPilotFieldOrientation.DATA
+ &apos; Associate the correct function
+ With com.sun.star.sheet.GeneralFunction2
+ Select Case UCase(sFunction)
+ Case &quot;&quot; : iFunction = .AUTO
+ Case &quot;SUM&quot; : iFunction = .SUM
+ Case &quot;COUNT&quot; : iFunction = .COUNT
+ Case &quot;AVERAGE&quot; : iFunction = .AVERAGE
+ Case &quot;MAX&quot; : iFunction = .MAX
+ Case &quot;MIN&quot; : iFunction = .MIN
+ Case &quot;PRODUCT&quot; : iFunction = .PRODUCT
+ Case &quot;COUNTNUMS&quot;: iFunction = .COUNTNUMS
+ Case &quot;STDEV&quot; : iFunction = .STDEV
+ Case &quot;STDEVP&quot; : iFunction = .STDEVP
+ Case &quot;VAR&quot; : iFunction = .VAR
+ Case &quot;VARP&quot; : iFunction = .VARP
+ Case &quot;MEDIAN&quot; : iFunction = .MEDIAN
+ Case Else
+ If Not ScriptForge.SF_Utils._Validate(sFunction, &quot;DataFields/Function&quot;, V_STRING _
+ , Array(&quot;Sum&quot;, &quot;Count&quot;, &quot;Average&quot;, &quot;Max&quot;, &quot;Min&quot;, &quot;Product&quot;, &quot;CountNums&quot; _
+ , &quot;StDev&quot;, &quot;StDevP&quot;, &quot;Var&quot;, &quot;VarP&quot;, &quot;Median&quot;) _
+ ) Then GoTo Finally
+ End Select
+ End With
+ oField.Function2 = iFunction
+ End If
+ Next i
+
+ &apos; Remove any pivot table with same name
+ If oPivotTables.hasByName(PivotTableName) Then oPivotTables.removeByName(PivotTableName)
+
+ &apos; Finalize the new pivot table
+ oDescriptor.ShowFilterButton = FilterButton
+ oDescriptor.RowGrand = RowTotals
+ oDescriptor.ColumnGrand = ColumnTotals
+ oPivotTables.insertNewByName(PivotTableName, oTargetAddress.XCellRange.getCellByPosition(0, 0).CellAddress, oDescriptor)
+
+ &apos; Determine the range of the new pivot table
+ Set oOutputRange = oPivotTables.getByName(PivotTableName).OutputRange
+ With oOutputRange
+ sPivotTable = _Component.getSheets().getCellRangeByPosition(.StartColumn, .StartRow, .EndColumn, .EndRow, .Sheet).AbsoluteName
+ End With
+
+Finally:
+ CreatePivotTable = sPivotTable
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CreatePivotTable
+
+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 as 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 -----------------------------------------------------------------------------
+Public Function ExportRangeToFile(Optional ByVal Range As Variant _
+ , Optional ByVal FileName As Variant _
+ , Optional ByVal ImageType As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Store the given range as an image to the given file location
+&apos;&apos;&apos; Actual selections are not impacted
+&apos;&apos;&apos; Inspired by https://stackoverflow.com/questions/30509532/how-to-export-cell-range-to-pdf-file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: sheet name or cell range to be exported, as a string
+&apos;&apos;&apos; FileName: Identifies the file where to save. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; ImageType: the name of the targeted media type
+&apos;&apos;&apos; Allowed values: jpeg, pdf (default) and png
+&apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False if the document could not be saved
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; RANGEEXPORTERROR The destination has its readonly attribute set or overwriting rejected
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.ExportRangeToFile(&apos;SheetX.B2:J15&quot;, &quot;C:\Me\Range2.png&quot;, ImageType := &quot;png&quot;, Overwrite := True)
+
+Dim bSaved As Boolean &apos; return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFile As String &apos; Alias of FileName
+Dim vStoreArguments As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim vFilterData As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim FSO As Object &apos; SF_FileSystem
+Dim vImageTypes As Variant &apos; Array of permitted image types
+Dim vFilters As Variant &apos; Array of corresponding filters in the same order as vImageTypes
+Dim sFilter As String &apos; The filter to apply
+Dim oSelect As Object &apos; Currently selected range(s)
+Dim oAddress As Object &apos; Alias of Range
+
+Const cstImageTypes = &quot;jpeg,pdf,png&quot;
+Const cstFilters = &quot;calc_jpg_Export,calc_pdf_Export,calc_png_Export&quot;
+
+Const cstThisSub = &quot;SFDocuments.Calc.ExportRangeToFile&quot;
+Const cstSubArgs = &quot;Range, FileName, [ImageType=&quot;&quot;pdf&quot;&quot;|&quot;&quot;jpeg&quot;&quot;|&quot;&quot;png&quot;&quot;], [Overwrite=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
+ bSaved = False
+
+Check:
+ If IsMissing(ImageType) Or IsEmpty(ImageType) Then ImageType = &quot;pdf&quot;
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+
+ vImageTypes = Split(cstImageTypes, &quot;,&quot;)
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ImageType, &quot;ImageType&quot;, V_STRING, vImageTypes) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ 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
+ vFilters = Split(cstFilters, &quot;,&quot;)
+ sFilter = vFilters(ScriptForge.SF_Array.IndexOf(vImageTypes, ImageType, CaseSensitive := False))
+ Set oAddress = _ParseAddress(Range)
+
+ &apos; The filter arguments differ between
+ &apos; 1) pdf : store range in Selection property value
+ &apos; 2) png, jpeg : save current selection, select range, restore initial selection
+ If LCase(ImageType) = &quot;pdf&quot; Then
+ vFilterData = Array(ScriptForge.SF_Utils._MakePropertyValue(&quot;Selection&quot;, oAddress.XCellRange) )
+ vStoreArguments = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, sFilter) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterData&quot;, vFilterData) _
+ )
+ Else &apos; png, jpeg
+ &apos; Save the current selection(s)
+ Set oSelect = _Component.CurrentController.getSelection()
+ _Component.CurrentController.select(oAddress.XCellRange)
+ vStoreArguments = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, sFilter) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;SelectionOnly&quot;, True) _
+ )
+ End If
+
+ &apos; Apply the filter and export
+ _Component.storeToUrl(sFile, vStoreArguments)
+ If LCase(ImageType) &lt;&gt; &quot;pdf&quot; Then _RestoreSelections(_Component, oSelect)
+
+ bSaved = True
+
+Finally:
+ ExportRangeToFile = bSaved
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ ScriptForge.SF_Exception.RaiseFatal(RANGEEXPORTERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Chart.ExportRangeToFile
+
+REM -----------------------------------------------------------------------------
+Public Function Forms(Optional ByVal SheetName As Variant _
+ , Optional ByVal Form As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the Forms contained in the given sheet
+&apos;&apos;&apos; - a SFDocuments.Form object based on its name or its index
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: the name of the sheet containing the requested form or forms
+&apos;&apos;&apos; Form: a form stored in the document given by its name or its index
+&apos;&apos;&apos; When absent, the list of available forms is returned
+&apos;&apos;&apos; To get the first (unique ?) form stored in the form document, set Form = 0
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; CALCFORMNOTFOUNDERROR Form not found
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based array of strings if Form is absent
+&apos;&apos;&apos; An instance of the SF_Form class if Form exists
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myForm As Object, myList As Variant
+&apos;&apos;&apos; myList = oDoc.Forms(&quot;ThisSheet&quot;)
+&apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;ThisSheet&quot;, 0)
+
+Dim oForm As Object &apos; The new Form class instance
+Dim oMainForm As Object &apos; com.sun.star.comp.sdb.Content
+Dim oXForm As Object &apos; com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
+Dim vFormNames As Variant &apos; Array of form names
+Dim oForms As Object &apos; Forms collection
+Const cstDrawPage = -1 &apos; There is no DrawPages collection in Calc sheets
+
+Const cstThisSub = &quot;SFDocuments.Calc.Forms&quot;
+Const cstSubArgs = &quot;SheetName, [Form=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Form) Or IsEmpty(Form) Then Form = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Start from the Calc sheet and go down to forms
+ Set oForms = _Component.getSheets.getByName(SheetName).DrawPage.Forms
+ vFormNames = oForms.getElementNames()
+
+ If Len(Form) = 0 Then &apos; Return the list of valid form names
+ Forms = vFormNames
+ Else
+ If VarType(Form) = V_STRING Then &apos; Find the form by name
+ If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, V_STRING, vFormNames) Then GoTo Finally
+ Set oXForm = oForms.getByName(Form)
+ Else &apos; Find the form by index
+ If Form &lt; 0 Or Form &gt;= oForms.Count Then GoTo CatchNotFound
+ Set oXForm = oForms.getByIndex(Form)
+ End If
+ &apos; Create the new Form class instance
+ Set oForm = SF_Register._NewForm(oXForm)
+ With oForm
+ Set .[_Parent] = [Me]
+ ._SheetName = SheetName
+ ._FormType = ISCALCFORM
+ Set ._Component = _Component
+ ._Initialize()
+ End With
+ Set Forms = oForm
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Exception.RaiseFatal(CALCFORMNOTFOUNDERROR, Form, _FileIdent())
+End Function &apos; SFDocuments.SF_Calc.Forms
+
+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 _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)
+ ElseIf Len(ObjectName) = 0 Then
+ GetProperty = _PropertyGet(PropertyName)
+ Else
+ GetProperty = _PropertyGet(PropertyName, ObjectName)
+ 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 _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; Beforehand 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.documentfoundation.org/Documentation/DevGuide/Spreadsheet_Documents#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 _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; Beforehand 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 a range of cells, 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 _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 _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 Calc service as an array
+
+ Methods = Array( _
+ &quot;A1Style&quot; _
+ , &quot;Charts&quot; _
+ , &quot;ClearAll&quot; _
+ , &quot;ClearFormats&quot; _
+ , &quot;ClearValues&quot; _
+ , &quot;CopySheet&quot; _
+ , &quot;CopySheetFromFile&quot; _
+ , &quot;CopyToCell&quot; _
+ , &quot;CopyToRange&quot; _
+ , &quot;CreateChart&quot; _
+ , &quot;DAvg&quot; _
+ , &quot;DCount&quot; _
+ , &quot;DMax&quot; _
+ , &quot;DMin&quot; _
+ , &quot;DSum&quot; _
+ , &quot;ExportRangeToFile&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;OpenRangeSelector&quot; _
+ , &quot;Printf&quot; _
+ , &quot;PrintOut&quot; _
+ , &quot;RemoveSheet&quot; _
+ , &quot;RenameSheet&quot; _
+ , &quot;SetArray&quot; _
+ , &quot;SetCellStyle&quot; _
+ , &quot;SetFormula&quot; _
+ , &quot;SetValue&quot; _
+ , &quot;ShiftDown&quot; _
+ , &quot;ShiftLeft&quot; _
+ , &quot;ShiftRight&quot; _
+ , &quot;ShiftUp&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; If given as a range of cells, 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.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 _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 _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 _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 OpenRangeSelector(Optional ByVal Title As Variant _
+ , Optional ByVal Selection As Variant _
+ , Optional ByVal SingleCell As Variant _
+ , Optional ByVal CloseAfterSelect As Variant _
+ ) As String
+&apos;&apos;&apos; Activates the Calc document, opens a non-modal dialog with a text box,
+&apos;&apos;&apos; let the user make a selection in the current or another sheet and
+&apos;&apos;&apos; returns the selected area as a string.
+&apos;&apos;&apos; This method does not change the current selection.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Title: the title to display on the top of the dialog
+&apos;&apos;&apos; Selection: a default preselection as a String. When absent, the first element of the
+&apos;&apos;&apos; current selection is preselected.
+&apos;&apos;&apos; SingleCell: When True, only a single cell may be selected. Default = False
+&apos;&apos;&apos; CloseAfterSelect: When True (default-, the dialog is closed immediately after
+&apos;&apos;&apos; the selection. When False, the user may change his/her mind and must close
+&apos;&apos;&apos; the dialog manually.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The selected range as a string, or the empty string when the user cancelled the request (close window button)
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim sSelect As String, vValues As Variant
+&apos;&apos;&apos; sSelect = oDoc.OpenRangeSelector(&quot;Select a range ...&quot;)
+&apos;&apos;&apos; If sSelect = &quot;&quot; Then Exit Function
+&apos;&apos;&apos; vValues = oDoc.GetValue(sSelect)
+
+Dim sSelector As String &apos; Return value
+Dim vPropertyValues As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim oSelection As Object &apos; The current selection before opening the selector
+Dim oAddress As Object &apos; Preselected address as _Address
+
+Const cstThisSub = &quot;SFDocuments.Calc.OpenRangeSelector&quot;
+Const cstSubArgs = &quot;[Title=&quot;&quot;&quot;&quot;], [Selection=&quot;&quot;~&quot;&quot;], [SingleCell=False], [CloseAfterSelect=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sSelector = &quot;&quot;
+
+Check:
+ If IsMissing(Title) Or IsEmpty(Title) Then Title = &quot;&quot;
+ If IsMissing(Selection) Or IsEmpty(Selection) Then Selection = &quot;~&quot;
+ If IsMissing(SingleCell) Or IsEmpty(SingleCell) Then SingleCell = False
+ If IsMissing(CloseAfterSelect) Or IsEmpty(CloseAfterSelect) Then CloseAfterSelect = True
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Title, &quot;Title&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Selection, &quot;Selection&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SingleCell, &quot;SingleCell&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(CloseAfterSelect, &quot;CloseAfterSelect&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Save the current selections
+ Set oSelection = _Component.CurrentController.getSelection()
+
+ &apos; Process preselection and select its containing sheet
+ Set oAddress = _ParseAddress(Selection)
+ Activate(oAddress.SheetName)
+
+ &apos; Build arguments array and execute the dialog box
+ With ScriptForge.SF_Utils
+ vPropertyValues = Array( _
+ ._MakePropertyValue(&quot;Title&quot;, Title) _
+ , ._MakePropertyValue(&quot;CloseOnMouseRelease&quot;, CloseAfterSelect) _
+ , ._MakePropertyValue(&quot;InitialValue&quot;, oAddress.XCellRange.AbsoluteName) _
+ , ._MakePropertyValue(&quot;SingleCellMode&quot;, SingleCell) _
+ )
+ End With
+ sSelector = SF_DocumentListener.RunRangeSelector(_Component, vPropertyValues)
+
+ &apos; Restore the saved selections
+ _RestoreSelections(_Component, oSelection)
+
+Finally:
+ OpenRangeSelector = sSelector
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.OpenRangeSelector
+
+REM -----------------------------------------------------------------------------
+Public Function Printf(Optional ByVal InputStr As Variant _
+ , Optional ByVal Range As Variant _
+ , Optional ByVal TokenCharacter As Variant _
+ ) As String
+&apos;&apos;&apos; Returns the input string after substitution of its tokens by
+&apos;&apos;&apos; their values in the given range
+&apos;&apos;&apos; This method is usually used in combination with SetFormula()
+&apos;&apos;&apos; The accepted tokens are:
+&apos;&apos;&apos; - %S The sheet name containing the range, including single quotes when necessary
+&apos;&apos;&apos; - %R1 The row number of the topleft part of the range
+&apos;&apos;&apos; - %C1 The column letter of the topleft part of the range
+&apos;&apos;&apos; - %R2 The row number of the bottomright part of the range
+&apos;&apos;&apos; - %C2 The column letter of the bottomright part of the range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; InputStr: usually a Calc formula or a part of a formula, but may be any string
+&apos;&apos;&apos; Range: the range, as a string from which the values of the tokens are derived
+&apos;&apos;&apos; TokenCharacter: the character identifying tokens. Default = &quot;%&quot;.
+&apos;&apos;&apos; Double the TokenCharacter to not consider it as a token.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The input string after substitution of the contained tokens
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Assume we have in A1:E10 a matrix of numbers. To obtain the sum by row in F1:F10 ...
+&apos;&apos;&apos; Dim range As String, formula As String
+&apos;&apos;&apos; range = &quot;$A$1:$E$10&quot;)
+&apos;&apos;&apos; formula = &quot;=SUM($%C1%R1:$%C2%R1)&quot; &apos; &quot;=SUM($A1:$E1)&quot;, note the relative references
+&apos;&apos;&apos; oDoc.SetFormula(&quot;$F$1:$F$10&quot;, formula)
+&apos;&apos;&apos; &apos;F1 will contain =Sum($A1:$E1)
+&apos;&apos;&apos; &apos;F2 =Sum($A2:$E2)
+&apos;&apos;&apos; &apos; ...
+
+Dim sPrintf As String &apos; Return value
+Dim vSubstitute As Variants &apos; Array of strings representing the token values
+Dim oAddress As Object &apos; A range as an _Address object
+Dim sSheetName As String &apos; The %S token value
+Dim sC1 As String &apos; The %C1 token value
+Dim sR1 As String &apos; The %R1 token value
+Dim sC2 As String &apos; The %C2 token value
+Dim sR2 As String &apos; The %R2 token value
+Dim i As Long
+Const cstPseudoToken = &quot;@#@&quot;
+
+Const cstThisSub = &quot;SFDocuments.Calc.Printf&quot;
+Const cstSubArgs = &quot;InputStr, Range, TokenCharacter=&quot;&quot;%&quot;&quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sPrintf = &quot;&quot;
+
+Check:
+ If IsMissing(TokenCharacter) Or IsEmpty(TokenCharacter) Then TokenCharacter = &quot;%&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(TokenCharacter, &quot;TokenCharacter&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Define the token values
+ Set oAddress = _ParseAddress(Range)
+ With oAddress.XCellRange
+ sC1 = _GetColumnName(.RangeAddress.StartColumn + 1)
+ sR1 = CStr(.RangeAddress.StartRow + 1)
+ sC2 = _GetColumnName(.RangeAddress.EndColumn + 1)
+ sR2 = CStr(.RangeAddress.EndRow + 1)
+ sSheetName = _QuoteSheetName(oAddress.XSpreadsheet.Name)
+ End With
+
+ &apos; Substitute tokens by their values
+ sPrintf = ScriptForge.SF_String.ReplaceStr(InputStr _
+ , Array(TokenCharacter &amp; TokenCharacter _
+ , TokenCharacter &amp; &quot;R1&quot; _
+ , TokenCharacter &amp; &quot;C1&quot; _
+ , TokenCharacter &amp; &quot;R2&quot; _
+ , TokenCharacter &amp; &quot;C2&quot; _
+ , TokenCharacter &amp; &quot;S&quot; _
+ , cstPseudoToken _
+ ) _
+ , Array(cstPseudoToken _
+ , sR1 _
+ , sC1 _
+ , sR2 _
+ , sC2 _
+ , sSheetName _
+ , TokenCharacter _
+ ) _
+ )
+
+Finally:
+ Printf = sPrintf
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.Printf
+
+REM -----------------------------------------------------------------------------
+Public Function PrintOut(Optional ByVal SheetName As Variant _
+ , Optional ByVal Pages As Variant _
+ , Optional ByVal Copies As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Send the content of the given sheet to the printer.
+&apos;&apos;&apos; The printer might be defined previously by default, by the user or by the SetPrinter() method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: the sheet to print. Default = the active sheet
+&apos;&apos;&apos; Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
+&apos;&apos;&apos; Copies: the number of copies
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.PrintOut(&quot;SheetX&quot;, &quot;1-4;10;15-18&quot;, Copies := 2)
+
+Dim bPrint As Boolean &apos; Return value
+Dim oSheet As Object &apos; SheetName as a reference
+
+Const cstThisSub = &quot;SFDocuments.Calc.PrintOut&quot;
+Const cstSubArgs = &quot;[SheetName=&quot;&quot;~&quot;&quot;], [Pages=&quot;&quot;&quot;&quot;], [Copies=1]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrint = False
+
+Check:
+ If IsMissing(SheetName) Or IsEmpty(SheetName) Then SheetName = &quot;&quot;
+ If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
+ If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True, True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Copies, &quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ If SheetName = &quot;~&quot; Then SheetName = &quot;&quot;
+ &apos; Make given sheet active
+ If Len(SheetName) &gt; 0 Then
+ With _Component
+ Set oSheet = .getSheets.getByName(SheetName)
+ Set .CurrentController.ActiveSheet = oSheet
+ End With
+ End If
+
+ bPrint = [_Super].PrintOut(Pages, Copies, _Component)
+
+Finally:
+ PrintOut = bPrint
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.PrintOut
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Calc class as an array
+
+ Properties = Array( _
+ &quot;CurrentSelection&quot; _
+ , &quot;CustomProperties&quot; _
+ , &quot;Description&quot; _
+ , &quot;DocumentProperties&quot; _
+ , &quot;DocumentType&quot; _
+ , &quot;ExportFilters&quot; _
+ , &quot;FirstCell&quot; _
+ , &quot;FirstColumn&quot; _
+ , &quot;FirstRow&quot; _
+ , &quot;Height&quot; _
+ , &quot;ImportFilters&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;Region&quot; _
+ , &quot;Sheet&quot; _
+ , &quot;SheetName&quot; _
+ , &quot;Sheets&quot; _
+ , &quot;Subject&quot; _
+ , &quot;Title&quot; _
+ , &quot;Width&quot; _
+ , &quot;XCellRange&quot; _
+ , &quot;XComponent&quot; _
+ , &quot;XSheetCellCursor&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 _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 _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 _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 _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.XSpreadsheet.Name)
+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 _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 o.XSpreadsheet.Name)f 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 _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 ShiftDown(Optional ByVal Range As Variant _
+ , Optional ByVal WholeRow As Variant _
+ , Optional ByVal Rows As Variant _
+ ) As String
+&apos;&apos;&apos; Move a specified range and all cells below in the same columns downwards by inserting empty cells
+&apos;&apos;&apos; The inserted cells can span whole rows or be limited to the width of the range
+&apos;&apos;&apos; The height of the inserted area is provided by the Rows argument
+&apos;&apos;&apos; Nothing happens if the range shift crosses one of the edges of the worksheet
+&apos;&apos;&apos; The execution of the method has no effect on the current selection
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range above which cells have to be inserted, as a string
+&apos;&apos;&apos; WholeRow: when True (default = False), insert whole rows
+&apos;&apos;&apos; Rows: the height of the area to insert. Default = the height of the Range argument
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the new location of the initial range
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; newrange = oDoc.ShiftDown(&quot;SheetX.A1:F10&quot;) &apos; &quot;$SheetX.$A$11:$F$20&quot;
+&apos;&apos;&apos; newrange = oDoc.ShiftDown(&quot;SheetX.A1:F10&quot;, Rows := 3) &apos; &quot;$SheetX.$A$4:$F$13&quot;
+
+Dim sShift As String &apos; Return value
+Dim oSourceAddress As Object &apos; Alias of Range as _Address
+Dim lHeight As Long &apos; Range height
+Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right width
+Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellInsertMode enum values
+
+Const cstThisSub = &quot;SFDocuments.Calc.ShiftDown&quot;
+Const cstSubArgs = &quot;Range, [WholeRow=False], [Rows]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sShift = &quot;&quot;
+
+Check:
+ If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
+ If IsMissing(Rows) Or IsEmpty(Rows) Then Rows = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(WholeRow, &quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Rows, &quot;Rows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Range)
+
+ With oSourceAddress
+
+ &apos; Manage the height of the area to shift
+ &apos; The insertCells() method inserts a number of rows equal to the height of the cell range to shift
+ lHeight = .Height
+ If Rows &lt;= 0 Then Rows = lHeight
+ If _LastCell(.XSpreadsheet)(1) + Rows &gt; MAXROWS Then GoTo Catch
+ If Rows &lt;&gt; lHeight Then
+ Set oShiftAddress = _Offset(oSourceAddress, 0, 0, Rows, 0).XCellRange.RangeAddress
+ Else
+ Set oShiftAddress = .XCellRange.RangeAddress
+ End If
+
+ &apos; Determine the shift mode
+ With com.sun.star.sheet.CellInsertMode
+ If WholeRow Then lShiftMode = .ROWS Else lShiftMode = .DOWN
+ End With
+
+ &apos; Move the cells as requested. This modifies .XCellRange
+ .XSpreadsheet.insertCells(oShiftAddress, lShiftMode)
+
+ &apos; Determine the receiving area
+ sShift = .XCellRange.AbsoluteName
+
+ End With
+
+Finally:
+ ShiftDown = sShift
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ &apos; When error, return the original range
+ If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.ShiftDown
+
+REM -----------------------------------------------------------------------------
+Public Function ShiftLeft(Optional ByVal Range As Variant _
+ , Optional ByVal WholeColumn As Variant _
+ , Optional ByVal Columns As Variant _
+ ) As String
+&apos;&apos;&apos; Delete the leftmost columns of a specified range and move all cells at their right leftwards
+&apos;&apos;&apos; The deleted cells can span whole columns or be limited to the height of the range
+&apos;&apos;&apos; The width of the deleted area is provided by the Columns argument
+&apos;&apos;&apos; The execution of the method has no effect on the current selection
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
+&apos;&apos;&apos; WholeColumn: when True (default = False), erase whole columns
+&apos;&apos;&apos; Columns: the width of the area to delete.
+&apos;&apos;&apos; Default = the width of the Range argument, it is also its maximum value
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the location of the remaining part of the initial range,
+&apos;&apos;&apos; or the zero-length string if the whole range has been deleted
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; newrange = oDoc.ShiftLeft(&quot;SheetX.G1:L10&quot;) &apos; &quot;&quot;&quot;
+&apos;&apos;&apos; newrange = oDoc.ShiftLeft(&quot;SheetX.G1:L10&quot;, Columns := 3) &apos; &quot;$SheetX.$G$1:$I$10&quot;
+
+Dim sShift As String &apos; Return value
+Dim oSourceAddress As Object &apos; Alias of Range as _Address
+Dim lWidth As Long &apos; Range width
+Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right width
+Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellDeleteMode enum values
+
+Const cstThisSub = &quot;SFDocuments.Calc.ShiftLeft&quot;
+Const cstSubArgs = &quot;Range, [WholeColumn=False], [Columns]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sShift = &quot;&quot;
+
+Check:
+ If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = False
+ If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(WholeColumn, &quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Columns, &quot;Columns&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Range)
+ Set _LastParsedAddress = Nothing &apos; Range will be erased. Force re-parsing next time
+
+ With oSourceAddress
+
+ &apos; Manage the width of the area to delete
+ &apos; The removeRange() method erases a number of columns equal to the width of the cell range to delete
+ lWidth = .Width
+ If Columns &lt;= 0 Then Columns = lWidth
+ If Columns &lt; lWidth Then
+ Set oShiftAddress = _Offset(oSourceAddress, 0, 0, 0, Columns).XCellRange.RangeAddress
+ Else &apos; Columns is capped at the range width
+ Set oShiftAddress = .XCellRange.RangeAddress
+ End If
+
+ &apos; Determine the Delete mode
+ With com.sun.star.sheet.CellDeleteMode
+ If WholeColumn Then lShiftMode = .COLUMNS Else lShiftMode = .LEFT
+ End With
+
+ &apos; Move the cells as requested. This modifies .XCellRange
+ .XSpreadsheet.removeRange(oShiftAddress, lShiftMode)
+
+ &apos; Determine the remaining area
+ If Columns &lt; lWidth Then sShift = .XCellRange.AbsoluteName
+
+ End With
+
+Finally:
+ ShiftLeft = sShift
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ &apos; When error, return the original range
+ If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.ShiftLeft
+
+REM -----------------------------------------------------------------------------
+Public Function ShiftRight(Optional ByVal Range As Variant _
+ , Optional ByVal WholeColumn As Variant _
+ , Optional ByVal Columns As Variant _
+ ) As String
+&apos;&apos;&apos; Move a specified range and all next cells in the same rows to the right by inserting empty cells
+&apos;&apos;&apos; The inserted cells can span whole columns or be limited to the height of the range
+&apos;&apos;&apos; The width of the inserted area is provided by the Columns argument
+&apos;&apos;&apos; Nothing happens if the range shift crosses one of the edges of the worksheet
+&apos;&apos;&apos; The execution of the method has no effect on the current selection
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range before which cells have to be inserted, as a string
+&apos;&apos;&apos; WholeColumn: when True (default = False), insert whole columns
+&apos;&apos;&apos; Columns: the width of the area to insert. Default = the width of the Range argument
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the new location of the initial range
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; newrange = oDoc.ShiftRight(&quot;SheetX.A1:F10&quot;) &apos; &quot;$SheetX.$G$1:$L$10&quot;
+&apos;&apos;&apos; newrange = oDoc.ShiftRight(&quot;SheetX.A1:F10&quot;, Columns := 3) &apos; &quot;$SheetX.$D$1:$I$10&quot;
+
+Dim sShift As String &apos; Return value
+Dim oSourceAddress As Object &apos; Alias of Range as _Address
+Dim lWidth As Long &apos; Range width
+Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right width
+Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellInsertMode enum values
+
+Const cstThisSub = &quot;SFDocuments.Calc.ShiftRight&quot;
+Const cstSubArgs = &quot;Range, [WholeColumn=False], [Columns]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sShift = &quot;&quot;
+
+Check:
+ If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = False
+ If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(WholeColumn, &quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Columns, &quot;Columns&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Range)
+
+ With oSourceAddress
+
+ &apos; Manage the width of the area to Shift
+ &apos; The insertCells() method inserts a number of columns equal to the width of the cell range to Shift
+ lWidth = .Width
+ If Columns &lt;= 0 Then Columns = lWidth
+ If _LastCell(.XSpreadsheet)(0) + Columns &gt; MAXCOLS Then GoTo Catch
+ If Columns &lt;&gt; lWidth Then
+ Set oShiftAddress = _Offset(oSourceAddress, 0, 0, 0, Columns).XCellRange.RangeAddress
+ Else
+ Set oShiftAddress = .XCellRange.RangeAddress
+ End If
+
+ &apos; Determine the Shift mode
+ With com.sun.star.sheet.CellInsertMode
+ If WholeColumn Then lShiftMode = .COLUMNS Else lShiftMode = .RIGHT
+ End With
+
+ &apos; Move the cells as requested. This modifies .XCellRange
+ .XSpreadsheet.insertCells(oShiftAddress, lShiftMode)
+
+ &apos; Determine the receiving area
+ sShift = .XCellRange.AbsoluteName
+
+ End With
+
+Finally:
+ ShiftRight = sShift
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ &apos; When error, return the original range
+ If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.ShiftRight
+
+REM -----------------------------------------------------------------------------
+Public Function ShiftUp(Optional ByVal Range As Variant _
+ , Optional ByVal WholeRow As Variant _
+ , Optional ByVal Rows As Variant _
+ ) As String
+&apos;&apos;&apos; Delete the topmost rows of a specified range and move all cells below upwards
+&apos;&apos;&apos; The deleted cells can span whole rows or be limited to the width of the range
+&apos;&apos;&apos; The height of the deleted area is provided by the Rows argument
+&apos;&apos;&apos; The execution of the method has no effect on the current selection
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
+&apos;&apos;&apos; WholeRow: when True (default = False), erase whole rows
+&apos;&apos;&apos; Rows: the height of the area to delete.
+&apos;&apos;&apos; Default = the height of the Range argument, it is also its maximum value
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the location of the remaining part of the initial range,
+&apos;&apos;&apos; or the zero-length string if the whole range has been deleted
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; newrange = oDoc.ShiftUp(&quot;SheetX.G1:L10&quot;) &apos; &quot;&quot;
+&apos;&apos;&apos; newrange = oDoc.ShiftUp(&quot;SheetX.G1:L10&quot;, Rows := 3) &apos; &quot;$SheetX.$G$1:$I$10&quot;
+
+Dim sShift As String &apos; Return value
+Dim oSourceAddress As Object &apos; Alias of Range as _Address
+Dim lHeight As Long &apos; Range height
+Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right height
+Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellDeleteMode enum values
+
+Const cstThisSub = &quot;SFDocuments.Calc.ShiftUp&quot;
+Const cstSubArgs = &quot;Range, [WholeRow=False], [Rows]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sShift = &quot;&quot;
+
+Check:
+ If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
+ If IsMissing(Rows) Or IsEmpty(Rows) Then Rows = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(WholeRow, &quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Rows, &quot;Rows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Range)
+ Set _LastParsedAddress = Nothing &apos; Range will be erased. Force re-parsing next time
+
+ With oSourceAddress
+
+ &apos; Manage the height of the area to delete
+ &apos; The removeRange() method erases a number of rows equal to the height of the cell range to delete
+ lHeight = .Height
+ If Rows &lt;= 0 Then Rows = lHeight
+ If Rows &lt; lHeight Then
+ Set oShiftAddress = _Offset(oSourceAddress, 0, 0, Rows, 0).XCellRange.RangeAddress
+ Else &apos; Rows is capped at the range height
+ Set oShiftAddress = .XCellRange.RangeAddress
+ End If
+
+ &apos; Determine the Delete mode
+ With com.sun.star.sheet.CellDeleteMode
+ If WholeRow Then lShiftMode = .ROWS Else lShiftMode = .UP
+ End With
+
+ &apos; Move the cells as requested. This modifies .XCellRange
+ .XSpreadsheet.removeRange(oShiftAddress, lShiftMode)
+
+ &apos; Determine the remaining area
+ If Rows &lt; lHeight Then sShift = .XCellRange.AbsoluteName
+
+ End With
+
+Finally:
+ ShiftUp = sShift
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ &apos; When error, return the original range
+ If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.ShiftUp
+
+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. Default = False
+&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;], [DestinationCell=&quot;&quot;&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 _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;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SortColumns, &quot;SortColumns&quot;, ScriptForge.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
+ vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;IsSortColumns&quot;, SortColumns)
+ vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;ContainsHeader&quot;, ContainsHeader)
+ vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;BindFormatsToContent&quot;, True)
+ If Len(DestinationCell) = 0 Then
+ vSortDescriptor = 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
+ vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;CopyOutputData&quot;, True)
+ vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;OutputPosition&quot;, oDestCell)
+ End If
+ vSortDescriptor = 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
+ vSortDescriptor = 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 ExportFilters() As Variant
+ ExportFilters = [_Super].GetProperty(&quot;ExportFilters&quot;)
+End Property &apos; SFDocuments.SF_Calc.ExportFilters
+
+REM -----------------------------------------------------------------------------
+Property Get ImportFilters() As Variant
+ ImportFilters = [_Super].GetProperty(&quot;ImportFilters&quot;)
+End Property &apos; SFDocuments.SF_Calc.ImportFilters
+
+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 Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ ) As Object
+ Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function &apos; SFDocuments.SF_Calc.CreateMenu
+
+REM -----------------------------------------------------------------------------
+Public Function ExportAsPDF(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Pages As Variant _
+ , Optional ByVal Password As Variant _
+ , Optional ByVal Watermark As Variant _
+ ) As Boolean
+ ExportAsPDF = [_Super].ExportAsPDF(FileName, Overwrite, Pages, Password, Watermark)
+End Function &apos; SFDocuments.SF_Calc.ExportAsPDF
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function &apos; SFDocuments.SF_Calc.RemoveMenu
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant _
+ , ParamArray Args As Variant _
+ )
+ [_Super].RunCommand(Command, Args)
+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 -----------------------------------------------------------------------------
+Public Function SetPrinter(Optional ByVal Printer As Variant _
+ , Optional ByVal Orientation As Variant _
+ , Optional ByVal PaperFormat As Variant _
+ ) As Boolean
+ SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
+End Function &apos; SFDocuments.SF_Calc.SetPrinter
+
+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.getDataArray 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; Input may be a 1D array of arrays, typically when call issued by a Python script
+&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 (1) of input array
+Dim lMax1 As Long &apos; Upper bound (1)
+Dim lMin2 As Long &apos; Lower bound (2)
+Dim lMax2 As Long &apos; Upper bound (2)
+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 bDataArray As Boolean &apos; Input array is already an array of arrays
+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 )
+ bDataArray = IsArray(pvArray(0))
+ If Not bDataArray Then
+ If Not bHorizontal Then
+ lMin1 = LBound(pvArray) : lMax1 = UBound(pvArray)
+ Else
+ lMin2 = LBound(pvArray) : lMax2 = UBound(pvArray)
+ End If
+ Else
+ iDims = 2
+ lMin1 = LBound(pvArray) : lMax1 = UBound(pvArray)
+ lMin2 = LBound(pvArray(0)) : lMax2 = UBound(pvArray(0))
+ 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
+ If bDataArray Then
+ vItem = _ConvertToCellValue(pvArray(i + lMin1)(j + lMin2))
+ Else
+ vItem = _ConvertToCellValue(pvArray(i + lMin1, j + lMin2))
+ End If
+ 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 _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 -----------------------------------------------------------------------------
+Private Function _FileIdent() As String
+&apos;&apos;&apos; Returns a file identification from the information that is currently available
+&apos;&apos;&apos; Useful e.g. for display in error messages
+
+ _FileIdent = [_Super]._FileIdent()
+
+End Function &apos; SFDocuments.SF_Calc._FileIdent
+
+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 _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
+ , Optional ByVal pbError As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the document has not been closed manually or incidentally since the last use
+&apos;&apos;&apos; If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbForUpdate: if True (default = False), check additionally if document is open for editing
+&apos;&apos;&apos; pbError: if True (default), raise a fatal error
+
+Dim bAlive As Boolean &apos; Return value
+
+ If IsMissing(pbForUpdate) Then pbForUpdate = False
+ If IsMissing(pbError) Then pbError = True
+
+Try:
+ bAlive = [_Super]._IsStillAlive(pbForUpdate, pbError)
+
+Finally:
+ _IsStillAlive = bAlive
+ Exit Function
+End Function &apos; SFDocuments.SF_Calc._IsStillAlive
+
+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
+ .ServiceName = SERVICEREFERENCE
+ .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; Address could not be parsed to a valid address
+
+Dim oAddress As Object &apos; Return value
+Dim sAddress As String &apos; Alias of psAddress
+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
+
+ &apos; If psAddress has already been parsed, get the result back
+ If Not IsNull(_LastParsedAddress) Then
+ &apos; Given argument must contain an explicit reference to a sheet
+ If (InStr(psAddress, &quot;~.&quot;) = 0 And InStr(psAddress, &quot;.&quot;) &gt; 0 And psAddress = _LastParsedAddress.RawAddress) _
+ Or psAddress = _LastParsedAddress.RangeName Then
+ Set _ParseAddress = _LastParsedAddress
+ Exit Function
+ Else
+ Set _LastParsedAddress = Nothing
+ End If
+ End If
+
+ &apos; Reinitialize a new _Address object
+ Set oAddress = New _Address
+ With oAddress
+ sSheet = &quot;&quot; : sRange = &quot;&quot;
+ .SheetName = &quot;&quot; : .RangeName = &quot;&quot;
+
+ .ObjectType = CALCREFERENCE
+ .ServiceName = SERVICEREFERENCE
+ .RawAddress = psAddress
+ Set .XSpreadSheet = Nothing : Set .XCellRange = Nothing
+
+ &apos; Remove leading &apos;$&apos;
+ If Left(psAddress, 1) = &quot;$&quot; Then sAddress = Mid(psAddress, 2) Else sAddress = psAddress
+ &apos; Split in sheet and range components - Check presence of surrounding single quotes or dot
+ If Left(sAddress, 1) = &quot;&apos;&quot; Then
+ lStart = 1
+ sSheet = ScriptForge.SF_String.FindRegex(sAddress, &quot;^&apos;[^\[\]*?:\/\\]+&apos;&quot;)
+ If lStart = 0 Then GoTo CatchAddress &apos; Invalid sheet name
+ If Len(sAddress) &gt; Len(sSheet) + 1 Then
+ If Mid(sAddress, Len(sSheet) + 1, 1) = &quot;.&quot; then sRange = Mid(sAddress, Len(sSheet) + 2)
+ End If
+ sSheet = Replace(Replace(sSheet, &quot;$&quot;, &quot;&quot;), &quot;&apos;&quot;, &quot;&quot;)
+ ElseIf InStr(sAddress, &quot;.&quot;) &gt; 0 Then
+ sSheet = Replace(Split(sAddress, &quot;.&quot;)(0), &quot;$&quot;, &quot;&quot;)
+ sRange = Replace(Split(sAddress, &quot;.&quot;)(1), &quot;$&quot;, &quot;&quot;)
+ Else
+ sSheet = sAddress
+ 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 = .XCellRange.AbsoluteName
+ .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
+
+ &apos; Store last parsed address for reuse
+ Set _LastParsedAddress = oAddress
+
+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 oAddress As Object &apos; _Address type for range description
+Dim oCursor As Object &apos; com.sun.star.sheet.XSheetCellCursor
+Dim i As Long
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ _PropertyGet = False
+
+ cstThisSub = &quot;SFDocuments.Calc.get&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+ Select Case UCase(psProperty)
+ Case UCase(&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 UCase(&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 UCase(&quot;FirstCell&quot;), UCase(&quot;FirstRow&quot;), UCase(&quot;FirstColumn&quot;) _
+ , UCase(&quot;LastCell&quot;), UCase(&quot;LastColumn&quot;), UCase(&quot;LastRow&quot;) _
+ , UCase(&quot;SheetName&quot;)
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then &apos; Avoid errors when instance is watched in Basic IDE
+ If InStr(UCase(psProperty), &quot;CELL&quot;) &gt; 0 Then _PropertyGet = &quot;&quot; Else _PropertyGet = -1
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ Set oAddress = _ParseAddress(pvArg)
+ With oAddress.XCellRange
+ Select Case UCase(psProperty)
+ Case UCase(&quot;FirstCell&quot;)
+ _PropertyGet = A1Style(.RangeAddress.StartRow + 1, .RangeAddress.StartColumn + 1, , , oAddress.XSpreadsheet.Name)
+ Case UCase(&quot;FirstColumn&quot;) : _PropertyGet = CLng(.RangeAddress.StartColumn + 1)
+ Case UCase(&quot;FirstRow&quot;) : _PropertyGet = CLng(.RangeAddress.StartRow + 1)
+ Case UCase(&quot;LastCell&quot;)
+ _PropertyGet = A1Style(.RangeAddress.EndRow + 1, .RangeAddress.EndColumn + 1, , , oAddress.XSpreadsheet.Name)
+ Case UCase(&quot;LastColumn&quot;) : _PropertyGet = CLng(.RangeAddress.EndColumn + 1)
+ Case UCase(&quot;LastRow&quot;) : _PropertyGet = CLng(.RangeAddress.EndRow + 1)
+ Case UCase(&quot;SheetName&quot;) : _PropertyGet = oAddress.XSpreadsheet.Name
+ End Select
+ End With
+ End If
+ Case UCase(&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 UCase(&quot;Region&quot;)
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ _PropertyGet = &quot;&quot;
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ Set oAddress = _ParseAddress(pvArg)
+ With oAddress
+ Set oCursor = .XSpreadsheet.createCursorByRange(.XCellRange)
+ oCursor.collapseToCurrentRegion()
+ _PropertyGet = oCursor.AbsoluteName
+ End With
+ End If
+ Case UCase(&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 UCase(&quot;Sheets&quot;)
+ _PropertyGet = _Component.getSheets.getElementNames()
+ Case UCase(&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 UCase(&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 UCase(&quot;XSheetCellCursor&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 oAddress = _ParseAddress(pvArg)
+ Set _PropertyGet = oAddress.XSpreadsheet.createCursorByRange(oAddress.XCellRange)
+ End If
+ Case UCase(&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 _QuoteSheetName(ByVal psSheetName As String) As String
+&apos;&apos;&apos; Return the given sheet name surrounded with single quotes
+&apos;&apos;&apos; when required to insert the sheet name into a Calc formula
+&apos;&apos;&apos; Enclosed single quotes are doubled
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psSheetName: the name to quote
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The quoted or unchanged sheet name
+
+Dim sSheetName As String &apos; Return value
+Dim i As Long
+
+Try:
+ &apos; Surround the sheet name with single quotes when required by the presence of single quotes
+ If InStr(psSheetName, &quot;&apos;&quot;) &gt; 0 Then
+ sSheetName = &quot;&apos;&quot; &amp; Replace(psSheetName, &quot;&apos;&quot;, &quot;&apos;&apos;&quot;) &amp; &quot;&apos;&quot;
+ Else
+ &apos; Surround the sheet name with single quotes when required by the presence of at least one of the special characters
+ sSheetName = psSheetName
+ For i = 1 To Len(cstSPECIALCHARS)
+ If InStr(sSheetName, Mid(cstSPECIALCHARS, i, 1)) &gt; 0 Then
+ sSheetName = &quot;&apos;&quot; &amp; sSheetName &amp; &quot;&apos;&quot;
+ Exit For
+ End If
+ Next i
+ End If
+
+Finally:
+ _QuoteSheetName = sSheetName
+ Exit Function
+End Function &apos; SFDocuments.SF_Calc._QuoteSheetName
+
+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 _
+ , Optional ByVal pvResetSheet 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; pvArgName: the name of the variable to be used in the error message
+&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; pvResetSheet: if True, return in pvSheetName the correct (case-sensitive) sheet name (default = False)
+&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 sSheet As String &apos; Sheet name without single quotes
+Dim lSheet As Long &apos; Index in 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
+ If IsMissing(pvResetSheet) Or IsEmpty(pvResetSheet) Then pvResetSheet = 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()
+ sSheet = Replace(pvSheetName, &quot;&apos;&quot;, &quot;&quot;)
+ If pvNew Then
+ If ScriptForge.SF_Array.Contains(vSheets, sSheet) Then GoTo CatchDuplicate
+ Else
+ If Not ScriptForge.SF_Utils._Validate(sSheet, psArgName, V_STRING, vSheets) Then GoTo Finally
+ If pvResetSheet Then
+ lSheet = ScriptForge.SF_Array.IndexOf(vSheets, sSheet, CaseSensitive := False)
+ pvSheetName = vSheets(lSheet)
+ End If
+ 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_Chart.xba b/wizards/source/sfdocuments/SF_Chart.xba
new file mode 100644
index 000000000..0538fb8af
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Chart.xba
@@ -0,0 +1,814 @@
+<?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_Chart" 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_Chart
+&apos;&apos;&apos; ========
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SF_Chart module is focused on the description of chart documents
+&apos;&apos;&apos; stored in Calc sheets.
+&apos;&apos;&apos; With this service, many chart types and chart characteristics available
+&apos;&apos;&apos; in the user interface can be read or modified.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions
+&apos;&apos;&apos; Charts have 2 distinct names:
+&apos;&apos;&apos; - an internal name, given by the LibreOffice application
+&apos;&apos;&apos; - an optional user-defined name
+&apos;&apos;&apos; In the scope of the ScriptForge libraries, the chart name is the name given by the user.
+&apos;&apos;&apos; Only when there is no user name, the internal name may be used instead.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation from the &quot;Calc&quot; service
+&apos;&apos;&apos; Either make a new chart
+&apos;&apos;&apos; calc.CreateChart(ChartName, SheetName, &quot;SheetX.A1:C8&quot;)
+&apos;&apos;&apos; or select an existing one
+&apos;&apos;&apos; calc.Charts(SheetName, ChartName)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_chart.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const CHARTEXPORTERROR = &quot;CHARTEXPORTERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object &apos; Parent Calc document
+Private ObjectType As String &apos; Must be CHART
+Private ServiceName As String
+
+&apos; Chart description
+Private _SheetName As String &apos; Name of the Calc sheet containing the chart
+Private _DrawIndex As Long &apos; Index of the chart in the sheet&apos;s draw page
+Private _ChartName As String &apos; User name
+Private _PersistentName As String &apos; Internal name
+Private _Shape As Object &apos; com.sun.star.drawing.XShape
+Private _Chart As Object &apos; com.sun.star.table.XTableChart
+Private _ChartObject As Object &apos; com.sun.star.lang.XComponent - ScChartObj
+Private _Diagram As Object &apos; com.sun.star.chart.XDiagram
+
+REM ============================================================ MODULE CONSTANTS
+
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;CHART&quot;
+ ServiceName = &quot;SFDocuments.Chart&quot;
+ _SheetName = &quot;&quot;
+ _DrawIndex = -1
+ _ChartName = &quot;&quot;
+ _PersistentName = &quot;&quot;
+ Set _Shape = Nothing
+ Set _Chart = Nothing
+ Set _ChartObject = Nothing
+ Set _Diagram = Nothing
+End Sub &apos; SFDocuments.SF_Chart Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_Chart Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDocuments.SF_Chart Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ChartType() As Variant
+&apos;&apos;&apos; The ChartType property specifies the type of chart as a string among next values:
+&apos;&apos;&apos; Pie, Bar, Donut, Column, Area, Line, XY, Bubble, Net
+ ChartType = _PropertyGet(&quot;ChartType&quot;)
+End Property &apos; SFDocuments.SF_Chart.ChartType (get)
+
+REM -----------------------------------------------------------------------------
+Property Let ChartType(Optional ByVal pvChartType As Variant)
+&apos;&apos;&apos; Set the updatable property ChartType
+ _PropertySet(&quot;ChartType&quot;, pvChartType)
+End Property &apos; SFDocuments.SF_Chart.ChartType (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Deep() As Variant
+&apos;&apos;&apos; If True, determines that in a three-dimensional bar chart the bars of each series are arranged behind each other in the z-direction.
+&apos;&apos;&apos; If False the arrangement of bars is like in two-dimensional bar charts.
+&apos;&apos;&apos; Bar and Column chart types only
+ Deep = _PropertyGet(&quot;Deep&quot;)
+End Property &apos; SFDocuments.SF_Chart.Deep (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Deep(Optional ByVal pvDeep As Variant)
+&apos;&apos;&apos; Set the updatable property Deep
+ _PropertySet(&quot;Deep&quot;, pvDeep)
+End Property &apos; SFDocuments.SF_Chart.Deep (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Dim3D() As Variant
+&apos;&apos;&apos; The Dim3D property specifies if the chart is displayed with 3D elements
+&apos;&apos;&apos; String or Boolean
+&apos;&apos;&apos; When String, must be 1 of next values: Bar, Cylinder, Cone or Pyramid
+&apos;&apos;&apos; When Boolean True, Bar is assumed; when False, no 3D to be applied
+ Dim3D = _PropertyGet(&quot;Dim3D&quot;)
+End Property &apos; SFDocuments.SF_Chart.Dim3D (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Dim3D(Optional ByVal pvDim3D As Variant)
+&apos;&apos;&apos; Set the updatable property Dim3D
+ _PropertySet(&quot;Dim3D&quot;, pvDim3D)
+End Property &apos; SFDocuments.SF_Chart.Dim3D (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Exploded() As Variant
+&apos;&apos;&apos; the offset by which pie segments in a PieDiagram (pie or donut) are dragged outside from the center.
+&apos;&apos;&apos; This value is given in percent of the radius.
+ Exploded = _PropertyGet(&quot;Exploded&quot;)
+End Property &apos; SFDocuments.SF_Chart.Exploded (get)_ChartObject
+
+REM -----------------------------------------------------------------------------
+Property Let Exploded(Optional ByVal pvExploded As Variant)
+&apos;&apos;&apos; Set the updatable property Exploded
+ _PropertySet(&quot;Exploded&quot;, pvExploded)
+End Property &apos; SFDocuments.SF_Chart.Exploded (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Filled() As Variant
+&apos;&apos;&apos; When True, the Net diagram is said of FilledNet type
+&apos;&apos;&apos; Net chart type only
+ Filled = _PropertyGet(&quot;Filled&quot;)
+End Property &apos; SFDocuments.SF_Chart.Filled (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Filled(Optional ByVal pvFilled As Variant)
+&apos;&apos;&apos; Set the updatable property Filled
+ _PropertySet(&quot;Filled&quot;, pvFilled)
+End Property &apos; SFDocuments.SF_Chart.Filled (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Legend() As Variant
+&apos;&apos;&apos; Specifies if the chart has a legend
+ Legend = _PropertyGet(&quot;Legend&quot;)
+End Property &apos; SFDocuments.SF_Chart.Legend (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Legend(Optional ByVal pvLegend As Variant)
+&apos;&apos;&apos; Set the updatable property Legend
+ _PropertySet(&quot;Legend&quot;, pvLegend)
+End Property &apos; SFDocuments.SF_Chart.Legend (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Percent() As Variant
+&apos;&apos;&apos; When True, the series of the diagram are stacked and each category sums up to 100%.
+&apos;&apos;&apos; Area, Bar, Bubble, Column and Net chart types only_ChartObject
+ Percent = _PropertyGet(&quot;Percent&quot;)
+End Property &apos; SFDocuments.SF_Chart.Percent (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Percent(Optional ByVal pvPercent As Variant)
+&apos;&apos;&apos; Set the updatable property Percent
+ _PropertySet(&quot;Percent&quot;, pvPercent)
+End Property &apos; SFDocuments.SF_Chart.Percent (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Stacked() As Variant
+&apos;&apos;&apos; When True, the series of the diagram are stacked.
+&apos;&apos;&apos; Area, Bar, Bubble, Column and Net chart types only
+ Stacked = _PropertyGet(&quot;Stacked&quot;)
+End Property &apos; SFDocuments.SF_Chart.Stacked (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Stacked(Optional ByVal pvStacked As Variant)
+&apos;&apos;&apos; Set the updatable property Stacked
+ _PropertySet(&quot;Stacked&quot;, pvStacked)
+End Property &apos; SFDocuments.SF_Chart.Stacked (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Title() As Variant
+&apos;&apos;&apos; Specifies the main title of the chart
+ Title = _PropertyGet(&quot;Title&quot;)
+End Property &apos; SFDocuments.SF_Chart.Title (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Title(Optional ByVal pvTitle As Variant)
+&apos;&apos;&apos; Set the updatable property Title
+ _PropertySet(&quot;Title&quot;, pvTitle)
+End Property &apos; SFDocuments.SF_Chart.Title (let)
+
+REM -----------------------------------------------------------------------------
+Property Get XTitle() As Variant
+&apos;&apos;&apos; Specifies the main XTitle of the chart
+ XTitle = _PropertyGet(&quot;XTitle&quot;)
+End Property &apos; SFDocuments.SF_Chart.XTitle (get)
+
+REM -----------------------------------------------------------------------------
+Property Let XTitle(Optional ByVal pvXTitle As Variant)
+&apos;&apos;&apos; Set the updatable property XTitle
+ _PropertySet(&quot;XTitle&quot;, pvXTitle)
+End Property &apos; SFDocuments.SF_Chart.XTitle (let)
+
+REM -----------------------------------------------------------------------------
+Property Get YTitle() As Variant
+&apos;&apos;&apos; Specifies the main YTitle of the chart
+ YTitle = _PropertyGet(&quot;YTitle&quot;)
+End Property &apos; SFDocuments.SF_Chart.YTitle (get)
+
+REM -----------------------------------------------------------------------------
+Property Let YTitle(Optional ByVal pvYTitle As Variant)
+&apos;&apos;&apos; Set the updatable property YTitle
+ _PropertySet(&quot;YTitle&quot;, pvYTitle)
+End Property &apos; SFDocuments.SF_Chart.YTitle (let)
+
+REM -----------------------------------------------------------------------------
+Property Get XChartObj() As Variant
+&apos;&apos;&apos; com.sun.star.lang.XComponent - ScChartObj
+ ChartType = _PropertyGet(&quot;XChartObj&quot;)
+End Property &apos; SFDocuments.SF_Chart.XChartObj (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XDiagram() As Variant
+&apos;&apos;&apos; com.sun.star.chart.XDiagram
+ ChartType = _PropertyGet(&quot;XDiagram&quot;)
+End Property &apos; SFDocuments.SF_Chart.XDiagram (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XShape() As Variant
+&apos;&apos;&apos; com.sun.star.drawing.XShape
+ ChartType = _PropertyGet(&quot;XShape&quot;)
+End Property &apos; SFDocuments.SF_Chart.XShape (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XTableChart() As Variant
+&apos;&apos;&apos; com.sun.star.table.XTableChart
+ ChartType = _PropertyGet(&quot;XTableChart&quot;)
+End Property &apos; SFDocuments.SF_Chart.XTableChart (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function ExportToFile(Optional ByVal FileName As Variant _
+ , Optional ByVal ImageType As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Store the chart as an image to the given file location
+&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; ImageType: the name of the targeted image type
+&apos;&apos;&apos; Allowed values: gif, jpeg, png (default), svg and tiff
+&apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False if the document could not be saved
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; CHARTEXPORTERROR The destination has its readonly attribute set or overwriting rejected
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oChart.ExportToFile(&quot;C:\Me\Chart2.gif&quot;, ImageType := &quot;gif&quot;, Overwrite := True)
+
+Dim bSaved As Boolean &apos; return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFile As String &apos; Alias of FileName
+Dim vStoreArguments As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim FSO As Object &apos; SF_FileSystem
+Dim oExport As Object &apos; com.sun.star.drawing.GraphicExportFilter
+Dim vImageTypes As Variant &apos; Array of permitted image types
+Dim vMimeTypes As Variant &apos; Array of corresponding mime types in the same order as vImageTypes
+
+Const cstImageTypes = &quot;gif,jpeg,png,svg,tiff&quot;
+Const cstMimeTypes = &quot;image/gif,image/jpeg,image/png,image/svg+xml,image/tiff&quot;
+
+Const cstThisSub = &quot;SFDocuments.Chart.ExportToFile&quot;
+Const cstSubArgs = &quot;FileName, [ImageType=&quot;&quot;png&quot;&quot;|&quot;&quot;gif&quot;&quot;|&quot;&quot;jpeg&quot;&quot;|&quot;&quot;svg&quot;&quot;|&quot;&quot;tiff&quot;&quot;], [Overwrite=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
+ bSaved = False
+
+Check:
+ If IsMissing(ImageType) Or IsEmpty(ImageType) Then ImageType = &quot;png&quot;
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+
+ vImageTypes = Split(cstImageTypes, &quot;,&quot;)
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ImageType, &quot;ImageType&quot;, V_STRING, vImageTypes) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ 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
+ vMimeTypes = Split(cstMimeTypes, &quot;,&quot;)
+ vStoreArguments = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;URL&quot;, sFile) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;MediaType&quot; _
+ , vMimeTypes(ScriptForge.SF_Array.IndexOf(vImageTypes, ImageType, CaseSensitive := False))) _
+ )
+ &apos; Export with the com.sun.star.drawing.GraphicExportFilter UNO service
+ Set oExport = ScriptForge.SF_Utils._GetUNOService(&quot;GraphicExportFilter&quot;)
+ With oExport
+ .setSourceDocument(_Shape)
+ .filter(vStoreArguments)
+ End With
+ bSaved = True
+
+Finally:
+ ExportToFile = bSaved
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ ScriptForge.SF_Exception.RaiseFatal(CHARTEXPORTERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Chart.ExportToFile
+
+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; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;SFDocuments.Chart.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Chart.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Chart service as an array
+
+ Methods = Array( _
+ &quot;ExportToFile&quot; _
+ , &quot;Resize&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Chart.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Chart class as an array
+
+ Properties = Array( _
+ &quot;ChartType&quot; _
+ , &quot;Deep&quot; _
+ , &quot;Dim3D&quot; _
+ , &quot;Exploded&quot; _
+ , &quot;Filled&quot; _
+ , &quot;Legend&quot; _
+ , &quot;Percent&quot; _
+ , &quot;Stacked&quot; _
+ , &quot;Title&quot; _
+ , &quot;XChartObj&quot; _
+ , &quot;XDiagram&quot; _
+ , &quot;XShape&quot; _
+ , &quot;XTableChart&quot; _
+ , &quot;XTitle&quot; _
+ , &quot;YTitle&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Chart.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Resize(Optional ByVal XPos As Variant _
+ , Optional ByVal YPos As Variant _
+ , Optional ByVal Width As Variant _
+ , Optional ByVal Height As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Move the topleft corner of a chart to new coordinates and/or modify its dimensions
+&apos;&apos;&apos; All distances are expressed in 1/100th mm
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; XPos : the vertical distance from the topleft corner
+&apos;&apos;&apos; YPos : the horizontal distance from the topleft corner
+&apos;&apos;&apos; Width : the horizontal width of the shape containing the chart
+&apos;&apos;&apos; Height : the vertical height of the shape containing the chart
+&apos;&apos;&apos; Negative or missing arguments are left unchanged
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oChart.Resize(1000, 2000, Height := 6000) &apos; Width is not changed
+
+Dim bResize As Boolean &apos; Return value
+Dim oPosition As Object &apos; com.sun.star.awt.Point
+Dim oSize As Object &apos; com.sun.star.awt.Size
+Const cstThisSub = &quot;SFDocuments.Chart.Resize&quot;
+Const cstSubArgs = &quot;[XPos], [YPos], [Width], [Height]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bResize = False
+
+Check:
+ If IsMissing(XPos) Or IsEmpty(XPos) Then XPos = -1
+ If IsMissing(YPos) Or IsEmpty(YPos) Then YPos = -1
+ If IsMissing(Height) Or IsEmpty(Height) Then Height = -1
+ If IsMissing(Width) Or IsEmpty(Width) Then Width = -1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(XPos, &quot;XPos&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(YPos, &quot;YPos&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Width, &quot;Width&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Height, &quot;Height&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ With _Shape
+ &apos; Get the current values
+ Set oPosition = .Position
+ Set oSize = .Size
+ &apos; Modify relevant elements
+ If XPos &gt;= 0 Then oPosition.X = CLng(XPos)
+ If YPos &gt;= 0 Then oPosition.Y = CLng(YPos)
+ If Width &gt; 0 Then oSize.Width = CLng(Width)
+ If Height &gt; 0 Then oSize.Height = CLng(Height)
+ &apos; Rewrite
+ .setPosition(oPosition)
+ .setSize(oSize)
+ End With
+ bResize = True
+
+Finally:
+ Resize = bResize
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Chart.Resize
+
+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.Chart.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 ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Chart.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+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
+
+Static oSession As Object &apos; Alias of SF_Session
+Dim vData As Variant &apos; Data points array of values
+
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDocuments.Chart.get&quot; &amp; psProperty
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;ChartType&quot;)
+ With _Diagram
+ Select Case .DiagramType
+ Case &quot;com.sun.star.chart.BarDiagram&quot;
+ If .Vertical Then _PropertyGet = &quot;Bar&quot; Else _PropertyGet = &quot;Column&quot;
+ Case &quot;com.sun.star.chart.PieDiagram&quot;
+ _PropertyGet = &quot;Pie&quot;
+ Case &quot;com.sun.star.chart.DonutDiagram&quot;
+ _PropertyGet = &quot;Donut&quot;
+ Case &quot;com.sun.star.chart.AreaDiagram&quot;
+ _PropertyGet = &quot;Area&quot;
+ Case &quot;com.sun.star.chart.LineDiagram&quot;
+ _PropertyGet = &quot;Line&quot;
+ Case &quot;com.sun.star.chart.XYDiagram&quot;
+ _PropertyGet = &quot;XY&quot;
+ Case &quot;com.sun.star.chart.BubbleDiagram&quot;
+ _PropertyGet = &quot;Bubble&quot;
+ Case &quot;com.sun.star.chart.NetDiagram&quot;, &quot;com.sun.star.chart.FilledNetDiagram&quot;
+ _PropertyGet = &quot;Net&quot;
+ Case Else
+ _PropertyGet = &quot;&quot;
+ End Select
+ End With
+ Case UCase(&quot;Deep&quot;)
+ If oSession.HasUnoProperty(_Diagram, &quot;Deep&quot;) Then _PropertyGet = _Diagram.Deep Else _PropertyGet = False
+ Case UCase(&quot;Dim3D&quot;)
+ If oSession.HasUnoProperty(_Diagram, &quot;Dim3D&quot;) Then
+ If _Diagram.Dim3D Then
+ If oSession.HasUnoProperty(_Diagram, &quot;SolidType&quot;) Then
+ Select Case _Diagram.SolidType
+ Case com.sun.star.chart.ChartSolidType.RECTANGULAR_SOLID : _PropertyGet = &quot;Bar&quot;
+ Case com.sun.star.chart.ChartSolidType.CYLINDER : _PropertyGet = &quot;Cylinder&quot;
+ Case com.sun.star.chart.ChartSolidType.CONE : _PropertyGet = &quot;Cone&quot;
+ Case com.sun.star.chart.ChartSolidType.PYRAMID : _PropertyGet = &quot;Pyramid&quot;
+ End Select
+ Else
+ _PropertyGet = _Diagram.Dim3D
+ End If
+ Else
+ _PropertyGet = False
+ End If
+ Else
+ _PropertyGet = False
+ End If
+ Case UCase(&quot;Exploded&quot;)
+ If oSession.HasUnoProperty(_ChartObject, &quot;Data&quot;) Then
+ &apos; All data points are presumed exploded with the same coefficient. Determine the (0, 0)th
+ With _ChartObject
+ vData = .Data.Data
+ _PropertyGet = 0
+ If IsArray(vData) Then
+ If UBound(vData) &gt;= 0 Then
+ If IsArray(vData(0)) Then
+ If UBound(vData(0)) &gt;= 0 Then _PropertyGet = _Diagram.getDataPointProperties(0, 0).SegmentOffset
+ End If
+ End If
+ End If
+ End With
+ End If
+ Case UCase(&quot;Filled&quot;)
+ _PropertyGet = ( _Diagram.DiagramType = &quot;com.sun.star.chart.FilledNetDiagram&quot; )
+ Case UCase(&quot;Legend&quot;)
+ If oSession.HasUnoProperty(_ChartObject, &quot;HasLegend&quot;) Then _PropertyGet = _ChartObject.HasLegend Else _PropertyGet = False
+ Case UCase(&quot;Percent&quot;)
+ If oSession.HasUnoProperty(_Diagram, &quot;Percent&quot;) Then _PropertyGet = _Diagram.Percent Else _PropertyGet = False
+ Case UCase(&quot;Stacked&quot;)
+ If oSession.HasUnoProperty(_Diagram, &quot;Stacked&quot;) Then _PropertyGet = _Diagram.Stacked Else _PropertyGet = False
+ Case UCase(&quot;Title&quot;)
+ If oSession.HasUnoProperty(_ChartObject, &quot;HasMainTitle&quot;) Then
+ If _ChartObject.HasMainTitle Then _PropertyGet = _ChartObject.Title.String Else _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;XTitle&quot;)
+ If oSession.HasUnoProperty(_Diagram, &quot;HasXAxisTitle&quot;) Then
+ If _Diagram.HasXAxisTitle Then _PropertyGet = _Diagram.XAxisTitle.String Else _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;YTitle&quot;)
+ If oSession.HasUnoProperty(_Diagram, &quot;HasYAxisTitle&quot;) Then
+ If _Diagram.HasYAxisTitle Then _PropertyGet = _Diagram.YAxisTitle.String Else _PropertyGet = &quot;&quot;
+ End If
+ Case UCase(&quot;XChartObj&quot;)
+ Set _PropertyGet = _ChartObject
+ Case UCase(&quot;XDiagram&quot;)
+ Set _PropertyGet = _Diagram
+ Case UCase(&quot;XShape&quot;)
+ Set _PropertyGet = _Shape
+ Case UCase(&quot;XTableChart&quot;)
+ Set _PropertyGet = _Chart
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFDocuments.SF_Chart._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(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
+
+Dim bSet As Boolean &apos; Return value
+Static oSession As Object &apos; Alias of SF_Session
+Dim sChartType As String &apos; Diagram type
+Dim bDim3D As Boolean &apos; Alias of Dim3D property of diagram
+Dim bVertical As Boolean &apos; When True, chart type is a bar, not a column
+Dim vData As Variant &apos; Data points array of values
+Dim i As Long, j As Long
+Const cstChart = &quot;com.sun.star.chart.&quot;
+
+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.Chart.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not [_Parent]._IsStillAlive() Then GoTo Catch
+
+ bSet = True
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;ChartType&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;ChartType&quot;, V_STRING _
+ , Array(&quot;Bar&quot;, &quot;Column&quot;, &quot;Pie&quot;, &quot;Donut&quot;, &quot;Area&quot;, &quot;Line&quot;, &quot;XY&quot;, &quot;Bubble&quot;, &quot;Net&quot;) _
+ ) Then GoTo Finally
+ With _Diagram
+ &apos; Specify the targeted chart type
+ Select Case UCase(pvValue)
+ Case &quot;BAR&quot;, &quot;COLUMN&quot; : sChartType = cstChart &amp; &quot;BarDiagram&quot;
+ Case &quot;PIE&quot; : sChartType = cstChart &amp; &quot;PieDiagram&quot;
+ Case &quot;DONUT&quot; : sChartType = cstChart &amp; &quot;DonutDiagram&quot;
+ Case &quot;AREA&quot; : sChartType = cstChart &amp; &quot;AreaDiagram&quot;
+ Case &quot;LINE&quot; : sChartType = cstChart &amp; &quot;LineDiagram&quot;
+ Case &quot;XY&quot; : sChartType = cstChart &amp; &quot;XYDiagram&quot;
+ Case &quot;BUBBLE&quot; : sChartType = cstChart &amp; &quot;BubbleDiagram&quot;
+ Case &quot;NET&quot; : sChartType = cstChart &amp; &quot;NetDiagram&quot;
+ End Select
+ &apos; If there is no change, do nothing
+ If sChartType &lt;&gt; .DiagramType Then
+ &apos; Some combinations old type =&gt; new type require the cancellation of 3D graphs
+ bDim3D = .Dim3D
+ .Dim3D = False
+ _ChartObject.createInstance(sChartType)
+ Set _Diagram = _ChartObject.Diagram
+ .Dim3D = bDim3D
+ End If
+ If UCase(pvValue) = &quot;BAR&quot; Or UCase(pvValue) = &quot;COLUMN&quot; Then .Vertical = ( UCase(pvValue) = &quot;BAR&quot; )
+ End With
+ Case UCase(&quot;Deep&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Deep&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_Diagram, &quot;Deep&quot;) Then _Diagram.Deep = pvValue
+ Case UCase(&quot;Dim3D&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Dim3D&quot;, Array(ScriptForge.V_Boolean, V_STRING) _
+ , Array(False, True, &quot;Bar&quot;, &quot;Cylinder&quot;, &quot;Cone&quot;, &quot;Pyramid&quot;) _
+ ) Then GoTo Finally
+ With _Diagram
+ If oSession.HasUnoProperty(_Diagram, &quot;Dim3D&quot;) Then
+ If _Diagram.DiagramType = &quot;com.sun.star.chart.BubbleDiagram&quot; Then
+ .Dim3D = False &apos; Force False value to avoid empty graph
+ ElseIf VarType(pvValue) = V_STRING Then
+ bVertical = .Vertical
+ .Dim3D = True
+ .Vertical = bVertical
+ If oSession.HasUnoProperty(_Diagram, &quot;SolidType&quot;) Then
+ If .DiagramType = cstChart &amp; &quot;BarDiagram&quot; Then
+ Select Case UCase(pvValue)
+ Case &quot;BAR&quot; : .SolidType = com.sun.star.chart.ChartSolidType.RECTANGULAR_SOLID
+ Case &quot;CYLINDER&quot; : .SolidType = com.sun.star.chart.ChartSolidType.CYLINDER
+ Case &quot;CONE&quot; : .SolidType = com.sun.star.chart.ChartSolidType.CONE
+ Case &quot;PYRAMID&quot; : .SolidType = com.sun.star.chart.ChartSolidType.PYRAMID
+ End Select
+ Else
+ .SolidType = 0
+ End If
+ End If
+ Else &apos; Boolean
+ If oSession.HasUnoProperty(_Diagram, &quot;SolidType&quot;) Then .SolidType = 0
+ .Dim3D = pvValue
+ End If
+ End If
+ End With
+ Case UCase(&quot;Exploded&quot;)
+ If oSession.HasUnoProperty(_ChartObject, &quot;Data&quot;) And _Diagram.DiagramType &lt;&gt; &quot;com.sun.star.chart.BubbleDiagram&quot; Then
+ &apos; All data points are presumed exploded with the same coefficient
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Exploded&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ With _ChartObject
+ vData = .Data.Data
+ If IsArray(vData) Then
+ For i = 0 To UBound(vData)
+ If IsArray(vData(i)) Then
+ For j = 0 To UBound(vData(i))
+ _Diagram.getDataPointProperties(i, j).SegmentOffset = CLng(pvValue)
+ Next j
+ End If
+ Next i
+ End If
+ End With
+ End If
+ Case UCase(&quot;Filled&quot;)
+ &apos; Flipflop between NetDiagram and FilledNetDiagram
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Filled&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ With _Diagram
+ &apos; Specify the targeted chart type
+ sChartType = cstChart &amp; Iif(pvValue, &quot;Filled&quot;, &quot;&quot;) &amp; &quot;NetDiagram&quot;
+ &apos; If there is no change, do nothing
+ If sChartType &lt;&gt; .DiagramType then
+ &apos; Do not apply if the chart type not = &quot;Net&quot;
+ If (pvValue And .DiagramType = cstChart &amp; &quot;NetDiagram&quot;) _
+ Or (Not pvValue And .DiagramType = cstChart &amp; &quot;FilledNetDiagram&quot;) Then
+ &apos; Some combinations old type =&gt; new type require the cancellation of 3D graphs
+ bDim3D = .Dim3D
+ .Dim3D = False
+ _ChartObject.createInstance(sChartType)
+ Set _Diagram = _ChartObject.Diagram
+ .Dim3D = bDim3D
+ End If
+ End If
+ End With
+ Case UCase(&quot;Legend&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Legend&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ChartObject, &quot;HasLegend&quot;) Then _ChartObject.HasLegend = pvValue
+ Case UCase(&quot;Percent&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Percent&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_Diagram, &quot;Percent&quot;) Then
+ _Diagram.Stacked = pvValue
+ _Diagram.Percent = pvValue
+ End If
+ Case UCase(&quot;Stacked&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Stacked&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_Diagram, &quot;Stacked&quot;) Then
+ _Diagram.Stacked = pvValue
+ If Not pvValue Then _Diagram.Percent = False
+ End If
+ Case UCase(&quot;Title&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Title&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ChartObject, &quot;HasMainTitle&quot;) Then
+ _ChartObject.HasMainTitle = ( Len(pvValue) &gt; 0 )
+ If Len(pvValue) &gt; 0 Then _ChartObject.Title.String = pvValue
+ End If
+ Case UCase(&quot;XTitle&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;XTitle&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_Diagram, &quot;HasXAxisTitle&quot;) Then
+ _Diagram.HasXAxisTitle = ( Len(pvValue) &gt; 0 )
+ If Len(pvValue) &gt; 0 Then _Diagram.XAxisTitle.String = pvValue
+ End If
+ Case UCase(&quot;YTitle&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;YTitle&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_Diagram, &quot;HasYAxisTitle&quot;) Then
+ _Diagram.HasYAxisTitle = ( Len(pvValue) &gt; 0 )
+ If Len(pvValue) &gt; 0 Then _Diagram.YAxisTitle.String = pvValue
+ End If
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bSet = False
+ GoTo Finally
+End Function &apos; SFDocuments.SF_FormControl._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Chart instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Chart]: Name - Type
+
+ _Repr = &quot;[Chart]: &quot; &amp; ChartName &amp; &quot; - &quot; &amp; ChartType
+
+End Function &apos; SFDocuments.SF_Chart._Repr
+
+REM ============================================ END OF SFDOCUMENTS.SF_CHART
+</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 000000000..c54409445
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Document.xba
@@ -0,0 +1,1504 @@
+<?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; managing and manipulating LibreOffice documents
+&apos;&apos;&apos;
+&apos;&apos;&apos; Some methods are generic for all types of documents: they are combined in the
+&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_Base, ...
+&apos;&apos;&apos;
+&apos;&apos;&apos; Documents might contain forms. The current service gives access to the &quot;SFDocuments.Form&quot; service
+&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; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_document.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const DOCUMENTDEADERROR = &quot;DOCUMENTDEADERROR&quot;
+Private Const DOCUMENTSAVEERROR = &quot;DOCUMENTSAVEERROR&quot;
+Private Const DOCUMENTSAVEASERROR = &quot;DOCUMENTSAVEASERROR&quot;
+Private Const DOCUMENTREADONLYERROR = &quot;DOCUMENTREADONLYERROR&quot;
+
+Private Const FORMDEADERROR = &quot;FORMDEADERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private [_SubClass] As Object &apos; Subclass instance
+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
+
+Const ISDOCFORM = 1 &apos; Form is stored in a Writer document
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ Set [_SubClass] = 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 ExportFilters() As Variant
+&apos;&apos;&apos; Returns the list of the export filter names applicable to the current document
+&apos;&apos;&apos; as a zero-based array of strings
+&apos;&apos;&apos; Import/Export filters are included
+ ExportFilters = _PropertyGet(&quot;ExportFilters&quot;)
+End Property &apos; SFDocuments.SF_Document.ExportFilters
+
+REM -----------------------------------------------------------------------------
+Property Get ImportFilters() As Variant
+&apos;&apos;&apos; Returns the list of the import filter names applicable to the current document
+&apos;&apos;&apos; as a zero-based array of strings
+&apos;&apos;&apos; Import/Export filters are included
+ ImportFilters = _PropertyGet(&quot;ImportFilters&quot;)
+End Property &apos; SFDocuments.SF_Document.ImportFilters
+
+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;, ScriptForge.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 CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ , Optional ByRef _Document As Variant _
+ ) As Object
+&apos;&apos;&apos; Create a new menu entry in the document&apos;s menubar
+&apos;&apos;&apos; The menu is not intended to be saved neither in the LibreOffice global environment, nor in the document
+&apos;&apos;&apos; The method returns a SFWidgets.Menu instance. Its methods let define the menu further.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuHeader: the name/header of the menu
+&apos;&apos;&apos; Before: the place where to put the new menu on the menubar (string or number &gt;= 1)
+&apos;&apos;&apos; When not found =&gt; last position
+&apos;&apos;&apos; SubmenuChar: the delimiter used in menu trees. Default = &quot;&gt;&quot;
+&apos;&apos;&apos; _Document: undocumented argument to designate the document where the menu will be located
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SFWidgets.Menu instance or Nothing
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim oMenu As Object
+&apos;&apos;&apos; Set oMenu = oDoc.CreateMenu(&quot;My menu&quot;, Before := &quot;Styles&quot;)
+&apos;&apos;&apos; With oMenu
+&apos;&apos;&apos; .AddItem(&quot;Item 1&quot;, Command := &quot;About&quot;)
+&apos;&apos;&apos; &apos;...
+&apos;&apos;&apos; .Dispose() &apos; When definition is complete, the menu instance may be disposed
+&apos;&apos;&apos; End With
+&apos;&apos;&apos; &apos; ...
+
+Dim oMenu As Object &apos; return value
+Const cstThisSub = &quot;SFDocuments.Document.CreateMenu&quot;
+Const cstSubArgs = &quot;MenuHeader, [Before=&quot;&quot;&quot;&quot;], [SubmenuChar=&quot;&quot;&gt;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oMenu = Nothing
+
+Check:
+ If IsMissing(Before) Or IsEmpty(Before) Then Before = &quot;&quot;
+ If IsMissing(SubmenuChar) Or IsEmpty(SubmenuChar) Then SubmenuChar = &quot;&quot;
+ If IsMissing(_Document) Or IsEmpty(_Document) Or IsNull(_Document) Then Set _Document = _Component
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Before, &quot;Before&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SubmenuChar, &quot;SubmenuChar&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oMenu = ScriptForge.SF_Services.CreateScriptService(&quot;SFWidgets.Menu&quot;, _Document, MenuHeader, Before, SubmenuChar)
+
+Finally:
+ Set CreateMenu = oMenu
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.CreateMenu
+
+REM -----------------------------------------------------------------------------
+Public Function ExportAsPDF(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Pages As Variant _
+ , Optional ByVal Password As Variant _
+ , Optional ByVal Watermark As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Store the document to the given file location in PDF format
+&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; Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
+&apos;&apos;&apos; Password: password to open the document
+&apos;&apos;&apos; Watermark: the text for a watermark to be drawn on every page of the exported PDF file
+&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.ExportAsPDF(&quot;C:\Me\myDoc.pdf&quot;, Overwrite := True)
+
+Dim bSaved As Boolean &apos; return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFile As String &apos; Alias of FileName
+Dim sFilter As String &apos; One of the pdf filter names
+Dim vFilterData As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim FSO As Object &apos; SF_FileSystem
+Const cstThisSub = &quot;SFDocuments.Document.ExportAsPDF&quot;
+Const cstSubArgs = &quot;FileName, [Overwrite=False], [Pages=&quot;&quot;&quot;&quot;], [Password=&quot;&quot;&quot;&quot;], [Watermark=&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(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
+ If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
+ If IsMissing(Watermark) Or IsEmpty(Watermark) Then Watermark = &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;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(Watermark, &quot;Watermark&quot;, V_STRING) Then GoTo Finally
+ 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
+ sFilter = LCase(_DocumentType) &amp; &quot;_pdf_Export&quot;
+ &apos; FilterData parameters are added only if they are meaningful
+ vFilterData = Array()
+ If Len(Pages) &gt; 0 Then
+ vFilterData = ScriptForge.SF_Array.Append(vFilterData _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;PageRange&quot;, Pages))
+ End If
+ If Len(Password) &gt; 0 Then
+ vFilterData = ScriptForge.SF_Array.Append(vFilterData _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;EncryptFile&quot;, True) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;DocumentOpenPassword&quot;, Password))
+ End If
+ If Len(Watermark) &gt; 0 Then
+ vFilterData = ScriptForge.SF_Array.Append(vFilterData _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;Watermark&quot;, Watermark))
+ End If
+
+ &apos; Finalize properties and export
+ vProperties = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, sFilter) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterData&quot;, vFilterData))
+ _Component.StoreToURL(sFile, vProperties)
+ bSaved = True
+
+Finally:
+ ExportAsPDF = 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;, &quot;PDF Export&quot;)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.ExportAsPDF
+
+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 Document service as an array
+
+ Methods = Array( _
+ &quot;Activate&quot; _
+ , &quot;CloseDocument&quot; _
+ , &quot;CreateMenu&quot; _
+ , &quot;ExportAsPDF&quot; _
+ , &quot;PrintOut&quot; _
+ , &quot;RemoveMenu&quot; _
+ , &quot;RunCommand&quot; _
+ , &quot;Save&quot; _
+ , &quot;SaveAs&quot; _
+ , &quot;SaveCopyAs&quot; _
+ , &quot;SetPrinter&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Document.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function PrintOut(Optional ByVal Pages As Variant _
+ , Optional ByVal Copies As Variant _
+ , Optional ByRef _Document As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Send the content of the document to the printer.
+&apos;&apos;&apos; The printer might be defined previously by default, by the user or by the SetPrinter() method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
+&apos;&apos;&apos; Copies: the number of copies
+&apos;&apos;&apos; _Document: undocumented argument to designate the document to print when called from a subclass
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.PrintOut(&quot;1-4;10;15-18&quot;, Copies := 2)
+
+Dim bPrint As Boolean &apos; Return value
+Dim vPrintGoal As Variant &apos; Array of property values
+
+Const cstThisSub = &quot;SFDocuments.Document.PrintOut&quot;
+Const cstSubArgs = &quot;[Pages=&quot;&quot;&quot;&quot;], [Copies=1]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrint = False
+
+Check:
+ If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
+ If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
+ If IsMissing(_Document) Or IsEmpty(_Document) Or IsNull(_Document) Then Set _Document = _Component
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Copies, &quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ vPrintGoal = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;CopyCount&quot;, CInt(Copies)) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;Collate&quot;, True) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;Pages&quot;, Pages) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;Wait&quot;, False) _
+ )
+
+ _Document.Print(vPrintGoal)
+ bPrint = True
+
+Finally:
+ PrintOut = bPrint
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.PrintOut
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Document class as an array
+
+ Properties = Array( _
+ &quot;CustomProperties&quot; _
+ , &quot;Description&quot; _
+ , &quot;DocumentProperties&quot; _
+ , &quot;DocumentType&quot; _
+ , &quot;ExportFilters&quot; _
+ , &quot;ImportFilters&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 Function RemoveMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByRef _Document As Variant _
+) As Boolean
+&apos;&apos;&apos; Remove a menu entry in the document&apos;s menubar
+&apos;&apos;&apos; The removal is not intended to be saved neither in the LibreOffice global environment, nor in the document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuHeader: the name/header of the menu, without tilde &quot;~&quot;, as a case-sensitive string
+&apos;&apos;&apos; _Document: undocumented argument to designate the document where the menu is located
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.RemoveMenu(&quot;File&quot;)
+&apos;&apos;&apos; &apos; ...
+
+Dim bRemove As Boolean &apos; Return value
+Dim oLayout As Object &apos; com.sun.star.comp.framework.LayoutManager
+Dim oMenuBar As Object &apos; com.sun.star.awt.XMenuBar or stardiv.Toolkit.VCLXMenuBar
+Dim sName As String &apos; Menu name
+Dim iMenuId As Integer &apos; Menu identifier
+Dim iMenuPosition As Integer &apos; Menu position &gt;= 0
+Dim i As Integer
+Const cstTilde = &quot;~&quot;
+
+Const cstThisSub = &quot;SFDocuments.Document.RemoveMenu&quot;
+Const cstSubArgs = &quot;MenuHeader&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRemove = False
+
+Check:
+ If IsMissing(_Document) Or IsEmpty(_Document) Or IsNull(_Document) Then Set _Document = _Component
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oLayout = _Document.CurrentController.Frame.LayoutManager
+ Set oMenuBar = oLayout.getElement(&quot;private:resource/menubar/menubar&quot;).XMenuBar
+
+ &apos; Search the menu identifier to remove by its name, Mark its position
+ With oMenuBar
+ iMenuPosition = -1
+ For i = 0 To .ItemCount - 1
+ iMenuId = .getItemId(i)
+ sName = Replace(.getItemText(iMenuId), cstTilde, &quot;&quot;)
+ If MenuHeader= sName Then
+ iMenuPosition = i
+ Exit For
+ End If
+ Next i
+ &apos; Remove the found menu item
+ If iMenuPosition &gt;= 0 Then
+ .removeItem(iMenuPosition, 1)
+ bRemove = True
+ End If
+ End With
+
+Finally:
+ RemoveMenu = bRemove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.RemoveMenu
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant _
+ , ParamArray Args As Variant _
+ )
+&apos;&apos;&apos; Run on the current document window the given menu command. The command is executed with or 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 on next page: https://wiki.documentfoundation.org/Development/DispatchCommands
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Command: Case-sensitive. The command itself is not checked.
+&apos;&apos;&apos; If the command does not contain the &quot;.uno:&quot; prefix, it is added.
+&apos;&apos;&apos; If nothing happens, then the command is probably wrong
+&apos;&apos;&apos; Args: Pairs of arguments name (string), value (any)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.RunCommand(&quot;EditDoc&quot;, &quot;Editable&quot;, False) &apos; Toggle edit mode
+
+Dim vArgs As Variant &apos; Alias of Args
+Dim oDispatch &apos; com.sun.star.frame.DispatchHelper
+Dim vProps As Variant &apos; Array of PropertyValues
+Dim vValue As Variant &apos; A single value argument
+Dim sCommand As String &apos; Alias of Command
+Dim i As Long
+Const cstPrefix = &quot;.uno:&quot;
+
+Const cstThisSub = &quot;SFDocuments.Document.RunCommand&quot;
+Const cstSubArgs = &quot;Command, [arg0Name, arg0Value], [arg1Name, arg1Value], ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ &apos; When called from a subclass (Calc, Writer, ..) the arguments are gathered into one single array item
+ vArgs = Args
+ If IsArray(Args) Then
+ If UBound(Args) &gt;= 0 And IsArray(Args(0)) Then vArgs = Args(0)
+ End If
+ 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
+ If Not ScriptForge.SF_Utils._ValidateArray(vArgs, &quot;Args&quot;, 1) Then GoTo Finally
+ For i = 0 To UBound(vArgs) - 1 Step 2
+ If Not ScriptForge.SF_Utils._Validate(vArgs(i), &quot;Arg&quot; &amp; CStr(i/2) &amp; &quot;Name&quot;, V_STRING) Then GoTo Finally
+ Next i
+ End If
+
+Try:
+ &apos; Build array of property values
+ vProps = Array()
+ For i = 0 To UBound(vArgs) - 1 Step 2
+ If IsEmpty(vArgs(i + 1)) Then vValue = Null Else vValue = vArgs(i + 1)
+ vProps = ScriptForge.SF_Array.Append(vProps, ScriptForge.SF_Utils._MakePropertyValue(vArgs(i), vValue))
+ Next i
+ Set oDispatch = ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
+ If ScriptForge.SF_String.StartsWith(Command, cstPrefix) Then sCommand = Command Else sCommand = cstPrefix &amp; Command
+ oDispatch.executeDispatch(_Frame, sCommand, &quot;&quot;, 0, vProps)
+
+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;, ScriptForge.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;, ScriptForge.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 -----------------------------------------------------------------------------
+Public Function SetPrinter(Optional ByVal Printer As Variant _
+ , Optional ByVal Orientation As Variant _
+ , Optional ByVal PaperFormat As Variant _
+ , Optional ByRef _PrintComponent As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Define the printer options for the document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Printer: the name of the printer queue where to print to
+&apos;&apos;&apos; When absent or space, the default printer is set
+&apos;&apos;&apos; Orientation: either &quot;PORTRAIT&quot; or &quot;LANDSCAPE&quot;. Left unchanged when absent
+&apos;&apos;&apos; PaperFormat: one of next values
+&apos;&apos;&apos; &quot;A3&quot;, &quot;A4&quot;, &quot;A5&quot;, &quot;B4&quot;, &quot;B5&quot;, &quot;LETTER&quot;, &quot;LEGAL&quot;, &quot;TABLOID&quot;
+&apos;&apos;&apos; Left unchanged when absent
+&apos;&apos;&apos; _PrintComponent: undocumented argument to determine the component
+&apos;&apos;&apos; Useful typically to apply printer settings on a Base form document
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SetPrinter(Orientation := &quot;PORTRAIT&quot;)
+
+Dim bPrinter As Boolean &apos; Return value
+Dim vPrinters As Variant &apos; Array of known printers
+Dim vOrientations As Variant &apos; Array of allowed paper orientations
+Dim vPaperFormats As Variant &apos; Array of allowed formats
+Dim vPrinterSettings As Variant &apos; Array of property values
+Dim oPropertyValue As New com.sun.star.beans.PropertyValue
+ &apos; A single property value item
+Const cstThisSub = &quot;SFDocuments.Document.SetPrinter&quot;
+Const cstSubArgs = &quot;[Printer=&quot;&quot;&quot;&quot;], [Orientation=&quot;&quot;PORTRAIT&quot;&quot;|&quot;&quot;LANDSCAPE&quot;&quot;]&quot; _
+ &amp; &quot;, [PaperFormat=&quot;&quot;A3&quot;&quot;|&quot;&quot;A4&quot;&quot;|&quot;&quot;A5&quot;&quot;|&quot;&quot;B4&quot;&quot;|&quot;&quot;B5&quot;&quot;|&quot;&quot;LETTER&quot;&quot;|&quot;&quot;LEGAL&quot;&quot;|&quot;&quot;TABLOID&quot;&quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrinter = False
+
+Check:
+ If IsMissing(Printer) Or IsEmpty(Printer) Then Printer = &quot;&quot;
+ If IsMissing(Orientation) Or IsEmpty(Orientation) Then Orientation = &quot;&quot;
+ If IsMissing(PaperFormat) Or IsEmpty(PaperFormat) Then PaperFormat = &quot;&quot;
+ If IsMissing(_PrintComponent) Or IsEmpty(_PrintComponent) Then Set _PrintComponent = _Component
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional validation
+ If Not _IsStillAlive() Then GoTo Finally
+ If VarType(Printer) = V_STRING Then
+ vPrinters = ScriptForge.SF_Platform.Printers
+ If Len(Printer) &gt; 0 Then
+ If Not ScriptForge.SF_Utils._Validate(Printer, &quot;Printer&quot;, V_STRING, vPrinters) Then GoTo Finally
+ End If
+ Else
+ If Not ScriptForge.SF_Utils._Validate(Printer, &quot;Printer&quot;, V_STRING) Then GoTo Finally &apos; Manage here the VarType error
+ End If
+ If VarType(Orientation) = V_STRING Then
+ vOrientations = Array(&quot;PORTRAIT&quot;, &quot;LANDSCAPE&quot;)
+ If Len(Orientation) &gt; 0 Then
+ If Not ScriptForge.SF_Utils._Validate(Orientation, &quot;Orientation&quot;, V_STRING, vOrientations) Then GoTo Finally
+ End If
+ Else
+ If Not ScriptForge.SF_Utils._Validate(Orientation, &quot;Orientation&quot;, V_STRING) Then GoTo Finally
+ End If
+ If VarType(PaperFormat) = V_STRING Then
+ vPaperFormats = Array(&quot;A3&quot;, &quot;A4&quot;, &quot;A5&quot;, &quot;B4&quot;, &quot;B5&quot;, &quot;LETTER&quot;, &quot;LEGAL&quot;, &quot;TABLOID&quot;)
+ If Len(PaperFormat) &gt; 0 Then
+ If Not ScriptForge.SF_Utils._Validate(PaperFormat, &quot;PaperFormat&quot;, V_STRING, vPaperFormats) Then GoTo Finally
+ End If
+ Else
+ If Not ScriptForge.SF_Utils._Validate(PaperFormat, &quot;PaperFormat&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ With _PrintComponent
+ Set oPropertyValue = ScriptForge.SF_Utils._MakePropertyValue(&quot;Name&quot;, Iif(Len(Printer) &gt; 0, Printer, vPrinters(0)))
+ vPrinterSettings = Array(oPropertyValue)
+ If Len(Orientation) &gt; 0 Then
+ vPrinterSettings = ScriptForge.SF_Utils._SetPropertyValue(vPrinterSettings, &quot;PaperOrientation&quot; _
+ , ScriptForge.SF_Array.IndexOf(vOrientations, Orientation, CaseSensitive := False))
+ End If
+ If Len(PaperFormat) &gt; 0 Then
+ vPrinterSettings = ScriptForge.SF_Utils._SetPropertyValue(vPrinterSettings, &quot;PaperFormat&quot; _
+ , ScriptForge.SF_Array.IndexOf(vPaperFormats, PaperFormat, CaseSensitive := False))
+ End If
+ .setPrinter(vPrinterSettings)
+ End With
+ bPrinter = True
+
+Finally:
+ SetPrinter = bPrinter
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.SetPrinter
+
+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 _GetFilterNames(ByVal pbExport As Boolean) As Variant
+&apos;&apos;&apos; Returns the list of export (pbExport = True) or import filters
+&apos;&apos;&apos; applicable to the current document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbExport: True for export, False for import
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based array of strings
+
+Dim vFilters As Variant &apos; Return value
+Dim sIdentifier As String &apos; Document service, like com.sun.star.text.TextDocument
+Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
+Dim vAllFilters As Variant &apos; The full list of installed filters
+Dim sFilter As String &apos; A single filter name
+Dim iCount As Integer &apos; Filters counter
+Dim vFilter As Variant &apos; A filter descriptor as an array of Name/Value pairs
+Dim sType As String &apos; The filter type to be compared with the document service
+Dim lFlags As Long &apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Office_Development#Properties_of_a_Filter
+Dim bExport As Boolean &apos; Filter valid for export when True
+Dim bImport As Boolean &apos; Filter valid for import when True
+Dim bImportExport As Boolean &apos; Filter valid both for import and export when True
+
+ vFilters = Array()
+ On Local Error GoTo Finally &apos; Return empty or partial list if error
+
+Try:
+ sIdentifier = _Component.Identifier
+ Set oFilterFactory = ScriptForge.SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
+ vAllFilters = oFilterFactory.getElementNames()
+ ReDim vFilters(0 To UBound(vAllFilters))
+ iCount = -1
+
+ For Each sFilter In vAllFilters
+ vFilter = oFilterFactory.getByName(sFilter)
+ sType = vFilter(12).Value &apos; Hard-coded index for document types
+ If sType = sIdentifier Then
+ lFlags = vFilter(10).Value &apos; Hard-coded index for flags
+ &apos; export: flag is even
+ &apos; import: flag is odd and flag/2 is even
+ &apos; import/export: flag is odd and flag/2 is odd
+ bExport = ( lFlags Mod 2 = 0 )
+ bImport = ( (lFlags Mod 2 = 1) And ((lFlags \ 2) Mod 2 = 0) )
+ bImportExport = ( (lFlags Mod 2 = 1) And ((lFlags \ 2) Mod 2 = 1) )
+ &apos; Select filter ?
+ If bImportExport _
+ Or (pbExport And bExport) _
+ Or (Not pbExport And bImport) Then
+ iCount = iCount + 1
+ vFilters(iCount) = sFilter
+ End If
+ End If
+ Next sFilter
+
+ If iCount &gt; -1 Then
+ ReDim Preserve vFilters(0 To iCount)
+ End If
+
+Finally:
+ _GetFilterNames = vFilters
+ Exit Function
+End Function &apos; SFDocuments.SF_Document._GetFilterNames
+
+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;ExportFilters&quot;
+ _PropertyGet = _GetFilterNames(True)
+ Case &quot;ImportFilters&quot;
+ _PropertyGet = _GetFilterNames(False)
+ 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_DocumentListener.xba b/wizards/source/sfdocuments/SF_DocumentListener.xba
new file mode 100644
index 000000000..fbb0271bb
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_DocumentListener.xba
@@ -0,0 +1,114 @@
+<?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_DocumentListener" 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_DocumentListener
+&apos;&apos;&apos; ===================
+&apos;&apos;&apos; The current module is dedicated to the management of document events + listeners, triggered by user actions,
+&apos;&apos;&apos; which cannot be defined with the Basic IDE
+&apos;&apos;&apos;
+&apos;&apos;&apos; Concerned listeners:
+&apos;&apos;&apos; com.sun.star.sheet.XRangeSelectionListener
+&apos;&apos;&apos; allowing a user to select a cell range at any moment
+&apos;&apos;&apos;
+&apos;&apos;&apos; The described events/listeners are processed by UNO listeners
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ================================================================= DEFINITIONS
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private _SelectedRange As String &apos; The selected range is returned by a &quot;done&quot; event
+Private _RangeSelectionFinished As Boolean &apos; Flag indicating that the interaction with the user has stopped
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function RunRangeSelector(ByRef poComponent As Object _
+ , ByRef pvPropertyValues As Variant _
+ ) As String
+&apos;&apos;&apos; Called from the SF_Calc.OpenRangeSelector() method
+&apos;&apos;&apos; Opens a non-modal dialog with a text box,
+&apos;&apos;&apos; let the user make a selection in the current or another sheet and
+&apos;&apos;&apos; returns the selected area as a string.
+
+Dim oController As Object &apos; com.sun.star.frame.Controller
+Dim oListener As Object &apos; com.sun.star.sheet.XRangeSelectionListener
+Dim lCountLoops As Long &apos; Sleep cycles counter
+
+Const cstListenerPrefix = &quot;_SFRGSEL_&quot; &apos; Prefix used for naming events Subs
+Const cstSleep = 50 &apos; Sleep steps in ms while waiting for the end of the interaction
+Const cstMaxSleep = (60 * 5 * 1000) / cstSleep &apos; Never sleep more than 5 minutes. Afterwards, processing continues
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Try:
+ &apos; Create the listener
+ Set oController = poComponent.CurrentController
+ Set oListener = CreateUnoListener(cstListenerPrefix, &quot;com.sun.star.sheet.XRangeSelectionListener&quot;)
+ oController.addRangeSelectionListener(oListener)
+
+ &apos; Open the selector
+ _SelectedRange = &quot;&quot;
+ _RangeSelectionFinished = False
+ oController.startRangeSelection(pvPropertyValues)
+
+ &apos; Dummy thread synchronization
+ lCountLoops = 0
+ Do While Not _RangeSelectionFinished And lCountLoops &lt; cstMaxSleep
+ Wait(cstSleep)
+ lCountLoops = lCountLoops + 1
+ Loop
+
+Finally:
+ If Not IsNull(oListener) Then oController.removeRangeSelectionListener(oListener)
+ RunRangeSelector = _SelectedRange
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_DocumentListener.RunRangeSelector
+
+REM ============================================================= PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Sub _SFRGSEL_done(Optional poEvent As Object) &apos; com.sun.star.sheet.RangeSelectionEvent
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Try:
+ _SelectedRange = poEvent.RangeDescriptor
+ _RangeSelectionFinished = True
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub
+
+REM -----------------------------------------------------------------------------
+Sub _SFRGSEL_aborted(Optional poEvent As Object) &apos; com.sun.star.sheet.RangeSelectionEvent
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Try:
+ _RangeSelectionFinished = True
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub
+
+REM ============================================ END OF SFDIALOGS.SF_DIALOGLISTENER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Form.xba b/wizards/source/sfdocuments/SF_Form.xba
new file mode 100644
index 000000000..404c24bd3
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Form.xba
@@ -0,0 +1,1535 @@
+<?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_Form" 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_Form
+&apos;&apos;&apos; =======
+&apos;&apos;&apos; Management of forms defined in LibreOffice documents. Supported types are Base, Calc and Writer documents.
+&apos;&apos;&apos; It includes the management of subforms
+&apos;&apos;&apos; Each instance of the current class represents a single form or a single subform
+&apos;&apos;&apos;
+&apos;&apos;&apos; A form may optionally be (understand &quot;is often&quot;) linked to a data source manageable with the SFDatabases.Database service
+&apos;&apos;&apos; The current service offers a rapid access to that service
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos;
+&apos;&apos;&apos; FormDocument:
+&apos;&apos;&apos; For usual documents, there is only 1 form document. It is in fact the document itself.
+&apos;&apos;&apos; A Base document may contain an unlimited number of form documents.
+&apos;&apos;&apos; In the Base terminology they are called &quot;forms&quot; or &quot;Base forms&quot;. This could create some confusion.
+&apos;&apos;&apos; They can be organized in folders. Their name is then always the full path of folders + form
+&apos;&apos;&apos; with the slash (&quot;/&quot;) as path separator
+&apos;&apos;&apos; A FormDocument is a set of Forms. Form names are visible in the user interface thanks to the form navigator
+&apos;&apos;&apos; Often there is only 1 Form present in a FormDocument. Having more, however, might improve
+&apos;&apos;&apos; the user experience significantly
+&apos;&apos;&apos;
+&apos;&apos;&apos; Form: WHERE IT IS ABOUT IN THE CURRENT &quot;Form&quot; SERVICE
+&apos;&apos;&apos; Is an abstract set of Controls in an OPEN FormDocument
+&apos;&apos;&apos; Each form is usually linked to one single dataset (table, query or Select statement),
+&apos;&apos;&apos; located in any database (provided the user may access it)
+&apos;&apos;&apos; A usual document may contain several forms. Each of which may have its own data source (database + dataset)
+&apos;&apos;&apos; A Base form document may contain several forms. Each of which may address its own dataset. The database however is unique
+&apos;&apos;&apos; A form is defined by its owning FormDocument and its FormName or FormIndex
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocations:
+&apos;&apos;&apos;
+&apos;&apos;&apos; REM the form is stored in a not-Base document (Calc, Writer)
+&apos;&apos;&apos; Dim oDoc As Object, myForm As Object
+&apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.Document&quot;, ThisComponent)
+&apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;Form1&quot;)
+&apos;&apos;&apos; &apos; or, alternatively, when there is only 1 form
+&apos;&apos;&apos; Set myForm = oDoc.Forms(0)
+&apos;&apos;&apos;
+&apos;&apos;&apos; REM the form is stored in one of the FormDocuments of a Base document
+&apos;&apos;&apos; Dim oDoc As Object, myForm As Object, mySubForm As Object
+&apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.Document&quot;, ThisDatabaseDocument)
+&apos;&apos;&apos; oDoc.OpenFormDocument(&quot;thisFormDocument&quot;)
+&apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;thisFormDocument&quot;, &quot;MainForm&quot;)
+&apos;&apos;&apos; &apos; or, alternatively, when there is only 1 form
+&apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;thisFormDocument&quot;, 0)
+&apos;&apos;&apos; &apos; To access a subform: myForm and mySubForm become distinct instances of the current class
+&apos;&apos;&apos; Set mySubForm = myForm.SubForms(&quot;mySubForm&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; REM the form is the subject of an event
+&apos;&apos;&apos; Sub OnEvent(ByRef poEvent As Object)
+&apos;&apos;&apos; Dim myForm As Object
+&apos;&apos;&apos; Set myForm = CreateScriptService(&quot;SFDocuments.FormEvent&quot;, poEvent)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_form.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const FORMDEADERROR = &quot;FORMDEADERROR&quot;
+Private Const SUBFORMNOTFOUNDERROR = &quot;SUBFORMNOTFOUNDERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be Form
+Private ServiceName As String
+
+&apos; Form location
+Private _Name As String &apos; Internal name of the form
+Private _FormType As Integer &apos; One of the ISxxxFORM constants
+Private _SheetName As String &apos; Name as the sheet containing the form (Calc only)
+Private _FormDocumentName As String &apos; The hierarchical name of the containing form document (Base only)
+Private _FormDocument As Object &apos; com.sun.star.comp.sdb.Content - the containing form document
+ &apos; The form topmost container
+Private _Component As Object &apos; com.sun.star.lang.XComponent or com.sun.star.comp.dba.ODatabaseDocument
+
+&apos; Events management
+Private _CacheIndex As Long &apos; Index in central cache storage
+
+&apos; Form UNO references
+&apos; The entry to the interactions with the form. Validity checked by the _IsStillAlive() method
+&apos; Each method or property requiring that the form is opened should first invoke that method
+Private _Form As Object &apos; com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
+Private _Database As Object &apos; Database class instance
+
+&apos; Form attributes
+
+&apos; Cache storage for controls
+Private _ControlNames As Variant &apos; Array of control names
+Private _ControlCache As Variant &apos; Array of control objects sorted like ElementNames of XForm
+
+REM ============================================================ MODULE CONSTANTS
+
+Const ISDOCFORM = 1 &apos; Form is stored in a Writer document
+Const ISCALCFORM = 2 &apos; Form is stored in a Calc document
+Const ISBASEFORM = 3 &apos; Form is stored in a Base document
+Const ISSUBFORM = 4 &apos; Form is a subform of a form or of another subform
+Const ISUNDEFINED = -1 &apos; Undefined form type
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;FORM&quot;
+ ServiceName = &quot;SFDocuments.Form&quot;
+ _Name = &quot;&quot;
+ _SheetName = &quot;&quot;
+ _FormDocumentName = &quot;&quot;
+ Set _FormDocument = Nothing
+ _FormType = ISUNDEFINED
+ _CacheIndex = -1
+ Set _Form = Nothing
+ Set _Database = Nothing
+ _ControlNames = Array()
+ _ControlCache = Array()
+End Sub &apos; SFDocuments.SF_Form Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_Form Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ If Not IsNull(_Database) And (_FormType = ISDOCFORM Or _FormType = ISCALCFORM) Then
+ Set _Database = _Database.Dispose()
+ End If
+ SF_Register._CleanCacheEntry(_CacheIndex)
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDocuments.SF_Form Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get AllowDeletes() As Variant
+&apos;&apos;&apos; The AllowDeletes property specifies if the form allows to delete records
+ AllowDeletes = _PropertyGet(&quot;AllowDeletes&quot;)
+End Property &apos; SFDocuments.SF_Form.AllowDeletes (get)
+
+REM -----------------------------------------------------------------------------
+Property Let AllowDeletes(Optional ByVal pvAllowDeletes As Variant)
+&apos;&apos;&apos; Set the updatable property AllowDeletes
+ _PropertySet(&quot;AllowDeletes&quot;, pvAllowDeletes)
+End Property &apos; SFDocuments.SF_Form.AllowDeletes (let)
+
+REM -----------------------------------------------------------------------------
+Property Get AllowInserts() As Variant
+&apos;&apos;&apos; The AllowInserts property specifies if the form allows to add records
+ AllowInserts = _PropertyGet(&quot;AllowInserts&quot;)
+End Property &apos; SFDocuments.SF_Form.AllowInserts (get)
+
+REM -----------------------------------------------------------------------------
+Property Let AllowInserts(Optional ByVal pvAllowInserts As Variant)
+&apos;&apos;&apos; Set the updatable property AllowInserts
+ _PropertySet(&quot;AllowInserts&quot;, pvAllowInserts)
+End Property &apos; SFDocuments.SF_Form.AllowInserts (let)
+
+REM -----------------------------------------------------------------------------
+Property Get AllowUpdates() As Variant
+&apos;&apos;&apos; The AllowUpdates property specifies if the form allows to update records
+ AllowUpdates = _PropertyGet(&quot;AllowUpdates&quot;)
+End Property &apos; SFDocuments.SF_Form.AllowUpdates (get)
+
+REM -----------------------------------------------------------------------------
+Property Let AllowUpdates(Optional ByVal pvAllowUpdates As Variant)
+&apos;&apos;&apos; Set the updatable property AllowUpdates
+ _PropertySet(&quot;AllowUpdates&quot;, pvAllowUpdates)
+End Property &apos; SFDocuments.SF_Form.AllowUpdates (let)
+
+REM -----------------------------------------------------------------------------
+Property Get BaseForm() As String
+&apos;&apos;&apos; The BaseForm property specifies the hierarchical name of the Base form containing the actual form
+ BaseForm = _PropertyGet(&quot;BaseForm&quot;)
+End Property &apos; SFDocuments.SF_Form.BaseForm (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Bookmark() As Variant
+&apos;&apos;&apos; The Bookmark property specifies uniquely the current record of the form&apos;s underlying table, query or SQL statement.
+ Bookmark = _PropertyGet(&quot;Bookmark&quot;)
+End Property &apos; SFDocuments.SF_Form.Bookmark (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Bookmark(Optional ByVal pvBookmark As Variant)
+&apos;&apos;&apos; Set the updatable property Bookmark
+ _PropertySet(&quot;Bookmark&quot;, pvBookmark)
+End Property &apos; SFDocuments.SF_Form.Bookmark (let)
+
+REM -----------------------------------------------------------------------------
+Property Get CurrentRecord() As Variant
+&apos;&apos;&apos; The CurrentRecord property identifies the current record in the recordset being viewed on a form
+ CurrentRecord = _PropertyGet(&quot;CurrentRecord&quot;)
+End Property &apos; SFDocuments.SF_Form.CurrentRecord (get)
+
+REM -----------------------------------------------------------------------------
+Property Let CurrentRecord(Optional ByVal pvCurrentRecord As Variant)
+&apos;&apos;&apos; Set the updatable property CurrentRecord
+&apos;&apos;&apos; If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set.
+&apos;&apos;&apos; The first row is row 1, the second is row 2, and so on.
+&apos;&apos;&apos; If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set.
+&apos;&apos;&apos; For example, setting CurrentRecord = -1 positions the cursor on the last row, -2 indicates the next-to-last row, and so on
+ _PropertySet(&quot;CurrentRecord&quot;, pvCurrentRecord)
+End Property &apos; SFDocuments.SF_Form.CurrentRecord (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Filter() As Variant
+&apos;&apos;&apos; The Filter property specifies a subset of records to be displayed.
+ Filter = _PropertyGet(&quot;Filter&quot;)
+End Property &apos; SFDocuments.SF_Form.Filter (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Filter(Optional ByVal pvFilter As Variant)
+&apos;&apos;&apos; Set the updatable property Filter
+ _PropertySet(&quot;Filter&quot;, pvFilter)
+End Property &apos; SFDocuments.SF_Form.Filter (let)
+
+REM -----------------------------------------------------------------------------
+Property Get LinkChildFields() As Variant
+&apos;&apos;&apos; The LinkChildFields property specifies how records in a subform (child) are linked to records in its parent form
+&apos;&apos;&apos; It returns an array of strings
+ LinkChildFields = _PropertyGet(&quot;LinkChildFields&quot;)
+End Property &apos; SFDocuments.SF_Form.LinkChildFields (get)
+
+REM -----------------------------------------------------------------------------
+Property Get LinkParentFields() As Variant
+&apos;&apos;&apos; The LinkParentFields property specifies how records in a subform (Child) are linked to records in its parent form
+&apos;&apos;&apos; It returns an array of strings
+ LinkParentFields = _PropertyGet(&quot;LinkParentFields&quot;)
+End Property &apos; SFDocuments.SF_Form.LinkParentFields (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Name() As String
+&apos;&apos;&apos; Return the name of the actual Form
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; SFDocuments.SF_Form.Name
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveCursorMove() As Variant
+&apos;&apos;&apos; The OnApproveCursorMove property specifies the script to trigger when this event occurs
+ OnApproveCursorMove = _PropertyGet(&quot;OnApproveCursorMove&quot;)
+End Property &apos; SFDocuments.SF_Form.OnApproveCursorMove (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveCursorMove(Optional ByVal pvOnApproveCursorMove As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveCursorMove
+ _PropertySet(&quot;OnApproveCursorMove&quot;, pvOnApproveCursorMove)
+End Property &apos; SFDocuments.SF_Form.OnApproveCursorMove (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveReset() As Variant
+&apos;&apos;&apos; The OnApproveReset property specifies the script to trigger when this event occurs
+ OnApproveReset = _PropertyGet(&quot;OnApproveReset&quot;)
+End Property &apos; SFDocuments.SF_Form.OnApproveReset (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveReset(Optional ByVal pvOnApproveReset As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveReset
+ _PropertySet(&quot;OnApproveReset&quot;, pvOnApproveReset)
+End Property &apos; SFDocuments.SF_Form.OnApproveReset (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveRowChange() As Variant
+&apos;&apos;&apos; The OnApproveRowChange property specifies the script to trigger when this event occurs
+ OnApproveRowChange = _PropertyGet(&quot;OnApproveRowChange&quot;)
+End Property &apos; SFDocuments.SF_Form.OnApproveRowChange (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveRowChange(Optional ByVal pvOnApproveRowChange As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveRowChange
+ _PropertySet(&quot;OnApproveRowChange&quot;, pvOnApproveRowChange)
+End Property &apos; SFDocuments.SF_Form.OnApproveRowChange (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveSubmit() As Variant
+&apos;&apos;&apos; The OnApproveSubmit property specifies the script to trigger when this event occurs
+ OnApproveSubmit = _PropertyGet(&quot;OnApproveSubmit&quot;)
+End Property &apos; SFDocuments.SF_Form.OnApproveSubmit (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveSubmit(Optional ByVal pvOnApproveSubmit As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveSubmit
+ _PropertySet(&quot;OnApproveSubmit&quot;, pvOnApproveSubmit)
+End Property &apos; SFDocuments.SF_Form.OnApproveSubmit (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnConfirmDelete() As Variant
+&apos;&apos;&apos; The OnConfirmDelete property specifies the script to trigger when this event occurs
+ OnConfirmDelete = _PropertyGet(&quot;OnConfirmDelete&quot;)
+End Property &apos; SFDocuments.SF_Form.OnConfirmDelete (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnConfirmDelete(Optional ByVal pvOnConfirmDelete As Variant)
+&apos;&apos;&apos; Set the updatable property OnConfirmDelete
+ _PropertySet(&quot;OnConfirmDelete&quot;, pvOnConfirmDelete)
+End Property &apos; SFDocuments.SF_Form.OnConfirmDelete (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnCursorMoved() As Variant
+&apos;&apos;&apos; The OnCursorMoved property specifies the script to trigger when this event occurs
+ OnCursorMoved = _PropertyGet(&quot;OnCursorMoved&quot;)
+End Property &apos; SFDocuments.SF_Form.OnCursorMoved (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnCursorMoved(Optional ByVal pvOnCursorMoved As Variant)
+&apos;&apos;&apos; Set the updatable property OnCursorMoved
+ _PropertySet(&quot;OnCursorMoved&quot;, pvOnCursorMoved)
+End Property &apos; SFDocuments.SF_Form.OnCursorMoved (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnErrorOccurred() As Variant
+&apos;&apos;&apos; The OnErrorOccurred property specifies the script to trigger when this event occurs
+ OnErrorOccurred = _PropertyGet(&quot;OnErrorOccurred&quot;)
+End Property &apos; SFDocuments.SF_Form.OnErrorOccurred (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnErrorOccurred(Optional ByVal pvOnErrorOccurred As Variant)
+&apos;&apos;&apos; Set the updatable property OnErrorOccurred
+ _PropertySet(&quot;OnErrorOccurred&quot;, pvOnErrorOccurred)
+End Property &apos; SFDocuments.SF_Form.OnErrorOccurred (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnLoaded() As Variant
+&apos;&apos;&apos; The OnLoaded property specifies the script to trigger when this event occurs
+ OnLoaded = _PropertyGet(&quot;OnLoaded&quot;)
+End Property &apos; SFDocuments.SF_Form.OnLoaded (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnLoaded(Optional ByVal pvOnLoaded As Variant)
+&apos;&apos;&apos; Set the updatable property OnLoaded
+ _PropertySet(&quot;OnLoaded&quot;, pvOnLoaded)
+End Property &apos; SFDocuments.SF_Form.OnLoaded (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnReloaded() As Variant
+&apos;&apos;&apos; The OnReloaded property specifies the script to trigger when this event occurs
+ OnReloaded = _PropertyGet(&quot;OnReloaded&quot;)
+End Property &apos; SFDocuments.SF_Form.OnReloaded (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnReloaded(Optional ByVal pvOnReloaded As Variant)
+&apos;&apos;&apos; Set the updatable property OnReloaded
+ _PropertySet(&quot;OnReloaded&quot;, pvOnReloaded)
+End Property &apos; SFDocuments.SF_Form.OnReloaded (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnReloading() As Variant
+&apos;&apos;&apos; The OnReloading property specifies the script to trigger when this event occurs
+ OnReloading = _PropertyGet(&quot;OnReloading&quot;)
+End Property &apos; SFDocuments.SF_Form.OnReloading (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnReloading(Optional ByVal pvOnReloading As Variant)
+&apos;&apos;&apos; Set the updatable property OnReloading
+ _PropertySet(&quot;OnReloading&quot;, pvOnReloading)
+End Property &apos; SFDocuments.SF_Form.OnReloading (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnResetted() As Variant
+&apos;&apos;&apos; The OnResetted property specifies the script to trigger when this event occurs
+ OnResetted = _PropertyGet(&quot;OnResetted&quot;)
+End Property &apos; SFDocuments.SF_Form.OnResetted (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnResetted(Optional ByVal pvOnResetted As Variant)
+&apos;&apos;&apos; Set the updatable property OnResetted
+ _PropertySet(&quot;OnResetted&quot;, pvOnResetted)
+End Property &apos; SFDocuments.SF_Form.OnResetted (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnRowChanged() As Variant
+&apos;&apos;&apos; The OnRowChanged property specifies the script to trigger when this event occurs
+ OnRowChanged = _PropertyGet(&quot;OnRowChanged&quot;)
+End Property &apos; SFDocuments.SF_Form.OnRowChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnRowChanged(Optional ByVal pvOnRowChanged As Variant)
+&apos;&apos;&apos; Set the updatable property OnRowChanged
+ _PropertySet(&quot;OnRowChanged&quot;, pvOnRowChanged)
+End Property &apos; SFDocuments.SF_Form.OnRowChanged (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnUnloaded() As Variant
+&apos;&apos;&apos; The OnUnloaded property specifies the script to trigger when this event occurs
+ OnUnloaded = _PropertyGet(&quot;OnUnloaded&quot;)
+End Property &apos; SFDocuments.SF_Form.OnUnloaded (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnUnloaded(Optional ByVal pvOnUnloaded As Variant)
+&apos;&apos;&apos; Set the updatable property OnUnloaded
+ _PropertySet(&quot;OnUnloaded&quot;, pvOnUnloaded)
+End Property &apos; SFDocuments.SF_Form.OnUnloaded (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnUnloading() As Variant
+&apos;&apos;&apos; The OnUnloading property specifies the script to trigger when this event occurs
+ OnUnloading = _PropertyGet(&quot;OnUnloading&quot;)
+End Property &apos; SFDocuments.SF_Form.OnUnloading (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnUnloading(Optional ByVal pvOnUnloading As Variant)
+&apos;&apos;&apos; Set the updatable property OnUnloading
+ _PropertySet(&quot;OnUnloading&quot;, pvOnUnloading)
+End Property &apos; SFDocuments.SF_Form.OnUnloading (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OrderBy() As Variant
+&apos;&apos;&apos; The OrderBy property specifies in which order the records should be displayed.
+ OrderBy = _PropertyGet(&quot;OrderBy&quot;)
+End Property &apos; SFDocuments.SF_Form.OrderBy (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OrderBy(Optional ByVal pvOrderBy As Variant)
+&apos;&apos;&apos; Set the updatable property OrderBy
+ _PropertySet(&quot;OrderBy&quot;, pvOrderBy)
+End Property &apos; SFDocuments.SF_Form.OrderBy (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Parent() As Object
+&apos;&apos;&apos; Return the Parent of the actual Form
+ Parent = _PropertyGet(&quot;Parent&quot;)
+End Property &apos; SFDocuments.SF_Form.Parent
+
+REM -----------------------------------------------------------------------------
+Property Get RecordSource() As Variant
+&apos;&apos;&apos; The RecordSource property specifies the source of the data,
+&apos;&apos;&apos; a table name, a query name or a SQL statement
+ RecordSource = _PropertyGet(&quot;RecordSource&quot;)
+End Property &apos; SFDocuments.SF_Form.RecordSource (get)
+
+REM -----------------------------------------------------------------------------
+Property Let RecordSource(Optional ByVal pvRecordSource As Variant)
+&apos;&apos;&apos; Set the updatable property RecordSource
+ _PropertySet(&quot;RecordSource&quot;, pvRecordSource)
+End Property &apos; SFDocuments.SF_Form.RecordSource (let)
+
+REM -----------------------------------------------------------------------------
+Property Get XForm() As Object
+&apos;&apos;&apos; The XForm property returns the XForm UNO object of the Form
+ XForm = _PropertyGet(&quot;XForm&quot;)
+End Property &apos; SFDocuments.SF_Form.XForm (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate() As Boolean
+&apos;&apos;&apos; Set the focus on the current Form instance
+&apos;&apos;&apos; Probably called from after an event occurrence or to focus on an open Base form document
+&apos;&apos;&apos; If the parent document is ...
+&apos;&apos;&apos; Calc Activate the corresponding sheet
+&apos;&apos;&apos; Writer Activate the parent document
+&apos;&apos;&apos; Base Activate the parent form document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if focusing is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.Activate()
+
+Dim bActivate As Boolean &apos; Return value
+Dim oContainer As Object &apos; com.sun.star.awt.XWindow
+Const cstThisSub = &quot;SFDocuments.Form.Activate&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bActivate = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ Select Case _FormType
+ Case ISDOCFORM : bActivate = [_Parent].Activate()
+ Case ISCALCFORM : bActivate = [_Parent].Activate(_SheetName)
+ Case ISBASEFORM
+ Set oContainer = _FormDocument.Component.CurrentController.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
+ End Select
+
+Finally:
+ Activate = bActivate
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.Activate
+
+REM -----------------------------------------------------------------------------
+Public Function CloseFormDocument() As Boolean
+&apos;&apos;&apos; Close the form document containing the actual form instance
+&apos;&apos;&apos; The form instance is disposed
+&apos;&apos;&apos; The method does nothing if the actual form is not located in a Base form document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if closure is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.CloseFormDocument()
+
+Dim bClose As Boolean &apos; Return value
+Dim oContainer As Object &apos; com.sun.star.awt.XWindow
+Const cstThisSub = &quot;SFDocuments.Form.CloseFormDocument&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bClose = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ Select Case _FormType
+ Case ISDOCFORM, ISCALCFORM, ISSUBFORM
+ Case ISBASEFORM
+ _FormDocument.close()
+ Dispose()
+ bClose = True
+ End Select
+
+Finally:
+ CloseFormDocument = bClose
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.CloseFormDocument
+
+REM -----------------------------------------------------------------------------
+Public Function Controls(Optional ByVal ControlName As Variant) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the controls contained in the Form
+&apos;&apos;&apos; - a Form control object based on its name
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ControlName: a valid control name as a case-sensitive string. If absent the list is returned
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-base array of strings if ControlName is absent
+&apos;&apos;&apos; An instance of the SF_FormControl class if ControlName exists
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ControlName is invalid
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myForm As Object, myList As Variant, myControl As Object
+&apos;&apos;&apos; Set myForm = myDoc.Forms(&quot;myForm&quot;)
+&apos;&apos;&apos; myList = myForm.Controls()
+&apos;&apos;&apos; Set myControl = myForm.Controls(&quot;myTextBox&quot;)
+
+Dim oControl As Object &apos; The new control class instance
+Dim lIndexOfNames As Long &apos; Index in ElementNames array. Used to access _ControlCache
+Dim vControl As Variant &apos; Alias of _ControlCache entry
+Dim i As Long
+Const cstThisSub = &quot;SFDocuments.Form.Controls&quot;
+Const cstSubArgs = &quot;[ControlName]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(ControlName) Or IsEmpty(ControlName) Then ControlName = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ControlName, &quot;ControlName&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Collect all control names if not yet done
+ If UBound(_ControlNames) &lt; 0 Then
+ _ControlNames = _Form.getElementNames()
+ &apos; Remove all subforms from the list
+ For i = 0 To UBound(_ControlNames)
+ &apos; Subforms have no ClassId property
+ If Not ScriptForge.SF_Session.HasUnoProperty(_Form.getByName(_ControlNames(i)), &quot;ClassId&quot;) Then _ControlNames(i) = &quot;&quot;
+ Next i
+ _ControlNames = ScriptForge.SF_Array.TrimArray(_ControlNames)
+ &apos; Size the cache accordingly
+ If UBound(_ControlNames) &gt;= 0 Then
+ ReDim _ControlCache(0 To UBound(_ControlNames))
+ End If
+ End If
+
+ &apos; Return the list of controls or a FormControl instance
+ If Len(ControlName) = 0 Then
+ Controls = _ControlNames
+
+ Else
+
+ If Not _Form.hasByName(ControlName) Then GoTo CatchNotFound
+ lIndexOfNames = ScriptForge.SF_Array.IndexOf(_ControlNames, ControlName, CaseSensitive := True)
+ &apos; Reuse cache when relevant
+ vControl = _ControlCache(lIndexOfNames)
+
+ If IsEmpty(vControl) Then
+ &apos; Create the new form control class instance
+ Set oControl = New SF_FormControl
+ With oControl
+ ._Name = ControlName
+ Set .[Me] = oControl
+ Set .[_Parent] = [Me]
+ Set ._ParentForm = [Me]
+ ._IndexOfNames = lIndexOfNames
+ ._FormName = _Name
+ &apos; Get model and view of the current control
+ Set ._ControlModel = _Form.getByName(ControlName)
+ ._Initialize()
+ End With
+ Else
+ Set oControl = vControl
+ End If
+
+ Set Controls = oControl
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Utils._Validate(ControlName, &quot;ControlName&quot;, V_STRING, _Form.getElementNames())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.Controls
+
+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; Each main form has its own database connection, except within Base documents where
+&apos;&apos;&apos; they all share the same connection
+&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 = oForm.GetDatabase()
+
+Dim FSO As Object &apos; Alias for SF_FileSystem
+Dim sUser As String &apos; Alias for User
+Dim sPassword As String &apos; Alias for Password
+Const cstThisSub = &quot;SFDocuments.Form.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 [_Parent]._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:
+ &apos; Adjust connection arguments
+ If Len(User) = 0 Then
+ If ScriptForge.SF_Session.HasUnoProperty(_Form, &quot;User&quot;) Then sUser = _Form.User Else sUser = &quot;&quot;
+ Else
+ sUser = User
+ End If
+ If Len(sUser) + Len(Password) = 0 Then
+ If ScriptForge.SF_Session.HasUnoProperty(_Form, &quot;Password&quot;) Then sPassword = _Form.Password Else sPassword = Password
+ End If
+
+ &apos; Connect to database, avoiding multiple requests
+ If IsNull(_Database) Then &apos; 1st connection request from the current form instance
+ If _FormType = ISBASEFORM Then
+ &apos; Fetch the shared connection
+ Set _Database = [_Parent].GetDatabase(User, Password)
+ ElseIf _FormType = ISSUBFORM Then
+ Set _Database = [_Parent].GetDatabase() &apos; Recursive call, climb the tree
+ ElseIf Len(_Form.DataSourceName) = 0 Then &apos; There is no database linked with the form
+ &apos; Return Nothing
+ Else
+ &apos; Check if DataSourceName is a file or a registered name and create database instance accordingly
+ Set FSO = ScriptForge.SF_FileSystem
+ If FSO.FileExists(FSO._ConvertFromUrl(_Form.DataSourceName)) Then
+ Set _Database = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Database&quot; _
+ , _Form.DataSourceName, , , sUser, sPassword)
+ Else
+ Set _Database = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Database&quot; _
+ , , _Form.DataSourceName, , sUser, sPassword)
+ End If
+ If IsNull(_Database) Then GoTo CatchConnect
+ End If
+ Else
+ 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_Form.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
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDlg.GetProperty(&quot;Caption&quot;)
+
+Const cstThisSub = &quot;SFDocuments.Form.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If 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:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Form service as an array
+
+ Methods = Array( _
+ &quot;Activate&quot; _
+ , &quot;CloseForm&quot; _
+ , &quot;Controls&quot; _
+ , &quot;GetDatabase&quot; _
+ , &quot;MoveFirst&quot; _
+ , &quot;MoveLast&quot; _
+ , &quot;MoveNew&quot; _
+ , &quot;MoveNext&quot; _
+ , &quot;MovePrevious&quot; _
+ , &quot;Requery&quot; _
+ , &quot;SubForms&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Form.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function MoveFirst() As Boolean
+&apos;&apos;&apos; The cursor is (re)positioned on the first row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if cursor move is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.MoveFirst()
+
+Dim bMoveFirst As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Form.MoveFirst&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMoveFirst = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ With _Form
+ bMoveFirst = .first()
+ End With
+
+Finally:
+ MoveFirst = bMoveFirst
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.MoveFirst
+
+REM -----------------------------------------------------------------------------
+Public Function MoveLast() As Boolean
+&apos;&apos;&apos; The cursor is (re)positioned on the last row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if cursor move is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.MoveLast()
+
+Dim bMoveLast As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Form.MoveLast&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMoveLast = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ With _Form
+ bMoveLast = .last()
+ End With
+
+Finally:
+ MoveLast = bMoveLast
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.MoveLast
+
+REM -----------------------------------------------------------------------------
+Public Function MoveNew() As Boolean
+&apos;&apos;&apos; The cursor is (re)positioned in the new record area
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if cursor move is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.MoveNew()
+
+Dim bMoveNew As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Form.MoveNew&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMoveNew = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ With _Form
+ .last() &apos; To simulate the behaviour in the UI
+ .moveToInsertRow()
+ End With
+ bMoveNew = True
+
+Finally:
+ MoveNew = bMoveNew
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.MoveNew
+
+REM -----------------------------------------------------------------------------
+Public Function MoveNext(Optional ByVal Offset As Variant) As Boolean
+&apos;&apos;&apos; The cursor is (re)positioned on the next row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Offset: The number of records to go forward (default = 1)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if cursor move is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.MoveNext()
+
+Dim bMoveNext As Boolean &apos; Return value
+Dim lOffset As Long &apos; Alias of Offset
+Const cstThisSub = &quot;SFDocuments.Form.MoveNext&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMoveNext = False
+
+Check:
+ If IsMissing(Offset) Or IsEmpty(Offset) Then Offset = 1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Offset, &quot;Offset&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+Try:
+ lOffset = CLng(Offset) &apos; To be sure to have the right argument type
+ With _Form
+ If lOffset = 1 Then bMoveNext = .next() Else bMoveNext = .relative(lOffset)
+ End With
+
+Finally:
+ MoveNext = bMoveNext
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.MoveNext
+
+REM -----------------------------------------------------------------------------
+Public Function MovePrevious(Optional ByVal Offset As Variant) As Boolean
+&apos;&apos;&apos; The cursor is (re)positioned on the previous row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Offset: The number of records to go backward (default = 1)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if cursor move is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.MovePrevious()
+
+Dim bMovePrevious As Boolean &apos; Return value
+Dim lOffset As Long &apos; Alias of Offset
+Const cstThisSub = &quot;SFDocuments.Form.MovePrevious&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMovePrevious = False
+
+Check:
+ If IsMissing(Offset) Or IsEmpty(Offset) Then Offset = 1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Offset, &quot;Offset&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+Try:
+ lOffset = CLng(Offset) &apos; To be sure to have the right argument type
+ With _Form
+ If lOffset = 1 Then bMovePrevious = .previous() Else bMovePrevious = .relative(-lOffset)
+ End With
+
+Finally:
+ MovePrevious = bMovePrevious
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.MovePrevious
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Form class as an array
+
+ Properties = Array( _
+ &quot;AllowDeletes&quot; _
+ , &quot;AllowInserts&quot; _
+ , &quot;AllowUpdates&quot; _
+ , &quot;BaseForm&quot; _
+ , &quot;Bookmark&quot; _
+ , &quot;CurrentRecord&quot; _
+ , &quot;Filter&quot; _
+ , &quot;LinkChildFields&quot; _
+ , &quot;LinkParentFields&quot; _
+ , &quot;Name&quot; _
+ , &quot;OnApproveCursorMove&quot; _
+ , &quot;OnApproveParameter&quot; _
+ , &quot;OnApproveReset&quot; _
+ , &quot;OnApproveRowChange&quot; _
+ , &quot;OnApproveSubmit&quot; _
+ , &quot;OnConfirmDelete&quot; _
+ , &quot;OnCursorMoved&quot; _
+ , &quot;OnErrorOccurred&quot; _
+ , &quot;OnLoaded&quot; _
+ , &quot;OnReloaded&quot; _
+ , &quot;OnReloading&quot; _
+ , &quot;OnResetted&quot; _
+ , &quot;OnRowChanged&quot; _
+ , &quot;OnUnloaded&quot; _
+ , &quot;OnUnloading&quot; _
+ , &quot;OrderBy&quot; _
+ , &quot;Parent&quot; _
+ , &quot;RecordSource&quot; _
+ , &quot;XForm&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Form.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Requery() As Boolean
+&apos;&apos;&apos; Reload from the database the actual data into the form
+&apos;&apos;&apos; The cursor is (re)positioned on the first row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if requery is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; myForm.Requery()
+
+Dim bRequery As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Form.Requery&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRequery = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ End If
+Try:
+ With _Form
+ If .isLoaded() Then .reload() Else .load()
+ End With
+ bRequery = True
+
+Finally:
+ Requery = bRequery
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.Requery
+
+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.Form.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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Subforms(Optional ByVal Subform As Variant) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the subforms contained in the actual form or subform instance
+&apos;&apos;&apos; - a SFDocuments.Form object based on its name or its index in the alphabetic list of subforms
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Subform: a subform stored in the parent form given by its name or its index
+&apos;&apos;&apos; When absent, the list of available subforms is returned
+&apos;&apos;&apos; To get the first (unique ?) subform stored in the parent form, set Subform = 0
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; SUBFORMNOTFOUNDERROR Subform not found
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based array of strings if Subform is absent
+&apos;&apos;&apos; An instance of the SF_Form class if Subform exists
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myForm As Object, myList As Variant, mySubform As Object
+&apos;&apos;&apos; myList = myForm.Subforms()
+&apos;&apos;&apos; Set mySubform = myForm.Subforms(&quot;mySubform&quot;)
+
+Dim oSubform As Object &apos; The new Form class instance
+Dim oXSubform As Object &apos; com.sun.star.form.XForm
+Dim vSubformNames As Variant &apos; Array of subform names
+Dim i As Long
+Const cstDrawPage = 0 &apos; Only 1 drawpage in a Writer document
+
+Const cstThisSub = &quot;SFDocuments.Form.Subforms&quot;
+Const cstSubArgs = &quot;[Subform=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Subform) Or IsEmpty(Subform) Then Subform = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Subform, &quot;Subform&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Collect all control names and retain only the subforms
+ vSubformNames = _Form.getElementNames()
+ For i = 0 To UBound(vSubformNames)
+ Set oSubform = _Form.getByName(vSubformNames(i))
+ &apos; Subforms are the only control types having no ClassId property
+ If ScriptForge.SF_Session.HasUnoProperty(oSubform, &quot;ClassId&quot;) Then vSubformNames(i) = &quot;&quot;
+ Next i
+ vSubformNames = ScriptForge.SF_Array.TrimArray(vSubformNames)
+
+ If Len(Subform) = 0 Then &apos; Return the list of valid subform names
+ Subforms = vSubformNames
+ Else
+ If VarType(Subform) = V_STRING Then &apos; Find the form by name
+ If Not ScriptForge.SF_Array.Contains(vSubformNames, Subform, CaseSensitive := True) Then GoTo CatchNotFound
+ Set oXSubform = _Form.getByName(Subform)
+ Else &apos; Find the form by index
+ If Subform &lt; 0 Or Subform &gt; UBound(vSubformNames) Then GoTo CatchNotFound
+ Set oXSubform = _Form.getByName(vSubformNames(Subform))
+ End If
+ &apos; Create the new Form class instance
+ Set oSubform = SF_Register._NewForm(oXSubform)
+ With oSubform
+ Set .[_Parent] = [Me]
+ ._FormType = ISSUBFORM
+ Set ._Component = _Component
+ Set ._FormDocument = _FormDocument
+ ._SheetName = _SheetName
+ ._FormDocumentName = _FormDocumentName
+ Set ._Database = _Database
+ ._Initialize()
+ End With
+ Set Subforms = oSubform
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Exception.RaiseFatal(SUBFORMNOTFOUNDERROR, Subform, _Name)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form.Subforms
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _GetEventName(ByVal psProperty As String) As String
+&apos;&apos;&apos; Return the LO internal event name derived from the SF property name
+&apos;&apos;&apos; The SF property name is not case sensitive, while the LO name is case-sensitive
+&apos; Corrects the typo on ErrorOccur(r?)ed, if necessary
+
+Dim vProperties As Variant &apos; Array of class properties
+Dim sProperty As String &apos; Correctly cased property name
+
+ vProperties = Properties()
+ sProperty = vProperties(ScriptForge.SF_Array.IndexOf(vProperties, psProperty, SortOrder := &quot;ASC&quot;))
+
+ _GetEventName = LCase(Mid(sProperty, 3, 1)) &amp; Right(sProperty, Len(sProperty) - 3)
+
+End Function &apos; SFDocuments.SF_Form._GetEventName
+
+REM -----------------------------------------------------------------------------
+Private Function _GetListener(ByVal psEventName As String) As String
+&apos;&apos;&apos; Getting/Setting macros triggered by events requires a Listener-EventName pair
+&apos;&apos;&apos; Return the X...Listener corresponding with the event name in argument
+
+ Select Case UCase(psEventName)
+ Case UCase(&quot;OnApproveCursorMove&quot;)
+ _GetListener = &quot;XRowSetApproveListener&quot;
+ Case UCase(&quot;OnApproveParameter&quot;)
+ _GetListener = &quot;XDatabaseParameterListener&quot;
+ Case UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnResetted&quot;)
+ _GetListener = &quot;XResetListener&quot;
+ Case UCase(&quot;OnApproveRowChange&quot;)
+ _GetListener = &quot;XRowSetApproveListener&quot;
+ Case UCase(&quot;OnApproveSubmit&quot;)
+ _GetListener = &quot;XSubmitListener&quot;
+ Case UCase(&quot;OnConfirmDelete&quot;)
+ _GetListener = &quot;XConfirmDeleteListener&quot;
+ Case UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnRowChanged&quot;)
+ _GetListener = &quot;XRowSetListener&quot;
+ Case UCase(&quot;OnErrorOccurred&quot;)
+ _GetListener = &quot;XSQLErrorListener&quot;
+ Case UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ _GetListener = &quot;XLoadListener&quot;
+ End Select
+
+End Function &apos; SFDocuments.SF_Form._GetListener
+
+REM -----------------------------------------------------------------------------
+Private Sub _GetParents()
+&apos;&apos;&apos; When the current instance is created top-down, the parents are completely defined
+&apos;&apos;&apos; and nothing should be done in this method
+&apos;&apos;&apos; When the a class instance is created in a (form/control) event, it is the opposite
+&apos;&apos;&apos; The current method rebuilds the missing members in the instance from the bottom
+&apos;&apos;&apos; Members potentially to collect are:
+&apos;&apos;&apos; - _FormType
+&apos;&apos;&apos; - [_Parent], the immediate parent: a form or a document instance
+&apos;&apos;&apos; + Only when the _FormType is a main form
+&apos;&apos;&apos; - _SheetName (Calc only)
+&apos;&apos;&apos; - _FormDocumentName (Base only)
+&apos;&apos;&apos; - _FormDocument, the topmost form collection
+&apos;&apos;&apos; - _Component, the containing document
+&apos;&apos;&apos; They must be identified only starting from the _Form UNO object
+&apos;&apos;&apos;
+&apos;&apos;&apos; The method is called from the _Initialize() method at instance creation
+
+Dim oParent As Object &apos; Successive bottom-up parents
+Dim sType As String &apos; UNO object type
+Dim sPersistentName As String &apos; The Obj... name of a Base form
+Dim iLevel As Integer &apos; When = 1 =&gt; first parent
+Dim oSession As Object : Set oSession = ScriptForge.SF_Session
+
+ On Local Error GoTo Finally &apos; Being probably called from events, this method should avoid failures
+ &apos; When the form type is known, the upper part of the branch is not scanned
+ If _FormType &lt;&gt; ISUNDEFINED Then GoTo Finally
+
+Try:
+ &apos; The whole branch is scanned bottom-up
+ If oSession.HasUnoProperty(_Form, &quot;Parent&quot;) Then Set oParent = _Form.Parent Else Set oParent = Nothing
+ _FormType = ISUNDEFINED
+ iLevel = 1
+
+ Do While Not IsNull(oParent)
+ sType = SF_Session.UnoObjectType(oParent)
+ Select Case sType
+ &apos; Collect at each level the needed info
+ Case &quot;com.sun.star.comp.forms.ODatabaseForm&quot; &apos; The parent _Form of a subform
+ If iLevel = 1 Then
+ _FormType = ISSUBFORM
+ Set [_Parent] = SF_Register._NewForm(oParent)
+ &apos; Everything is in the parent, copy items and stop scan
+ [_Parent]._Initialize() &apos; Current method is called recursively here
+ With [_Parent]
+ _SheetName = ._SheetName
+ _FormDocumentName = ._FormDocumentName
+ Set _FormDocument = ._FormDocument
+ Set _Component = ._Component
+ End With
+ Exit Sub
+ End If
+ Case &quot;com.sun.star.form.OFormsCollection&quot; &apos; The collection of forms inside a drawpage
+ Case &quot;SwXTextDocument&quot; &apos; The parent document: a Writer document or a Base form document
+ If oParent.Identifier = &quot;com.sun.star.sdb.FormDesign&quot; Then
+ sPersistentName = ScriptForge._GetPropertyValue(oParent.Args, &quot;HierarchicalDocumentName&quot;)
+ ElseIf oParent.Identifier = &quot;com.sun.star.text.TextDocument&quot; Then
+ _FormType = ISDOCFORM
+ Set [_Parent] = ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, oParent)
+ Set _Component = [_Parent]._Component
+ End If
+ Case &quot;ScModelObj&quot; &apos; The parent document: a Calc document
+ _FormType = ISCALCFORM
+ Set [_Parent] = ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, oParent)
+ Set _Component = oParent
+ &apos; The triggered form event is presumed to be located in the (drawpage of the) active sheet
+ _SheetName = [_Parent].XSpreadsheet(&quot;~&quot;)
+ Case &quot;com.sun.star.comp.dba.ODatabaseDocument&quot; &apos; The Base document
+ _FormType = ISBASEFORM
+ Set [_Parent] = ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, oParent)
+ Set _Component = oParent
+ If IsNull([_Parent]._FormDocuments) Then Set [_Parent]._FormDocuments = _Component.getFormDocuments()
+ Set _FormDocument = [_Parent]._FindByPersistentName([_Parent]._FormDocuments, sPersistentName)
+ _FormDocumentName = _FormDocument.HierarchicalName
+ Case Else
+ End Select
+ If oSession.HasUnoProperty(oParent, &quot;Parent&quot;) Then Set oParent = oParent.Parent Else Set oParent = Nothing
+ iLevel = iLevel + 1
+ Loop
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDocuments.SF_Form._GetParents
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos;&apos;&apos; Achieve the creation of a SF_Form instance
+&apos;&apos;&apos; - complete the missing private members
+&apos;&apos;&apos; - store the new instance in the cache
+
+ _GetParents()
+ _CacheIndex = SF_Register._AddFormToCache(_Form, [Me])
+
+End Sub &apos; SFDocuments.SF_Form._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _IsStillAlive(Optional ByVal pbError As Boolean) As Boolean
+&apos;&apos;&apos; Return True if the Form is still open
+&apos;&apos;&apos; If dead the actual instance is disposed
+&apos;&apos;&apos; and the execution is cancelled when pbError = True (default)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbError: if True (default), raise a fatal error
+
+Dim bAlive As Boolean &apos; Return value
+Dim sName As String &apos; Alias of _Name
+Dim sId As String &apos; Alias of FileIdent
+
+Check:
+ On Local Error GoTo Catch &apos; Anticipate DisposedException errors or alike
+ If IsMissing(pbError) Then pbError = True
+
+Try:
+ &apos; At main form termination, all database connections are lost
+ bAlive = Not IsNull(_Form)
+ If Not bAlive Then GoTo Catch
+
+Finally:
+ _IsStillAlive = bAlive
+ Exit Function
+Catch:
+ bAlive = False
+ On Error GoTo 0
+ &apos; Keep error message elements before disposing the instance
+ sName = _SheetName &amp; _FormDocumentName &apos; At least one of them is a zero-length string
+ sName = Iif(Len(sName) &gt; 0, &quot;[&quot; &amp; sName &amp; &quot;].&quot;, &quot;&quot;) &amp; _Name
+ If Not IsNull(_Component) Then sId = _Component.Location Else sId = &quot;&quot;
+ &apos; Dispose the actual forms instance
+ Dispose()
+ &apos; Display error message
+ If pbError Then ScriptForge.SF_Exception.RaiseFatal(FORMDEADERROR, sName, sId)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form._IsStillAlive
+
+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
+
+Static oSession As Object &apos; Alias of SF_Session
+Dim vBookmark As Variant &apos; Form bookmark
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDocuments.Form.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ _PropertyGet = Empty
+ If Not _IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AllowDeletes&quot;)
+ If Not IsNull(_Form) Then _PropertyGet = _Form.AllowDeletes
+ Case UCase(&quot;AllowInserts&quot;)
+ If Not IsNull(_Form) Then _PropertyGet = _Form.AllowInserts
+ Case UCase(&quot;AllowUpdates&quot;)
+ If Not IsNull(_Form) Then _PropertyGet = _Form.AllowUpdates
+ Case UCase(&quot;BaseForm&quot;)
+ _PropertyGet = _FormDocumentName
+ Case UCase(&quot;Bookmark&quot;)
+ If IsNull(_Form) Then
+ _PropertyGet = 0
+ Else
+ On Local Error Resume Next &apos; Disable error handler because bookmarking does not always react well in events ...
+ If _Form.IsBookmarkable Then vBookmark = _Form.getBookmark() Else vBookmark = Nothing
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error Goto Catch Else On Local Error Goto 0
+ If IsNull(vBookmark) Then Goto Catch
+ _PropertyGet = vBookmark
+ End If
+ Case UCase(&quot;CurrentRecord&quot;)
+ If IsNull(_Form) Then _PropertyGet = 0 Else _PropertyGet = _Form.Row
+ Case UCase(&quot;Filter&quot;)
+ If IsNull(_Form) Then _PropertyGet = &quot;&quot; Else _PropertyGet = _Form.Filter
+ Case UCase(&quot;LinkChildFields&quot;)
+ If IsNull(_Form) Or _FormType &lt;&gt; ISSUBFORM Then _PropertyGet = Array() Else _PropertyGet = _Form.DetailFields
+ Case UCase(&quot;LinkParentFields&quot;)
+ If IsNull(_Form) Or _FormType &lt;&gt; ISSUBFORM Then _PropertyGet = Array() Else _PropertyGet = _Form.MasterFields
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;OnApproveCursorMove&quot;), UCase(&quot;OnApproveParameter&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveRowChange&quot;) _
+ , UCase(&quot;OnApproveSubmit&quot;), UCase(&quot;OnConfirmDelete&quot;), UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnErrorOccurred&quot;) _
+ , UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnRowChanged&quot;) _
+ , UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ If IsNull(_Form) Then _PropertyGet = &quot;&quot; Else _PropertyGet = SF_Register._GetEventScriptCode(_Form, psProperty, _Name)
+ Case UCase(&quot;OrderBy&quot;)
+ If IsNull(_Form) Then _PropertyGet = &quot;&quot; Else _PropertyGet = _Form.Order
+ Case UCase(&quot;Parent&quot;)
+ _PropertyGet = [_Parent]
+ Case UCase(&quot;RecordSource&quot;)
+ If IsNull(_Form) Then _PropertyGet = &quot;&quot; Else _PropertyGet = _Form.Command
+ Case UCase(&quot;XForm&quot;)
+ Set _PropertyGet = _Form
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(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
+Dim oDatabase As Object &apos; Database class instance
+Dim lCommandType As Long &apos; Record source type: 0 = Table, 1 = Query, 2 = SELECT
+Dim sCommand As String &apos; Record source
+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.Form.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;AllowDeletes&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;AllowDeletes&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not IsNull(_Form) Then
+ _Form.AllowDeletes = pvValue
+ _Form.reload()
+ End If
+ Case UCase(&quot;AllowInserts&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;AllowInserts&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not IsNull(_Form) Then
+ _Form.AllowInserts = pvValue
+ _Form.reload()
+ End If
+ Case UCase(&quot;AllowUpdates&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;AllowUpdates&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not IsNull(_Form) Then
+ _Form.AllowUpdates = pvValue
+ _Form.reload()
+ End If
+ Case UCase(&quot;Bookmark&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Bookmark&quot;, Array(ScriptForge.V_NUMERIC, ScriptForge.V_OBJECT)) Then GoTo Finally
+ If Not IsNull(pvValue) And Not IsNull(_Form) Then bSet = _Form.moveToBookmark(pvValue)
+ Case UCase(&quot;CurrentRecord&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;CurrentRecord&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not IsNull(_Form) Then bSet = _Form.absolute(pvValue)
+ Case UCase(&quot;Filter&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ If Not IsNull(_Form) Then
+ With _Form
+ If Len(pvValue) &gt; 0 Then
+ Set oDatabase = GetDatabase()
+ If Not IsNull(oDatabase) Then .Filter = oDatabase._ReplaceSquareBrackets(pvValue) Else .Filter = pvValue
+ Else
+ .Filter = &quot;&quot;
+ End If
+ .ApplyFilter = True
+ .reload()
+ End With
+ End If
+ Case UCase(&quot;OnApproveCursorMove&quot;), UCase(&quot;OnApproveParameter&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveRowChange&quot;) _
+ , UCase(&quot;OnApproveSubmit&quot;), UCase(&quot;OnConfirmDelete&quot;), UCase(&quot;OnCursorMoved&quot;), UCase(&quot;OnErrorOccurred&quot;) _
+ , UCase(&quot;OnLoaded&quot;), UCase(&quot;OnReloaded&quot;), UCase(&quot;OnReloading&quot;), UCase(&quot;OnResetted&quot;), UCase(&quot;OnRowChanged&quot;) _
+ , UCase(&quot;OnUnloaded&quot;), UCase(&quot;OnUnloading&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, psProperty, V_STRING) Then Goto Finally
+ If Not IsNull(_Form) Then
+ bSet = SF_Register._RegisterEventScript(_Form _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue _
+ , _Name _
+ )
+ End If
+ Case UCase(&quot;OrderBy&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;OrderBy&quot;, V_STRING) Then GoTo Finally
+ If Not IsNull(_Form) Then
+ With _Form
+ If Len(pvValue) &gt; 0 Then
+ Set oDatabase = GetDatabase()
+ If Not IsNull(oDatabase) Then .Order = oDatabase._ReplaceSquareBrackets(pvValue) Else .Order = pvValue
+ Else
+ .Order = &quot;&quot;
+ End If
+ .reload()
+ End With
+ End If
+ Case UCase(&quot;RecordSource&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;RecordSource&quot;, V_STRING) Then GoTo Finally
+ If Not IsNull(_Form) And Len(pvValue) &gt; 0 Then
+ Set oDatabase = GetDatabase()
+ If Not IsNull(oDatabase) Then
+ With oDatabase
+ If ScriptForge.SF_Array.Contains(.Tables, pvValue, CaseSensitive := True) Then
+ sCommand = pvValue
+ lCommandType = com.sun.star.sdb.CommandType.TABLE
+ ElseIf ScriptForge.SF_Array.Contains(.Queries, pvValue, CaseSensitive := True) Then
+ sCommand = pvValue
+ lCommandType = com.sun.star.sdb.CommandType.QUERY
+ ElseIf ScriptForge.SF_String.StartsWith(pvValue, &quot;SELECT&quot;, CaseSensitive := False) Then
+ sCommand = .ReplaceSquareBrackets(pvValue)
+ lCommandType = com.sun.star.sdb.CommandType.COMMAND
+ End If
+ _Form.Command = sCommand
+ _Form.CommandType = lCommandType
+ End With
+ End If
+ End If
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Form._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Form]: Name&quot;
+
+Dim sParent As String &apos; To recognize the parent
+
+ sParent = _SheetName &amp; _FormDocumentName &apos; At least one of them is a zero-length string
+ _Repr = &quot;[Form]: &quot; &amp; Iif(Len(sParent) &gt; 0, sParent &amp; &quot;...&quot;, &quot;&quot;) &amp; _Name
+
+End Function &apos; SFDocuments.SF_Form._Repr
+
+REM ============================================ END OF SFDOCUMENTS.SF_FORM
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_FormControl.xba b/wizards/source/sfdocuments/SF_FormControl.xba
new file mode 100644
index 000000000..a48c22b6c
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_FormControl.xba
@@ -0,0 +1,1888 @@
+<?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_FormControl" 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_FormControl
+&apos;&apos;&apos; ================
+&apos;&apos;&apos; Manage the controls belonging to a form or subform stored in a document
+&apos;&apos;&apos; Each instance of the current class represents a single control within a form, a subform or a tablecontrol
+&apos;&apos;&apos; A prerequisite is that all controls within the same form, subform or tablecontrol must have
+&apos;&apos;&apos; a unique name. This is also true for the individual radio buttons belonging to the same group.
+&apos;&apos;&apos; A common group name must identify such a single group.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The focus is clearly set on getting and setting the values displayed by the controls of the form,
+&apos;&apos;&apos; not on their formatting. The latter is easily accessible via the XControlModel and XControlView
+&apos;&apos;&apos; UNO objects.
+&apos;&apos;&apos; Essentially a single property &quot;Value&quot; maps many alternative UNO properties depending each on
+&apos;&apos;&apos; the control type.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocations:
+&apos;&apos;&apos; Dim myForm As Object, myControl As Object
+&apos;&apos;&apos; Set myForm = ... (read the comments in the SF_Form module)
+&apos;&apos;&apos; Set myControl = myForm.Controls(&quot;myTextBox&quot;)
+&apos;&apos;&apos; myControl.Value = &quot;Current time = &quot; &amp; Now()
+&apos;&apos;&apos;
+&apos;&apos;&apos; REM the control is the subject of an event
+&apos;&apos;&apos; Sub OnEvent(ByRef poEvent As Object)
+&apos;&apos;&apos; Dim myControl As Object
+&apos;&apos;&apos; Set myControl = CreateScriptService(&quot;SFDocuments.FormEvent&quot;, poEvent)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_formcontrol.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const FORMCONTROLTYPEERROR = &quot;FORMCONTROLTYPEERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be FORMCONTROL
+Private ServiceName As String
+
+&apos; Control naming and context
+Private _Name As String
+Private _IndexOfNames As Long &apos; Index in ElementNames array. Used to access SF_Form._ControlCache
+Private _FormName As String &apos; Parent form name
+Private _ParentForm As Object &apos; Parent form or subform instance
+Private _ParentIsTable As Boolean &apos; True when parent is a table control
+
+&apos; Control UNO references
+Private _ControlModel As Object &apos; com.sun.star.awt.XControlModel
+Private _ControlView As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
+
+&apos; Control attributes
+Private _ImplementationName As String
+Private _ControlType As String &apos; One of the CTLxxx constants
+Private _ClassId As Integer &apos; Numerical type of control
+
+&apos; Cache storage for table controls
+Private _ControlNames As Variant &apos; Array of control names
+Private _ControlCache As Variant &apos; Array of control objects sorted like ElementNames of XControlModel
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos; ClassId
+Private Const CTLBUTTON = &quot;Button&quot; &apos; 2
+Private Const CTLCHECKBOX = &quot;CheckBox&quot; &apos; 5
+Private Const CTLCOMBOBOX = &quot;ComboBox&quot; &apos; 7
+Private Const CTLCURRENCYFIELD = &quot;CurrencyField&quot; &apos; 18
+Private Const CTLDATEFIELD = &quot;DateField&quot; &apos; 15
+Private Const CTLFILECONTROL = &quot;FileControl&quot; &apos; 12
+Private Const CTLFIXEDTEXT = &quot;FixedText&quot; &apos; 10
+Private Const CTLFORMATTEDFIELD = &quot;FormattedField&quot; &apos; Idem TextField
+Private Const CTLGROUPBOX = &quot;GroupBox&quot; &apos; 8
+Private Const CTLHIDDENCONTROL = &quot;HiddenControl&quot; &apos; 13
+Private Const CTLIMAGEBUTTON = &quot;ImageButton&quot; &apos; 4
+Private Const CTLIMAGECONTROL = &quot;ImageControl&quot; &apos; 14
+Private Const CTLLISTBOX = &quot;ListBox&quot; &apos; 6
+Private Const CTLNAVIGATIONBAR = &quot;NavigationBar&quot; &apos; 22
+Private Const CTLNUMERICFIELD = &quot;NumericField&quot; &apos; 17
+Private Const CTLPATTERNFIELD = &quot;PatternField&quot; &apos; 19
+Private Const CTLRADIOBUTTON = &quot;RadioButton&quot; &apos; 3
+Private Const CTLSCROLLBAR = &quot;ScrollBar&quot; &apos; 20
+Private Const CTLSPINBUTTON = &quot;SpinButton&quot; &apos; 21
+Private Const CTLTABLECONTROL = &quot;TableControl&quot; &apos; 11
+Private Const CTLTEXTFIELD = &quot;TextField&quot; &apos; 9
+Private Const CTLTIMEFIELD = &quot;TimeField&quot; &apos; 16
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;FORMCONTROL&quot;
+ ServiceName = &quot;SFDocuments.FormControl&quot;
+ _Name = &quot;&quot;
+ _IndexOfNames = -1
+ _FormName = &quot;&quot;
+ _ParentIsTable = False
+ Set _ParentForm = Nothing
+ Set _ControlModel = Nothing
+ Set _ControlView = Nothing
+ _ImplementationName = &quot;&quot;
+ _ControlType = &quot;&quot;
+ _ClassId = 0
+ _ControlNames = Array()
+ _ControlCache = Array()
+End Sub &apos; SFDocuments.SF_FormControl Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_FormControl Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ If Not IsNull([_Parent]) And _IndexOfNames &gt;= 0 Then [_Parent]._ControlCache(_IndexOfNames) = Empty
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDocuments.SF_FormControl Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get Action() As Variant
+&apos;&apos;&apos; The Action property specifies the action triggered when the button is clicked
+&apos;&apos;&apos; Accepted values: none, submitForm, resetForm, refreshForm, moveToFirst, moveToLast,
+&apos;&apos;&apos; moveToNext, moveToPrev, saveRecord, moveToNew, deleteRecord, undoRecord
+ Action = _PropertyGet(&quot;Action&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.Action (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Action(Optional ByVal pvAction As Variant)
+&apos;&apos;&apos; Set the updatable property Action
+ _PropertySet(&quot;Action&quot;, pvAction)
+End Property &apos; SFDocuments.SF_FormControl.Action (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Caption() As Variant
+&apos;&apos;&apos; The Caption property refers to the text associated with the control
+ Caption = _PropertyGet(&quot;Caption&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.Caption (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Caption(Optional ByVal pvCaption As Variant)
+&apos;&apos;&apos; Set the updatable property Caption
+ _PropertySet(&quot;Caption&quot;, pvCaption)
+End Property &apos; SFDocuments.SF_FormControl.Caption (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ControlSource() As Variant
+&apos;&apos;&apos; The ControlSource property specifies the rowset field mapped onto the actual control
+ ControlSource = _PropertyGet(&quot;ControlSource&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.ControlSource (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ControlType() As String
+&apos;&apos;&apos; Return the type of the actual control: &quot;CheckBox&quot;, &quot;TextField&quot;, &quot;DateField&quot;, ...
+ ControlType = _PropertyGet(&quot;ControlType&quot;)
+End Property &apos; SFDocuments.SF_FormControl.ControlType
+
+REM -----------------------------------------------------------------------------
+Property Get Default() As Variant
+&apos;&apos;&apos; The Default property specifies whether a command button is the default (OK) button.
+ Default = _PropertyGet(&quot;Default&quot;, False)
+End Property &apos; SFDocuments.SF_FormControl.Default (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Default(Optional ByVal pvDefault As Variant)
+&apos;&apos;&apos; Set the updatable property Default
+ _PropertySet(&quot;Default&quot;, pvDefault)
+End Property &apos; SFDocuments.SF_FormControl.Default (let)
+
+REM -----------------------------------------------------------------------------
+Property Get DefaultValue() As Variant
+&apos;&apos;&apos; The DefaultValue property specifies how the control is initialized in a new record
+ DefaultValue = _PropertyGet(&quot;DefaultValue&quot;, Null)
+End Property &apos; SFDocuments.SF_FormControl.DefaultValue (get)
+
+REM -----------------------------------------------------------------------------
+Property Let DefaultValue(Optional ByVal pvDefaultValue As Variant)
+&apos;&apos;&apos; Set the updatable property DefaultValue
+ _PropertySet(&quot;DefaultValue&quot;, pvDefaultValue)
+End Property &apos; SFDocuments.SF_FormControl.DefaultValue (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Enabled() As Variant
+&apos;&apos;&apos; The Enabled property specifies if the control is accessible with the cursor.
+ Enabled = _PropertyGet(&quot;Enabled&quot;, False)
+End Property &apos; SFDocuments.SF_FormControl.Enabled (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Enabled(Optional ByVal pvEnabled As Variant)
+&apos;&apos;&apos; Set the updatable property Enabled
+ _PropertySet(&quot;Enabled&quot;, pvEnabled)
+End Property &apos; SFDocuments.SF_FormControl.Enabled (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Format() As Variant
+&apos;&apos;&apos; The Format property specifies the format in which to display dates and times.
+ Format = _PropertyGet(&quot;Format&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.Format (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Format(Optional ByVal pvFormat As Variant)
+&apos;&apos;&apos; Set the updatable property Format
+&apos;&apos;&apos; NB: Format is read-only for formatted field controls
+ _PropertySet(&quot;Format&quot;, pvFormat)
+End Property &apos; SFDocuments.SF_FormControl.Format (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ListCount() As Long
+&apos;&apos;&apos; The ListCount property specifies the number of rows in a list box or a combo box
+ ListCount = _PropertyGet(&quot;ListCount&quot;, 0)
+End Property &apos; SFDocuments.SF_FormControl.ListCount (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ListIndex() As Variant
+&apos;&apos;&apos; The ListIndex property specifies which item is selected in a list box or combo box.
+&apos;&apos;&apos; In case of multiple selection, the index of the first one is returned or only one is set
+ ListIndex = _PropertyGet(&quot;ListIndex&quot;, -1)
+End Property &apos; SFDocuments.SF_FormControl.ListIndex (get)
+
+REM -----------------------------------------------------------------------------
+Property Let ListIndex(Optional ByVal pvListIndex As Variant)
+&apos;&apos;&apos; Set the updatable property ListIndex
+ _PropertySet(&quot;ListIndex&quot;, pvListIndex)
+End Property &apos; SFDocuments.SF_FormControl.ListIndex (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ListSource() As Variant
+&apos;&apos;&apos; The ListSource property specifies the data contained in a combobox or a listbox
+&apos;&apos;&apos; as a zero-based array of string values
+ ListSource = _PropertyGet(&quot;ListSource&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.ListSource (get)
+
+REM -----------------------------------------------------------------------------
+Property Let ListSource(Optional ByVal pvListSource As Variant)
+&apos;&apos;&apos; Set the updatable property ListSource
+ _PropertySet(&quot;ListSource&quot;, pvListSource)
+End Property &apos; SFDocuments.SF_FormControl.ListSource (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ListSourceType() As Variant
+&apos;&apos;&apos; The ListSourceType property specifies the kind of data source used to fill the list data of a listbox or a combobox
+ ListSourceType = _PropertyGet(&quot;ListSourceType&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.ListSourceType (get)
+
+REM -----------------------------------------------------------------------------
+Property Let ListSourceType(Optional ByVal pvListSourceType As Variant)
+&apos;&apos;&apos; Set the updatable property ListSourceType
+ _PropertySet(&quot;ListSourceType&quot;, pvListSourceType)
+End Property &apos; SFDocuments.SF_FormControl.ListSourceType (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Locked() As Variant
+&apos;&apos;&apos; The Locked property specifies if a control is read-only
+ Locked = _PropertyGet(&quot;Locked&quot;, False)
+End Property &apos; SFDocuments.SF_FormControl.Locked (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Locked(Optional ByVal pvLocked As Variant)
+&apos;&apos;&apos; Set the updatable property Locked
+ _PropertySet(&quot;Locked&quot;, pvLocked)
+End Property &apos; SFDocuments.SF_FormControl.Locked (let)
+
+REM -----------------------------------------------------------------------------
+Property Get MultiSelect() As Variant
+&apos;&apos;&apos; The MultiSelect property specifies whether a user can make multiple selections in a listbox
+ MultiSelect = _PropertyGet(&quot;MultiSelect&quot;, False)
+End Property &apos; SFDocuments.SF_FormControl.MultiSelect (get)
+
+REM -----------------------------------------------------------------------------
+Property Let MultiSelect(Optional ByVal pvMultiSelect As Variant)
+&apos;&apos;&apos; Set the updatable property MultiSelect
+ _PropertySet(&quot;MultiSelect&quot;, pvMultiSelect)
+End Property &apos; SFDocuments.SF_FormControl.MultiSelect (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Name() As String
+&apos;&apos;&apos; Return the name of the actual control
+ Name = _PropertyGet(&quot;Name&quot;)
+End Property &apos; SFDocuments.SF_FormControl.Name
+
+REM -----------------------------------------------------------------------------
+Property Get OnActionPerformed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnActionPerformed event
+ OnActionPerformed = _PropertyGet(&quot;OnActionPerformed&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnActionPerformed (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnActionPerformed(Optional ByVal pvOnActionPerformed As Variant)
+&apos;&apos;&apos; Set the updatable property OnActionPerformed
+ _PropertySet(&quot;OnActionPerformed&quot;, pvOnActionPerformed)
+End Property &apos; SFDocuments.SF_FormControl.OnActionPerformed (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnAdjustmentValueChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnAdjustmentValueChanged event
+ OnAdjustmentValueChanged = _PropertyGet(&quot;OnAdjustmentValueChanged&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnAdjustmentValueChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnAdjustmentValueChanged(Optional ByVal pvOnAdjustmentValueChanged As Variant)
+&apos;&apos;&apos; Set the updatable property OnAdjustmentValueChanged
+ _PropertySet(&quot;OnAdjustmentValueChanged&quot;, pvOnAdjustmentValueChanged)
+End Property &apos; SFDocuments.SF_FormControl.OnAdjustmentValueChanged (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveAction() As Variant
+&apos;&apos;&apos; Get the script associated with the OnApproveAction event
+ OnApproveAction = _PropertyGet(&quot;OnApproveAction&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnApproveAction (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveAction(Optional ByVal pvOnApproveAction As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveAction
+ _PropertySet(&quot;OnApproveAction&quot;, pvOnApproveAction)
+End Property &apos; SFDocuments.SF_FormControl.OnApproveAction (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveReset() As Variant
+&apos;&apos;&apos; Get the script associated with the OnApproveReset event
+ OnApproveReset = _PropertyGet(&quot;OnApproveReset&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnApproveReset (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveReset(Optional ByVal pvOnApproveReset As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveReset
+ _PropertySet(&quot;OnApproveReset&quot;, pvOnApproveReset)
+End Property &apos; SFDocuments.SF_FormControl.OnApproveReset (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnApproveUpdate() As Variant
+&apos;&apos;&apos; Get the script associated with the OnApproveUpdate event
+ OnApproveUpdate = _PropertyGet(&quot;OnApproveUpdate&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnApproveUpdate (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnApproveUpdate(Optional ByVal pvOnApproveUpdate As Variant)
+&apos;&apos;&apos; Set the updatable property OnApproveUpdate
+ _PropertySet(&quot;OnApproveUpdate&quot;, pvOnApproveUpdate)
+End Property &apos; SFDocuments.SF_FormControl.OnApproveUpdate (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnChanged event
+ OnChanged = _PropertyGet(&quot;OnChanged&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnChanged(Optional ByVal pvOnChanged As Variant)
+&apos;&apos;&apos; Set the updatable property OnChanged
+ _PropertySet(&quot;OnChanged&quot;, pvOnChanged)
+End Property &apos; SFDocuments.SF_FormControl.OnChanged (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnErrorOccurred() As Variant
+&apos;&apos;&apos; Get the script associated with the OnErrorOccurred event
+ OnErrorOccurred = _PropertyGet(&quot;OnErrorOccurred&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnErrorOccurred (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnErrorOccurred(Optional ByVal pvOnErrorOccurred As Variant)
+&apos;&apos;&apos; Set the updatable property OnErrorOccurred
+ _PropertySet(&quot;OnErrorOccurred&quot;, pvOnErrorOccurred)
+End Property &apos; SFDocuments.SF_FormControl.OnErrorOccurred (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnFocusGained() As Variant
+&apos;&apos;&apos; Get the script associated with the OnFocusGained event
+ OnFocusGained = _PropertyGet(&quot;OnFocusGained&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnFocusGained (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnFocusGained(Optional ByVal pvOnFocusGained As Variant)
+&apos;&apos;&apos; Set the updatable property OnFocusGained
+ _PropertySet(&quot;OnFocusGained&quot;, pvOnFocusGained)
+End Property &apos; SFDocuments.SF_FormControl.OnFocusGained (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnFocusLost() As Variant
+&apos;&apos;&apos; Get the script associated with the OnFocusLost event
+ OnFocusLost = _PropertyGet(&quot;OnFocusLost&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnFocusLost (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnFocusLost(Optional ByVal pvOnFocusLost As Variant)
+&apos;&apos;&apos; Set the updatable property OnFocusLost
+ _PropertySet(&quot;OnFocusLost&quot;, pvOnFocusLost)
+End Property &apos; SFDocuments.SF_FormControl.OnFocusLost (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnItemStateChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnItemStateChanged event
+ OnItemStateChanged = _PropertyGet(&quot;OnItemStateChanged&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnItemStateChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnItemStateChanged(Optional ByVal pvOnItemStateChanged As Variant)
+&apos;&apos;&apos; Set the updatable property OnItemStateChanged
+ _PropertySet(&quot;OnItemStateChanged&quot;, pvOnItemStateChanged)
+End Property &apos; SFDocuments.SF_FormControl.OnItemStateChanged (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnKeyPressed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnKeyPressed event
+ OnKeyPressed = _PropertyGet(&quot;OnKeyPressed&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnKeyPressed (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnKeyPressed(Optional ByVal pvOnKeyPressed As Variant)
+&apos;&apos;&apos; Set the updatable property OnKeyPressed
+ _PropertySet(&quot;OnKeyPressed&quot;, pvOnKeyPressed)
+End Property &apos; SFDocuments.SF_FormControl.OnKeyPressed (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnKeyReleased() As Variant
+&apos;&apos;&apos; Get the script associated with the OnKeyReleased event
+ OnKeyReleased = _PropertyGet(&quot;OnKeyReleased&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnKeyReleased (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnKeyReleased(Optional ByVal pvOnKeyReleased As Variant)
+&apos;&apos;&apos; Set the updatable property OnKeyReleased
+ _PropertySet(&quot;OnKeyReleased&quot;, pvOnKeyReleased)
+End Property &apos; SFDocuments.SF_FormControl.OnKeyReleased (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseDragged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseDragged event
+ OnMouseDragged = _PropertyGet(&quot;OnMouseDragged&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseDragged (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnMouseDragged(Optional ByVal pvOnMouseDragged As Variant)
+&apos;&apos;&apos; Set the updatable property OnMouseDragged
+ _PropertySet(&quot;OnMouseDragged&quot;, pvOnMouseDragged)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseDragged (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseEntered() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseEntered event
+ OnMouseEntered = _PropertyGet(&quot;OnMouseEntered&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseEntered (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnMouseEntered(Optional ByVal pvOnMouseEntered As Variant)
+&apos;&apos;&apos; Set the updatable property OnMouseEntered
+ _PropertySet(&quot;OnMouseEntered&quot;, pvOnMouseEntered)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseEntered (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseExited() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseExited event
+ OnMouseExited = _PropertyGet(&quot;OnMouseExited&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseExited (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnMouseExited(Optional ByVal pvOnMouseExited As Variant)
+&apos;&apos;&apos; Set the updatable property OnMouseExited
+ _PropertySet(&quot;OnMouseExited&quot;, pvOnMouseExited)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseExited (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseMoved() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseMoved event
+ OnMouseMoved = _PropertyGet(&quot;OnMouseMoved&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseMoved (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnMouseMoved(Optional ByVal pvOnMouseMoved As Variant)
+&apos;&apos;&apos; Set the updatable property OnMouseMoved
+ _PropertySet(&quot;OnMouseMoved&quot;, pvOnMouseMoved)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseMoved (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMousePressed() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMousePressed event
+ OnMousePressed = _PropertyGet(&quot;OnMousePressed&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnMousePressed (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnMousePressed(Optional ByVal pvOnMousePressed As Variant)
+&apos;&apos;&apos; Set the updatable property OnMousePressed
+ _PropertySet(&quot;OnMousePressed&quot;, pvOnMousePressed)
+End Property &apos; SFDocuments.SF_FormControl.OnMousePressed (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnMouseReleased() As Variant
+&apos;&apos;&apos; Get the script associated with the OnMouseReleased event
+ OnMouseReleased = _PropertyGet(&quot;OnMouseReleased&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseReleased (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnMouseReleased(Optional ByVal pvOnMouseReleased As Variant)
+&apos;&apos;&apos; Set the updatable property OnMouseReleased
+ _PropertySet(&quot;OnMouseReleased&quot;, pvOnMouseReleased)
+End Property &apos; SFDocuments.SF_FormControl.OnMouseReleased (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnResetted() As Variant
+&apos;&apos;&apos; Get the script associated with the OnResetted event
+ OnResetted = _PropertyGet(&quot;OnResetted&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnResetted (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnResetted(Optional ByVal pvOnResetted As Variant)
+&apos;&apos;&apos; Set the updatable property OnResetted
+ _PropertySet(&quot;OnResetted&quot;, pvOnResetted)
+End Property &apos; SFDocuments.SF_FormControl.OnResetted (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnTextChanged() As Variant
+&apos;&apos;&apos; Get the script associated with the OnTextChanged event
+ OnTextChanged = _PropertyGet(&quot;OnTextChanged&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnTextChanged (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnTextChanged(Optional ByVal pvOnTextChanged As Variant)
+&apos;&apos;&apos; Set the updatable property OnTextChanged
+ _PropertySet(&quot;OnTextChanged&quot;, pvOnTextChanged)
+End Property &apos; SFDocuments.SF_FormControl.OnTextChanged (let)
+
+REM -----------------------------------------------------------------------------
+Property Get OnUpdated() As Variant
+&apos;&apos;&apos; Get the script associated with the OnUpdated event
+ OnUpdated = _PropertyGet(&quot;OnUpdated&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.OnUpdated (get)
+
+REM -----------------------------------------------------------------------------
+Property Let OnUpdated(Optional ByVal pvOnUpdated As Variant)
+&apos;&apos;&apos; Set the updatable property OnUpdated
+ _PropertySet(&quot;OnUpdated&quot;, pvOnUpdated)
+End Property &apos; SFDocuments.SF_FormControl.OnUpdated (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Parent() As Object
+&apos;&apos;&apos; Return the Parent form or [table]control object of the actual control
+ Parent = _PropertyGet(&quot;Parent&quot;, Nothing)
+End Property &apos; SFDocuments.SF_FormControl.Parent
+
+REM -----------------------------------------------------------------------------
+Property Get Picture() As Variant
+&apos;&apos;&apos; The Picture property specifies a bitmap or other type of graphic to be displayed on the specified control
+ Picture = _PropertyGet(&quot;Picture&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.Picture (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Picture(Optional ByVal pvPicture As Variant)
+&apos;&apos;&apos; Set the updatable property Picture
+ _PropertySet(&quot;Picture&quot;, pvPicture)
+End Property &apos; SFDocuments.SF_FormControl.Picture (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Required() As Variant
+&apos;&apos;&apos; A control is said Required when it must not contain a null value
+ Required = _PropertyGet(&quot;Required&quot;, False)
+End Property &apos; SFDocuments.SF_FormControl.Required (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Required(Optional ByVal pvRequired As Variant)
+&apos;&apos;&apos; Set the updatable property Required
+ _PropertySet(&quot;Required&quot;, pvRequired)
+End Property &apos; SFDocuments.SF_FormControl.Required (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Text() As Variant
+&apos;&apos;&apos; The Text property specifies the actual content of the control like it is displayed on the screen
+ Text = _PropertyGet(&quot;Text&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.Text (get)
+
+REM -----------------------------------------------------------------------------
+Property Get TipText() As Variant
+&apos;&apos;&apos; The TipText property specifies the text that appears in a screentip when you hold the mouse pointer over a control
+ TipText = _PropertyGet(&quot;TipText&quot;, &quot;&quot;)
+End Property &apos; SFDocuments.SF_FormControl.TipText (get)
+
+REM -----------------------------------------------------------------------------
+Property Let TipText(Optional ByVal pvTipText As Variant)
+&apos;&apos;&apos; Set the updatable property TipText
+ _PropertySet(&quot;TipText&quot;, pvTipText)
+End Property &apos; SFDocuments.SF_FormControl.TipText (let)
+
+REM -----------------------------------------------------------------------------
+Property Get TripleState() As Variant
+&apos;&apos;&apos; The TripleState property specifies how a check box will display Null values
+&apos;&apos;&apos; When True, the control will cycle through states for Yes, No, and Null values. The control appears dimmed (grayed) when its Value property is set to Null.
+&apos;&apos;&apos; When False, the control will cycle through states for Yes and No values. Null values display as if they were No values.
+ TripleState = _PropertyGet(&quot;TripleState&quot;, False)
+End Property &apos; SFDocuments.SF_FormControl.TripleState (get)
+
+REM -----------------------------------------------------------------------------
+Property Let TripleState(Optional ByVal pvTripleState As Variant)
+&apos;&apos;&apos; Set the updatable property TripleState
+ _PropertySet(&quot;TripleState&quot;, pvTripleState)
+End Property &apos; SFDocuments.SF_FormControl.TripleState (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Value() As Variant
+&apos;&apos;&apos; The Value property specifies the data contained in the control
+ Value = _PropertyGet(&quot;Value&quot;, Empty)
+End Property &apos; SFDocuments.SF_FormControl.Value (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Value(Optional ByVal pvValue As Variant)
+&apos;&apos;&apos; Set the updatable property Value
+ _PropertySet(&quot;Value&quot;, pvValue)
+End Property &apos; SFDocuments.SF_FormControl.Value (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Visible() As Variant
+&apos;&apos;&apos; The Visible property specifies if the control is accessible with the cursor.
+ Visible = _PropertyGet(&quot;Visible&quot;, True)
+End Property &apos; SFDocuments.SF_FormControl.Visible (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Visible(Optional ByVal pvVisible As Variant)
+&apos;&apos;&apos; Set the updatable property Visible
+ _PropertySet(&quot;Visible&quot;, pvVisible)
+End Property &apos; SFDocuments.SF_FormControl.Visible (let)
+
+REM -----------------------------------------------------------------------------
+Property Get XControlModel() As Object
+&apos;&apos;&apos; The XControlModel property returns the model UNO object of the control
+ XControlModel = _PropertyGet(&quot;XControlModel&quot;, Nothing)
+End Property &apos; SFDocuments.SF_FormControl.XControlModel (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XControlView() As Object
+&apos;&apos;&apos; The XControlView property returns the view UNO object of the control
+ XControlView = _PropertyGet(&quot;XControlView&quot;, Nothing)
+End Property &apos; SFDocuments.SF_FormControl.XControlView (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Controls(Optional ByVal ControlName As Variant) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the controls contained in the actual table control
+&apos;&apos;&apos; - a Form Control object based on its name
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ControlName: a valid control name as a case-sensitive string. If absent the list is returned
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-base array of strings if ControlName is absent
+&apos;&apos;&apos; An instance of the SF_FormControl class if ControlName exists
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; ControlName is invalid
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myGrid As Object, myList As Variant, myControl As Object
+&apos;&apos;&apos; Set myGrid = myForm.Controls(&quot;myTableControl&quot;)
+&apos;&apos;&apos; myList = myGrid.Controls()
+&apos;&apos;&apos; Set myControl = myGrid.Controls(&quot;myCheckBox&quot;)
+
+Dim oControl As Object &apos; The new control class instance
+Dim lIndexOfNames As Long &apos; Index in ElementNames array. Used to access _ControlCache
+Dim vControl As Variant &apos; Alias of _ControlCache entry
+Dim oView As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
+Dim i As Long
+Const cstThisSub = &quot;SFDocuments.FormControl.Controls&quot;
+Const cstSubArgs = &quot;[ControlName]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set Controls = Nothing
+
+Check:
+ If IsMissing(ControlName) Or IsEmpty(ControlName) Then ControlName = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If _ControlType &lt;&gt; CTLTABLECONTROL Then GoTo Catch
+ If Not [_Parent]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ControlName, &quot;ControlName&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Collect all control names if not yet done
+ If UBound(_ControlNames) &lt; 0 Then
+ _ControlNames = _ControlModel.getElementNames()
+ If UBound(_ControlNames) &gt;= 0 Then
+ ReDim _ControlCache(0 To UBound(_ControlNames))
+ End If
+ End If
+
+ &apos; Return the list of controls or a FormControl instance
+ If Len(ControlName) = 0 Then
+ Controls = _ControlNames
+
+ Else
+
+ If Not _ControlModel.hasByName(ControlName) Then GoTo CatchNotFound
+ lIndexOfNames = ScriptForge.SF_Array.IndexOf(_ControlNames, ControlName, CaseSensitive := True)
+ &apos; Reuse cache when relevant
+ vControl = _ControlCache(lIndexOfNames)
+
+ If IsEmpty(vControl) Then
+ &apos; Not in cache =&gt; Create the new form control class instance
+ Set oControl = New SF_FormControl
+ With oControl
+ ._Name = ControlName
+ Set .[Me] = oControl
+ Set .[_Parent] = [Me]
+ ._ParentIsTable = True
+ ._IndexOfNames = lIndexOfNames
+ ._FormName = _FormName
+ Set ._ParentForm = _ParentForm
+ &apos; Get model and view of the current control
+ Set ._ControlModel = _ControlModel.getByName(ControlName)
+ ._ImplementationName = ._ControlModel.ColumnServiceName &apos; getImplementationName aborts for subcontrols !?
+ &apos; Bypass to find the control view: cannot be done from the top component
+ If Not IsNull(_ControlView) Then &apos; Anticipate absence of ControlView in table controls when edit mode
+ For i = 0 to _ControlView.getCount() - 1
+ Set oView = _ControlView.GetByIndex(i)
+ If Not IsNull(oView) Then
+ If oView.getModel.Name = ControlName Then
+ Set ._ControlView = oView
+ Exit For
+ End If
+ End If
+ Next i
+ End If
+ ._Initialize()
+ End With
+ Else
+ Set oControl = vControl
+ End If
+
+ Set Controls = oControl
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Utils._Validate(ControlName, &quot;ControlName&quot;, V_STRING, _ControlModel.getElementNames())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_FormControl.Controls
+
+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; myControl.GetProperty(&quot;MyProperty&quot;)
+
+Dim vDefault As Variant &apos; Default value when property not applicable on control type
+Const cstThisSub = &quot;SFDocuments.FormControl.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; FormControl properties are far from applicable to all control types
+ &apos; Getting a property must never abort to not interfere with the Basic IDE watch function
+ &apos; Hence a default value must be provided
+ Select Case UCase(PropertyName)
+ Case UCase(&quot;Default&quot;) : vDefault = False
+ Case UCase(&quot;DefaultValue&quot;) : vDefault = Null
+ Case UCase(&quot;Enabled&quot;) : vDefault = False
+ Case UCase(&quot;ListCount&quot;) : vDefault = 0
+ Case UCase(&quot;ListIndex&quot;) : vDefault = -1
+ Case UCase(&quot;Locked&quot;) : vDefault = False
+ Case UCase(&quot;MultiSelect&quot;) : vDefault = False
+ Case UCase(&quot;Parent&quot;) : vDefault = Nothing
+ Case UCase(&quot;Required&quot;) : vDefault = False
+ Case UCase(&quot;TripleState&quot;) : vDefault = False
+ Case UCase(&quot;Value&quot;) : vDefault = Empty
+ Case UCase(&quot;Visible&quot;) : vDefault = True
+ Case UCase(&quot;XControlModel&quot;) : vDefault = Nothing
+ Case UCase(&quot;XControlView&quot;) : vDefault = Nothing
+ Case Else : vDefault = &quot;&quot;
+ End Select
+
+ GetProperty = _PropertyGet(PropertyName, vDefault)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_FormControl.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the FormControl service as an array
+
+ Methods = Array( _
+ &quot;AddSubNode&quot; _
+ , &quot;AddSubTree&quot; _
+ , &quot;CreateRoot&quot; _
+ , &quot;FindNode&quot; _
+ , &quot;SetFocus&quot; _
+ , &quot;WriteLine&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_FormControl.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the FormControl class as an array
+
+ Properties = Array( _
+ &quot;Action&quot; _
+ , &quot;Cancel&quot; _
+ , &quot;Caption&quot; _
+ , &quot;ControlSource&quot; _
+ , &quot;ControlType&quot; _
+ , &quot;Default&quot; _
+ , &quot;DefaultValue&quot; _
+ , &quot;Enabled&quot; _
+ , &quot;Format&quot; _
+ , &quot;ListCount&quot; _
+ , &quot;ListIndex&quot; _
+ , &quot;ListSource&quot; _
+ , &quot;ListSourceType&quot; _
+ , &quot;Locked&quot; _
+ , &quot;MultiSelect&quot; _
+ , &quot;Name&quot; _
+ , &quot;OnActionPerformed&quot; _
+ , &quot;OnAdjustmentValueChanged&quot; _
+ , &quot;OnApproveAction&quot; _
+ , &quot;OnApproveReset&quot; _
+ , &quot;OnApproveUpdate&quot; _
+ , &quot;OnChanged&quot; _
+ , &quot;OnErrorOccurred&quot; _
+ , &quot;OnFocusGained&quot; _
+ , &quot;OnFocusLost&quot; _
+ , &quot;OnItemStateChanged&quot; _
+ , &quot;OnKeyPressed&quot; _
+ , &quot;OnKeyReleased&quot; _
+ , &quot;OnMouseDragged&quot; _
+ , &quot;OnMouseEntered&quot; _
+ , &quot;OnMouseExited&quot; _
+ , &quot;OnMouseMoved&quot; _
+ , &quot;OnMousePressed&quot; _
+ , &quot;OnMouseReleased&quot; _
+ , &quot;OnResetted&quot; _
+ , &quot;OnTextChanged&quot; _
+ , &quot;OnUpdated&quot; _
+ , &quot;Parent&quot; _
+ , &quot;Picture&quot; _
+ , &quot;Required&quot; _
+ , &quot;Text&quot; _
+ , &quot;TipText&quot; _
+ , &quot;TripleState&quot; _
+ , &quot;Value&quot; _
+ , &quot;Visible&quot; _
+ , &quot;XControlModel&quot; _
+ , &quot;XControlView&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_FormControl.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function SetFocus() As Boolean
+&apos;&apos;&apos; Set the focus on the current Control instance
+&apos;&apos;&apos; Probably called from after an event occurrence
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if focusing is successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDoc As Object, oForm As Object, oControl As Object
+&apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.Document&quot;, ThisComponent)
+&apos;&apos;&apos; Set oForm = oDoc.Forms(0)
+&apos;&apos;&apos; Set oControl = oForm.Controls(&quot;thisControl&quot;)
+&apos;&apos;&apos; oControl.SetFocus()
+
+Dim bSetFocus As Boolean &apos; Return value
+Dim iColPosition As Integer &apos; Position of control in table
+Dim oTableModel As Object &apos; XControlModel of parent table
+Dim oControl As Object &apos; com.sun.star.awt.XControlModel
+Dim i As Integer, j As Integer
+Const cstThisSub = &quot;SFDocuments.FormControl.SetFocus&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSetFocus = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _ParentForm._IsStillAlive() Then GoTo Finally
+ End If
+
+Try:
+ If Not IsNull(_ControlView) Then
+ If _ParentIsTable Then &apos; setFocus() method does not work on controlviews in table control ?!?
+ &apos; Find the column position of the current instance in the parent table control
+ iColPosition = -1
+ Set oTableModel = [_Parent]._ControlModel
+ j = -1
+ For i = 0 To oTableModel.Count - 1
+ Set oControl = oTableModel.getByIndex(i)
+ If Not oControl.Hidden Then j = j + 1 &apos; Skip hidden columns
+ If oControl.Name = _Name Then
+ iColPosition = j
+ Exit For
+ End If
+ Next i
+ If iColPosition &gt;= 0 Then
+ [_Parent]._ControlView.setFocus() &apos;Set first focus on table control itself
+ [_Parent]._ControlView.setCurrentColumnPosition(iColPosition) &apos;Deprecated but no alternative found
+ End If
+ Else
+ _ControlView.setFocus()
+ End If
+ bSetFocus = True
+ End If
+ bSetFocus = True
+
+Finally:
+ SetFocus = bSetFocus
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFControls.SF_FormControl.SetFocus
+
+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.FormControl.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 ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_FormControl.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _FormatsList() As Variant
+&apos;&apos;&apos; Return the allowed format entries as a zero-based array for Date and Time control types
+
+Dim vFormats() As Variant &apos; Return value
+
+ Select Case _ControlType
+ Case CTLDATEFIELD
+ vFormats = Array( _
+ &quot;Standard (short)&quot; _
+ , &quot;Standard (short YY)&quot; _
+ , &quot;Standard (short YYYY)&quot; _
+ , &quot;Standard (long)&quot; _
+ , &quot;DD/MM/YY&quot; _
+ , &quot;MM/DD/YY&quot; _
+ , &quot;YY/MM/DD&quot; _
+ , &quot;DD/MM/YYYY&quot; _
+ , &quot;MM/DD/YYYY&quot; _
+ , &quot;YYYY/MM/DD&quot; _
+ , &quot;YY-MM-DD&quot; _
+ , &quot;YYYY-MM-DD&quot; _
+ )
+ Case CTLTIMEFIELD
+ vFormats = Array( _
+ &quot;24h short&quot; _
+ , &quot;24h long&quot; _
+ , &quot;12h short&quot; _
+ , &quot;12h long&quot; _
+ )
+ Case Else
+ vFormats = Array()
+ End Select
+
+ _FormatsList = vFormats
+
+End Function &apos; SFDocuments.SF_FormControl._FormatsList
+
+REM -----------------------------------------------------------------------------
+Public Function _GetEventName(ByVal psProperty As String) As String
+&apos;&apos;&apos; Return the LO internal event name derived from the SF property name
+&apos;&apos;&apos; The SF property name is not case sensitive, while the LO name is case-sensitive
+&apos; Corrects the typo on ErrorOccur(r?)ed, if necessary
+
+Dim vProperties As Variant &apos; Array of class properties
+Dim sProperty As String &apos; Correctly cased property name
+
+ vProperties = Properties()
+ sProperty = vProperties(ScriptForge.SF_Array.IndexOf(vProperties, psProperty, SortOrder := &quot;ASC&quot;))
+
+ _GetEventName = LCase(Mid(sProperty, 3, 1)) &amp; Right(sProperty, Len(sProperty) - 3)
+
+End Function &apos; SFDocuments.SF_FormControl._GetEventName
+
+REM -----------------------------------------------------------------------------
+Private Function _GetListener(ByVal psEventName As String) As String
+&apos;&apos;&apos; Getting/Setting macros triggered by events requires a Listener-EventName pair
+&apos;&apos;&apos; Return the X...Listener corresponding with the event name in argument
+
+ Select Case UCase(psEventName)
+ Case UCase(&quot;OnActionPerformed&quot;)
+ _GetListener = &quot;XActionListener&quot;
+ Case UCase(&quot;OnAdjustmentValueChanged&quot;)
+ _GetListener = &quot;XAdjustmentListener&quot;
+ Case UCase(&quot;OnApproveAction&quot;)
+ _GetListener = &quot;XApproveActionListener&quot;
+ Case UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnResetted&quot;)
+ _GetListener = &quot;XResetListener&quot;
+ Case UCase(&quot;OnApproveUpdate&quot;), UCase(&quot;OnUpdated&quot;)
+ _GetListener = &quot;XUpdateListener&quot;
+ Case UCase(&quot;OnChanged&quot;)
+ _GetListener = &quot;XChangeListener&quot;
+ Case UCase(&quot;OnErrorOccurred&quot;)
+ _GetListener = &quot;XErrorListener&quot;
+ Case UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;)
+ _GetListener = &quot;XFocusListener&quot;
+ Case UCase(&quot;OnItemStateChanged&quot;)
+ _GetListener = &quot;XItemListener&quot;
+ Case UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;)
+ _GetListener = &quot;XKeyListener&quot;
+ Case UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseMoved&quot;)
+ _GetListener = &quot;XMouseMotionListener&quot;
+ Case UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;)
+ _GetListener = &quot;XMouseListener&quot;
+ Case UCase(&quot;OnTextChanged&quot;)
+ _GetListener = &quot;XTextListener&quot;
+ End Select
+
+End Function &apos; SFDocuments.SF_FormControl._GetListener
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos;&apos;&apos; Complete the object creation process:
+&apos;&apos;&apos; - Initialization of private members
+&apos;&apos;&apos; - Collection of specific attributes
+&apos;&apos;&apos; - Synchronization with parent form instance
+
+Dim vControlTypes As Variant &apos; Array of control types ordered by the ClassId property of XControlModel - 2
+Const acHiddenControl = 13 &apos; Class Id of an hidden control: has no ControlView
+
+ vControlTypes = array( CTLBUTTON _
+ , CTLRADIOBUTTON _
+ , CTLIMAGEBUTTON _
+ , CTLCHECKBOX _
+ , CTLLISTBOX _
+ , CTLCOMBOBOX _
+ , CTLGROUPBOX _
+ , CTLTEXTFIELD _
+ , CTLFIXEDTEXT _
+ , CTLTABLECONTROL _
+ , CTLFILECONTROL _
+ , CTLHIDDENCONTROL _
+ , CTLIMAGECONTROL _
+ , CTLDATEFIELD _
+ , CTLTIMEFIELD _
+ , CTLNUMERICFIELD _
+ , CTLCURRENCYFIELD _
+ , CTLPATTERNFIELD _
+ , CTLSCROLLBAR _
+ , CTLSPINBUTTON _
+ , CTLNAVIGATIONBAR _
+ )
+
+Try:
+ &apos; _implementationName is set elsewhere for controls in table control
+ If Len(_ImplementationName) = 0 Then _ImplementationName = ScriptForge.SF_Session.UnoObjectType(_ControlModel)
+ _ClassId = _ControlModel.ClassId
+
+ &apos; Identify the control type, ignore subforms and pay attention to formatted fields
+ If ScriptForge.SF_Session.HasUnoproperty(_ControlModel, &quot;ClassId&quot;) Then &apos; All control types have a ClassId property except subforms
+ _ControlType = vControlTypes(_ClassId - 2)
+ &apos; Formatted fields belong to the TextField family
+ If _ControlType = CTLTEXTFIELD Then
+ If _ImplementationName = &quot;com.sun.star.comp.forms.OFormattedFieldWrapper&quot; _
+ Or _ImplementationName = &quot;com.sun.star.comp.forms.OFormattedFieldWrapper_ForcedFormatted&quot; _
+ Or _ImplementationName = &quot;com.sun.star.form.component.FormattedField&quot; Then &apos; When in table control
+ _ControlType = CTLFORMATTEDFIELD
+ End If
+ End If
+ Else
+ Exit Sub &apos; Ignore subforms, should not happen
+ End If
+
+ With [_Parent]
+ &apos; Set control view if not set yet
+ If IsNull(_ControlView) Then
+ If _ClassId &gt; 0 And _ClassId &lt;&gt; acHiddenControl Then &apos; No view on hidden controls
+ If IsNull(._FormDocument) Then &apos; Usual document
+ Set _ControlView = ._Component.CurrentController.getControl(_ControlModel)
+ Else &apos; Base form document
+ Set _ControlView = ._FormDocument.Component.CurrentController.getControl(_ControlModel)
+ End If
+ End If
+ End If
+ End With
+
+ &apos; Store the SF_FormControl object in the parent cache
+ Set _Parent._ControlCache(_IndexOfNames) = [Me]
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDocuments.SF_FormControl._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _ListboxBound() As Boolean
+&apos;&apos;&apos; Return True if the actual control, which is a listbox, has a bound column
+&apos;&apos;&apos; Called before setting the value of a listbox, i.e. the value to be rewritten in the underlying table data
+&apos;&apos;&apos; The existence of a bound column is derived from the comparison between StringItemList and ValueItemList
+&apos;&apos;&apos; String ... : the strings displayed in the list box
+&apos;&apos;&apos; Value ... : the database values
+&apos;&apos;&apos; If they are different, then there is a bound column
+
+Dim bListboxBound As Boolean &apos; Return value
+Dim vValue() As Variant &apos; Alias of the control model ValueItemList
+Dim vString() As Variant &apos; Alias of the control model StringItemList
+Dim i As Long
+
+ bListboxBound = False
+
+ With _ControlModel
+ If Not IsNull(.ValueItemList) _
+ And .DataField &lt;&gt; &quot;&quot; _
+ And Not IsNull(.BoundField) _
+ And ScriptForge.SF_Array.Contains(Array( _
+ com.sun.star.form.ListSourceType.TABLE _
+ , com.sun.star.form.ListSourceType.QUERY _
+ , com.sun.star.form.ListSourceType.SQL _
+ , com.sun.star.form.ListSourceType.SQLPASSTHROUGH _
+ ), .ListSourceType) Then
+ If IsArray(.ValueItemList) Then
+ vValue = .ValueItemList
+ vString = .StringItemList
+ For i = 0 To UBound(vValue)
+ If VarType(vValue(i)) &lt;&gt; VarType(vString(i)) Then
+ bListboxBound = True
+ ElseIf vValue(i) &lt;&gt; vString(i) Then
+ bListboxBound = True
+ End If
+ If bListboxBound Then Exit For
+ Next i
+ End If
+ End If
+ End With
+
+ _ListboxBound = bListboxBound
+
+End Function &apos; _ListboxBound V0.9.0
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String _
+ , Optional ByVal pvDefault 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
+&apos;&apos;&apos; pvDefault: the value returned when the property is not applicable on the control&apos;s type
+&apos;&apos;&apos; Getting a non-existing property for a specific control type should
+&apos;&apos;&apos; not generate an error to not disrupt the Basic IDE debugger
+
+Dim vGet As Variant &apos; Return value
+Static oSession As Object &apos; Alias of SF_Session
+Dim vSelection As Variant &apos; Alias of Model.SelectedItems or Model.Selection
+Dim vList As Variant &apos; Alias of Model.StringItemList
+Dim lIndex As Long &apos; Index in StringItemList
+Dim sItem As String &apos; A single item
+Dim vDate As Variant &apos; Date after conversion from com.sun.star.util.Date or com.sun.star.util.Time
+Dim vValues As Variant &apos; Array of listbox values
+Dim oControlEvents As Object &apos; com.sun.star.container.XNameContainer
+Dim sEventName As String &apos; Internal event name
+Const cstUnoUrl = &quot;.uno:FormController/&quot;
+Dim i As Long
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDocuments.FormControl.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _ParentForm._IsStillAlive() Then GoTo Finally
+
+ If IsMissing(pvDefault) Or IsEmpty(pvDefault) Then pvDefault = Null
+ _PropertyGet = pvDefault
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Action&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;ButtonType&quot;) Then
+ Select Case _ControlModel.ButtonType
+ Case com.sun.star.form.FormButtonType.PUSH : _PropertyGet = &quot;none&quot;
+ Case com.sun.star.form.FormButtonType.SUBMIT : _PropertyGet = &quot;submitForm&quot;
+ Case com.sun.star.form.FormButtonType.RESET : _PropertyGet = &quot;resetForm&quot;
+ Case com.sun.star.form.FormButtonType.URL
+ &apos; &quot;.uno:FormController/moveToFirst&quot;
+ If Left(_ControlModel.TargetURL, Len(cstUnoUrl)) = cstUnoUrl Then
+ _PropertyGet = Mid(_ControlModel.TargetURL, Len(cstUnoUrl) + 1)
+ ElseIf Left(_ControlModel.TargetURL, 4) = &quot;http&quot; Then
+ _PropertyGet = &quot;openWebPage&quot;
+ ElseIf Left(_ControlModel.TargetURL, 4) = &quot;file&quot; Then
+ _PropertyGet =&quot;openDocument&quot;
+ End If
+ End Select
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Caption&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLCHECKBOX, CTLFIXEDTEXT, CTLGROUPBOX, CTLRADIOBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;Label&quot;) Then _PropertyGet = _ControlModel.Label
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ControlSource&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX, CTLCOMBOBOX, CTLCURRENCYFIELD, CTLDATEFIELD, CTLFORMATTEDFIELD, CTLIMAGECONTROL, CTLLISTBOX _
+ , CTLNUMERICFIELD, CTLPATTERNFIELD, CTLRADIOBUTTON, CTLTEXTFIELD, CTLTIMEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DataField&quot;) Then _PropertyGet = _ControlModel.DataField
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ControlType&quot;)
+ _PropertyGet = _ControlType
+ Case UCase(&quot;Default&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultButton&quot;) Then _PropertyGet = _ControlModel.DefaultButton
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;DefaultValue&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX, CTLRADIOBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultState&quot;) Then _PropertyGet = _ControlModel.DefaultState
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultText&quot;) Then _PropertyGet = _ControlModel.DefaultText
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultValue&quot;) Then _PropertyGet = _ControlModel.DefaultValue
+ Case CTLDATEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultDate&quot;) Then
+ If Not IsEmpty(_ControlModel.DefaultDate) Then
+ With _ControlModel.DefaultDate
+ vDate = DateSerial(.Year, .Month, .Day)
+ End With
+ _PropertyGet = vDate
+ End If
+ End If
+ Case CTLFORMATTEDFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;EffectiveDefault&quot;) Then _PropertyGet = _ControlModel.EffectiveDefault
+ Case CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultSelection&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ vList = _ControlModel.DefaultSelection
+ If IsArray(vList) Then
+ If UBound(vList) &gt;= LBound(vList) Then &apos; Is array initialized ?
+ lIndex = UBound(_ControlModel.StringItemList)
+ If vList(0) &gt;= 0 And vList(0) &lt;= lIndex Then _PropertyGet = _ControlModel.StringItemList(vList(0))
+ &apos; Only first default value is considered
+ End If
+ End If
+ End If
+ Case CTLSPINBUTTON
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultSpinValue&quot;) Then _PropertyGet = _ControlModel.DefaultSpinValue
+ Case CTLTIMEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultTime&quot;) Then
+ If Not IsEmpty(_ControlModel.DefaultTime) Then
+ With _ControlModel.DefaultTime
+ vDate = TimeSerial(.Hours, .Minutes, .Seconds)
+ End With
+ _PropertyGet = vDate
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Enabled&quot;)
+ Select Case _ControlType
+ Case CTLHIDDENCONTROL : GoTo CatchType
+ Case Else
+ If oSession.HasUnoProperty(_ControlModel, &quot;Enabled&quot;) Then _PropertyGet = _ControlModel.Enabled
+ End Select
+ Case UCase(&quot;Format&quot;)
+ Select Case _ControlType
+ Case CTLDATEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;DateFormat&quot;) Then _PropertyGet = _FormatsList()(_ControlModel.DateFormat)
+ Case CTLTIMEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;TimeFormat&quot;) Then _PropertyGet = _FormatsList()(_ControlModel.TimeFormat)
+ Case CTLFORMATTEDFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;FormatsSupplier&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;FormatKey&quot;) Then
+ _PropertyGet = _ControlModel.FormatsSupplier.getNumberFormats.getByKey(_ControlModel.FormatKey).FormatString
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListCount&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then _PropertyGet = UBound(_ControlModel.StringItemList) + 1
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListIndex&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX
+ _PropertyGet = -1 &apos; Not found, multiselection
+ If oSession.HasUNOProperty(_ControlModel, &quot;Text&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ _PropertyGet = ScriptForge.SF_Array.IndexOf(_ControlModel.StringItemList, _ControlModel.Text, CaseSensitive := True)
+ End If
+ Case CTLLISTBOX
+ _PropertyGet = -1 &apos; Not found, multiselection
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectedItems&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ vSelection = _ControlModel.SelectedItems
+ If UBound(vSelection) &gt;= 0 Then _PropertyGet = vSelection(0)
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListSource&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;ListSource&quot;) Then
+ With com.sun.star.form.ListSourceType
+ Select Case _ControlModel.ListSourceType
+ Case .VALUELIST _
+ , .TABLEFIELDS
+ If IsArray(_ControlModel.StringItemList) Then vValues = _ControlModel.StringItemList Else vValues = Array(_ControlModel.StringItemList)
+ Case .TABLE _
+ , .QUERY _
+ , .SQL _
+ , .SQLPASSTHROUGH
+ If IsArray(_ControlModel.ListSource) Then vValues = _ControlModel.ListSource Else vValues = Array(_ControlModel.ListSource)
+ End Select
+ End With
+ _PropertyGet = Join(vValues, &quot;;&quot;)
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListSourceType&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;ListSourceType&quot;) Then _PropertyGet = _ControlModel.ListSourceType
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Locked&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLCURRENCYFIELD, CTLDATEFIELD, CTLFILECONTROL, CTLFORMATTEDFIELD, CTLIMAGECONTROL _
+ , CTLLISTBOX, CTLNUMERICFIELD, CTLPATTERNFIELD, CTLTEXTFIELD, CTLTIMEFIELD
+ If oSession.HasUnoProperty(_ControlModel, &quot;ReadOnly&quot;) Then _PropertyGet = _ControlModel.ReadOnly
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;MultiSelect&quot;)
+ Select Case _ControlType
+ Case CTLLISTBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then
+ _PropertyGet = _ControlModel.MultiSelection
+ ElseIf oSession.HasUnoProperty(_ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then &apos; Not documented: gridcontrols only TBC ??
+ _PropertyGet = _ControlModel.MultiSelectionSimpleMode
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Name&quot;)
+ _PropertyGet = _Name
+ Case UCase(&quot;OnActionPerformed&quot;), UCase(&quot;OnAdjustmentValueChanged&quot;), UCase(&quot;OnApproveAction&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveUpdate&quot;) _
+ , UCase(&quot;OnChanged&quot;), UCase(&quot;OnErrorOccurred&quot;), UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;) _
+ , UCase(&quot;OnItemStateChanged&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;), UCase(&quot;OnResetted&quot;) _
+ , UCase(&quot;OnTextChanged&quot;), UCase(&quot;OnUpdated&quot;)
+ If IsNull(_ControlModel) Then _PropertyGet = &quot;&quot; Else _PropertyGet = SF_Register._GetEventScriptCode(_ControlModel, psProperty, _Name)
+ Case UCase(&quot;Parent&quot;)
+ Set _PropertyGet = [_Parent]
+ Case UCase(&quot;Picture&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLIMAGEBUTTON, CTLIMAGECONTROL
+ If oSession.HasUnoProperty(_ControlModel, &quot;ImageURL&quot;) Then _PropertyGet = ScriptForge.SF_FileSystem._ConvertFromUrl(_ControlModel.ImageURL)
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Required&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX, CTLCOMBOBOX, CTLCURRENCYFIELD, CTLDATEFIELD, CTLIMAGECONTROL, CTLLISTBOX, CTLNUMERICFIELD _
+ , CTLPATTERNFIELD, CTLRADIOBUTTON, CTLTEXTFIELD, CTLTIMEFIELD
+ If oSession.HasUnoProperty(_ControlModel, &quot;InputRequired&quot;) Then _PropertyGet = _ControlModel.InputRequired
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Text&quot;)
+ Select Case _ControlType
+ Case CTLDATEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;Date&quot;) _
+ And oSession.HasUNOProperty(_ControlModel, &quot;FormatKey&quot;) _
+ And oSession.HasUNOProperty(_ControlModel, &quot;FormatsSupplier&quot;) Then
+ If Not IsEmpty(_ControlModel.Date) Then
+ With _ControlModel.Date
+ vDate = DateSerial(.Year, .Month, .Day)
+ End With
+ _PropertyGet = Format(vDate, _ControlModel.FormatsSupplier.getNumberFormats.getByKey(_ControlModel.FormatKey).FormatString)
+ End If
+ End If
+ Case CTLTIMEFIELD
+ If oSession.HasUNOProperty(_ControlModel, &quot;Text&quot;) Then
+ If Not IsEmpty(_ControlModel.Time) Then
+ With _ControlModel.Time
+ vDate = TimeSerial(.Hours, .Minutes, .Seconds)
+ End With
+ _PropertyGet = Format(vDate, &quot;HH:MM:SS&quot;)
+ End If
+ End If
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLFORMATTEDFIELD, CTLPATTERNFIELD, CTLTEXTFIELD
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then _PropertyGet = _ControlModel.Text
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;TipText&quot;)
+ Select Case _ControlType
+ Case CTLHIDDENCONTROL : GoTo CatchType
+ Case Else
+ If oSession.HasUnoProperty(_ControlModel, &quot;HelpText&quot;) Then _PropertyGet = _ControlModel.HelpText
+ End Select
+ Case UCase(&quot;TripleState&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;TriState&quot;) Then _PropertyGet = _ControlModel.TriState
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Value&quot;) &apos; Default values are set here by control type, not in the 2nd argument (pvDefault)
+ vGet = pvDefault
+ Select Case _ControlType
+ Case CTLBUTTON &apos;Boolean, toggle buttons only
+ vGet = False
+ If oSession.HasUnoProperty(_ControlModel, &quot;Toggle&quot;) Then
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then vGet = ( _ControlModel.State = 1 )
+ End If
+ Case CTLCHECKBOX &apos;0 = Not checked, 1 = Checked, 2 = Don&apos;t know
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then vGet = _ControlModel.State Else vGet = 2
+ Case CTLCOMBOBOX, CTLFILECONTROL, CTLPATTERNFIELD, CTLTEXTFIELD &apos;String
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then vGet = _ControlModel.Text Else vGet = &quot;&quot;
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD &apos;Numeric
+ If oSession.HasUnoProperty(_ControlModel, &quot;Value&quot;) Then vGet = _ControlModel.Value Else vGet = 0
+ Case CTLDATEFIELD &apos;Date
+ vGet = CDate(1)
+ If oSession.HasUnoProperty(_ControlModel, &quot;Date&quot;) Then
+ If VarType(_ControlModel.Date) = ScriptForge.V_OBJECT Then &apos; com.sun.star.util.Date
+ With _ControlModel.Date
+ vDate = DateSerial(.Year, .Month, .Day)
+ End With
+ vGet = vDate
+ Else &apos; .Date = Empty
+ End If
+ End If
+ Case CTLFORMATTEDFIELD &apos;String or numeric
+ If oSession.HasUnoProperty(_ControlModel, &quot;EffectiveValue&quot;) Then vGet = _ControlModel.EffectiveValue Else vGet = &quot;&quot;
+ Case CTLHIDDENCONTROL &apos;String
+ If oSession.HasUnoProperty(_ControlModel, &quot;HiddenValue&quot;) Then vGet = _ControlModel.HiddenValue Else vGet = &quot;&quot;
+ Case CTLLISTBOX &apos;String or array of strings depending on MultiSelection
+ &apos; StringItemList is the list of the items displayed in the box
+ &apos; ValueItemList is the list of the values in the underlying database field
+ &apos; SelectedItems is the list of the indexes in StringItemList of the selected items
+ &apos; It can go beyond the limits of StringItemList
+ &apos; It can contain multiple values even if the listbox is not multiselect
+ If oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;SelectedItems&quot;) _
+ And oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then
+ vSelection = _ControlModel.SelectedItems
+ &apos; The list of allowed values depends on the existence of a bound column
+ If _ListBoxBound() Then vList = _ControlModel.ValueItemList Else vList = _ControlModel.StringItemList
+ If _ControlModel.MultiSelection Then vValues = Array()
+ For i = 0 To UBound(vSelection)
+ lIndex = vSelection(i)
+ If lIndex &gt;= 0 And lIndex &lt;= UBound(vList) Then
+ If Not _ControlModel.MultiSelection Then
+ vValues = vList(lIndex)
+ Exit For
+ End If
+ vValues = ScriptForge.SF_Array.Append(vValues, vList(lIndex))
+ End If
+ Next i
+ vGet = vValues
+ Else
+ vGet = &quot;&quot;
+ End If
+ Case CTLRADIOBUTTON &apos;Boolean
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then vGet = ( _ControlModel.State = 1 ) Else vGet = False
+ Case CTLSCROLLBAR &apos;Numeric
+ vGet = 0
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValue&quot;) Then
+ If Not IsEmpty(_ControlModel.ScrollValue) Then vGet = _ControlModel.ScrollValue
+ End If
+ Case CTLSPINBUTTON
+ If oSession.HasUnoProperty(_ControlModel, &quot;SpinValue&quot;) Then vGet = _ControlModel.SpinValue Else vGet = 0
+ Case CTLTIMEFIELD
+ vGet = CDate(0)
+ If oSession.HasUnoProperty(_ControlModel, &quot;Time&quot;) Then
+ If VarType(_ControlModel.Time) = ScriptForge.V_OBJECT Then &apos; com.sun.star.Util.Time
+ With _ControlModel.Time
+ vDate = TimeSerial(.Hours, .Minutes, .Seconds)
+ End With
+ vGet = vDate
+ Else &apos; .Time = Empty
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ _PropertyGet = vGet
+ Case UCase(&quot;Visible&quot;)
+ If oSession.HasUnoMethod(_ControlView, &quot;isVisible&quot;) Then _PropertyGet = CBool(_ControlView.isVisible())
+ Case UCase(&quot;XControlModel&quot;)
+ Set _PropertyGet = _ControlModel
+ Case UCase(&quot;XControlView&quot;)
+ Set _PropertyGet = _ControlView
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchType:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_FormControl._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(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
+
+Dim bSet As Boolean &apos; Return value
+Static oSession As Object &apos; Alias of SF_Session
+Dim sFormName As String &apos; Full form identification for error messages
+Dim vSet As Variant &apos; Value to set in UNO model or view property
+Dim vActions As Variant &apos; Action property: list of available actions
+Dim sAction As String &apos; A single action
+Dim vFormats As Variant &apos; Format property: output of _FormatsList()
+Dim iFormat As Integer &apos; Format property: index in vFormats
+Dim vSelection As Variant &apos; Alias of Model.SelectedItems
+Dim vList As Variant &apos; Alias of Model.StringItemList
+Dim lIndex As Long &apos; Index in StringItemList
+Dim sItem As String &apos; A single item
+Dim oDatabase As Object &apos; The database object related to the parent form of the control instance
+Dim i As Long
+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.FormControl.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _ParentForm._IsStillAlive() Then GoTo Finally
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;Action&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ vActions = Array(&quot;none&quot;, &quot;submitForm&quot;, &quot;resetForm&quot;, &quot;refreshForm&quot;, &quot;moveToFirst&quot;, &quot;moveToLast&quot;, &quot;moveToNext&quot;, &quot;moveToPrev&quot; _
+ , &quot;saveRecord&quot;, &quot;moveToNew&quot;, &quot;deleteRecord&quot;, &quot;undoRecord&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Action&quot;, ScriptForge.V_STRING, vActions) Then GoTo Finally
+ If oSession.HasUNOProperty(_ControlModel, &quot;ButtonType&quot;) Then
+ sAction = vActions(ScriptForge.SF_Array.IndexOf(vActions, pvValue, CaseSensitive := False))
+ _ControlModel.TargetURL = &quot;&quot;
+ Select Case sAction
+ Case &quot;none&quot; : vSet = com.sun.star.form.FormButtonType.PUSH
+ Case &quot;submitForm&quot; : vSet = com.sun.star.form.FormButtonType.SUBMIT
+ Case &quot;resetForm&quot; : vSet = com.sun.star.form.FormButtonType.RESET
+ Case Else
+ vSet = com.sun.star.form.FormButtonType.URL
+ _ControlModel.TargetURL = &quot;.uno:FormController/&quot; &amp; sAction
+ End Select
+ _ControlModel.ButtonType = vSet
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Caption&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLCHECKBOX, CTLFIXEDTEXT, CTLGROUPBOX, CTLRADIOBUTTON
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Caption&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUNOProperty(_ControlModel, &quot;Label&quot;) Then _ControlModel.Label = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Default&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Default&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUNOProperty(_ControlModel, &quot;DefaultButton&quot;) Then _ControlModel.DefaultButton = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Enabled&quot;)
+ Select Case _ControlType
+ Case CTLHIDDENCONTROL : GoTo CatchType
+ Case Else
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Enabled&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Enabled&quot;) Then _ControlModel.Enabled = pvValue
+ End Select
+ Case UCase(&quot;Format&quot;)
+ Select Case _ControlType
+ Case CTLDATEFIELD, CTLTIMEFIELD
+ vFormats = _FormatsList()
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Format&quot;, V_STRING, vFormats) Then GoTo Finally
+ iFormat = ScriptForge.SF_Array.IndexOf(vFormats, pvValue, CaseSensitive := False)
+ If oSession.HasUNOProperty(_ControlModel, &quot;DateFormat&quot;) Then
+ _ControlModel.DateFormat = iFormat
+ ElseIf oSession.HasUNOProperty(_ControlModel, &quot;TimeFormat&quot;) Then
+ _ControlModel.TimeFormat = iFormat
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListIndex&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;ListIndex&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ Select Case _ControlType
+ Case CTLCOMBOBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;Text&quot;) And oSession.HasUNOProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ If pvValue &gt;= 0 And pvValue &lt;= UBound(_ControlModel.StringItemList) Then _ControlModel.Text = _ControlModel.StringItemList(CInt(pvValue))
+ End If
+ Case CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;SelectedItems&quot;) Then _ControlModel.SelectedItems = Array(CInt(pvValue))
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListSource&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLLISTBOX
+ If oSession.HasUNOProperty(_ControlModel, &quot;ListSource&quot;) Then
+ If Not ScriptForge.SF_Utils._Validate(pvValue, psProperty, V_STRING) Then Goto Finally
+ With com.sun.star.form.ListSourceType
+ Select Case _ControlModel.ListSourceType
+ Case .QUERY _
+ , .TABLE _
+ , .TABLEFIELDS
+ Set oDatabase = _ParentForm.GetDatabase()
+ If _ControlModel.ListSourceType = .QUERY Then vList = oDatabase.Queries Else vList = oDatabase.Tables
+ If Not ScriptForge.SF_Utils._Validate(pvValue, psProperty, V_STRING, vList) Then Goto Finally
+ If _ControlType = CTLCOMBOBOX Then _ControlModel.ListSource = pvValue Else _ControlModel.ListSource = Array(pvValue)
+ _ControlModel.refresh()
+ Case .SQL
+ Set oDatabase = _ParentForm.GetDatabase()
+ If _ControlType = CTLCOMBOBOX Then _ControlModel.ListSource = oDatabase._ReplaceSquareBrackets(pvValue) Else _ControlModel.ListSource = Array(oDatabase._ReplaceSquareBrackets(pvValue))
+ _ControlModel.refresh()
+ Case .VALUELIST &apos; ListBox only !
+ _ControlModel.ListSource = Split(pvValue, &quot;;&quot;)
+ _ControlModel.StringItemList = _ControlModel.ListSource
+ Case .SQLPASSTHROUGH
+ If _ControlType = CTLCOMBOBOX Then _ControlModel.ListSource = pvValue Else _ControlModel.ListSource = Array(pvValue)
+ _ControlModel.refresh()
+ End Select
+ End With
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;ListSourceType&quot;)
+ With com.sun.star.form.ListSourceType
+ Select Case _ControlType
+ Case CTLCOMBOBOX
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;ListSourceType&quot;, ScriptForge.V_NUMERIC, Array( _
+ .TABLE _
+ , .QUERY _
+ , .SQL _
+ , .SQLPASSTHROUGH _
+ , .TABLEFIELDS _
+ )) Then GoTo Finally
+ Case CTLLISTBOX
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;ListSourceType&quot;, ScriptForge.V_NUMERIC, Array( _
+ .VALUELIST _
+ , .TABLE _
+ , .QUERY _
+ , .SQL _
+ , .SQLPASSTHROUGH _
+ , .TABLEFIELDS _
+ )) Then GoTo Finally
+ Case Else : GoTo CatchType
+ End Select
+ End With
+ If oSession.HasUnoProperty(_ControlModel, &quot;ListSourceType&quot;) Then _ControlModel.ListSourceType = pvValue
+ Case UCase(&quot;Locked&quot;)
+ Select Case _ControlType
+ Case CTLCOMBOBOX, CTLCURRENCYFIELD, CTLDATEFIELD, CTLFILECONTROL, CTLFORMATTEDFIELD, CTLIMAGECONTROL _
+ , CTLLISTBOX, CTLNUMERICFIELD, CTLPATTERNFIELD, CTLTEXTFIELD, CTLTIMEFIELD
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Locked&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ReadOnly&quot;) Then _ControlModel.ReadOnly = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;MultiSelect&quot;)
+ Select Case _ControlType
+ Case CTLLISTBOX
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;MultiSelect&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;MultiSelection&quot;) Then _ControlModel.MultiSelection = pvValue
+ If oSession.HasUnoProperty(_ControlModel, &quot;MultiSelectionSimpleMode&quot;) Then _ControlModel.MultiSelectionSimpleMode = pvValue
+ If oSession.HasUnoProperty(_ControlModel, &quot;SelectedItems&quot;) Then
+ &apos; Cancel selections when MultiSelect becomes False
+ If Not pvValue And UBound(_ControlModel.SelectedItems) &gt; 0 Then
+ lIndex = _ControlModel.SelectedItems(0)
+ _ControlModel.SelectedItems = Array(lIndex)
+ End If
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;OnActionPerformed&quot;), UCase(&quot;OnAdjustmentValueChanged&quot;), UCase(&quot;OnApproveAction&quot;), UCase(&quot;OnApproveReset&quot;), UCase(&quot;OnApproveUpdate&quot;) _
+ , UCase(&quot;OnChanged&quot;), UCase(&quot;OnErrorOccurred&quot;), UCase(&quot;OnFocusGained&quot;), UCase(&quot;OnFocusLost&quot;) _
+ , UCase(&quot;OnItemStateChanged&quot;), UCase(&quot;OnKeyPressed&quot;), UCase(&quot;OnKeyReleased&quot;) _
+ , UCase(&quot;OnMouseDragged&quot;), UCase(&quot;OnMouseEntered&quot;), UCase(&quot;OnMouseExited&quot;), UCase(&quot;OnMouseMoved&quot;) _
+ , UCase(&quot;OnMousePressed&quot;), UCase(&quot;OnMouseReleased&quot;), UCase(&quot;OnResetted&quot;) _
+ , UCase(&quot;OnTextChanged&quot;), UCase(&quot;OnUpdated&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, psProperty, V_STRING) Then Goto Finally
+ If Not IsNull(_ControlModel) Then
+ bSet = SF_Register._RegisterEventScript(_ControlModel _
+ , psProperty _
+ , _GetListener(psProperty) _
+ , pvValue _
+ , _Name _
+ )
+ End If
+ Case UCase(&quot;Picture&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON, CTLIMAGEBUTTON, CTLIMAGECONTROL
+ If Not ScriptForge.SF_Utils._ValidateFile(pvValue, &quot;Picture&quot;) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ImageURL&quot;) Then _ControlModel.ImageURL = ScriptForge.SF_FileSystem._ConvertToUrl(pvValue)
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;TipText&quot;)
+ Select Case _ControlType
+ Case CTLHIDDENCONTROL : GoTo CatchType
+ Case Else
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;TipText&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;HelpText&quot;) Then _ControlModel.HelpText = pvValue
+ End Select
+ Case UCase(&quot;TripleState&quot;)
+ Select Case _ControlType
+ Case CTLCHECKBOX
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;TripleState&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;TriState&quot;) Then _ControlModel.TriState = pvValue
+ Case Else : GoTo CatchType
+ End Select
+ Case UCase(&quot;Value&quot;)
+ Select Case _ControlType
+ Case CTLBUTTON &apos;Boolean, toggle buttons only
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Toggle&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then
+ _ControlModel.State = Iif(pvValue, 1, 0)
+ End If
+ Case CTLCHECKBOX &apos;0 = Not checked, 1 = Checked, 2 = Don&apos;t know
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, Array(ScriptForge.V_BOOLEAN, ScriptForge.V_NUMERIC), Array(0, 1, 2, True, False)) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then
+ If VarType(pvValue) = ScriptForge.V_BOOLEAN Then pvValue = Iif(pvValue, 1, 0)
+ _ControlModel.State = pvValue
+ End If
+ Case CTLCOMBOBOX
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) Then
+ If pvValue &lt;&gt; &quot;&quot; Then
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING, _ControlModel.StringItemList) Then Goto Finally
+ End If
+ _ControlModel.Text = pvValue
+ End If
+ Case CTLCURRENCYFIELD, CTLNUMERICFIELD &apos;Numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Value&quot;) Then _ControlModel.Value = pvValue
+ Case CTLDATEFIELD &apos;Date
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_DATE) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Date&quot;) Then
+ Set vSet = New com.sun.star.util.Date
+ vSet.Year = Year(pvValue)
+ vSet.Month = Month(pvValue)
+ vSet.Day = Day(pvValue)
+ _ControlModel.Date = vSet
+ End If
+ Case CTLFILECONTROL
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then _ControlModel.Text = ScriptForge.SF_FileSystem._ConvertToUrl(pvValue)
+ Case CTLFORMATTEDFIELD &apos;String or numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;EffectiveValue&quot;) Then _ControlModel.EffectiveValue = pvValue
+ Case CTLHIDDENCONTROL &apos;String
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;HiddenValue&quot;) Then _ControlModel.HiddenValue = pvValue
+ Case CTLLISTBOX &apos;String or number - Only a single value may be set
+ &apos; StringItemList is the list of the items displayed in the box
+ &apos; ValueItemList is the list of the values in the underlying database field
+ &apos; SelectedItems is the list of the indexes in StringItemList of the selected items
+ If oSession.HasUnoProperty(_ControlModel, &quot;StringItemList&quot;) And oSession.HasUnoProperty(_ControlModel, &quot;SelectedItems&quot;) Then
+ &apos; Setting the value on a listbox is allowed only if single value and value in the list
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ &apos; The list of allowed values depends on the existence of a bound column
+ If _ListboxBound() Then vList = _ControlModel.ValueItemList Else vList = _ControlModel.StringItemList
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, , vList) Then GoTo Finally
+ _ControlModel.SelectedItems = Array(ScriptForge.SF_Array.IndexOf(vList, pvValue, CaseSensitive := True))
+ End If
+ Case CTLPATTERNFIELD, CTLTEXTFIELD &apos;String
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Text&quot;) Then _ControlModel.Text = pvValue
+ Case CTLRADIOBUTTON &apos;Boolean
+ &apos; A group of radio buttons is presumed sharing the same GroupName
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;State&quot;) Then _ControlModel.State = Iif(pvValue, 1, 0)
+ Case CTLSCROLLBAR &apos;Numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValueMin&quot;) Then
+ If pvValue &lt; _ControlModel.ScrollValueMin Then pvValue = _ControlModel.ScrollValueMin
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValueMax&quot;) Then
+ If pvValue &gt; _ControlModel.ScrollValueMax Then pvValue = _ControlModel.ScrollValueMax
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;ScrollValue&quot;) Then _ControlModel.ScrollValue = pvValue
+ Case CTLSPINBUTTON &apos;Numeric
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;SpinValueMin&quot;) Then
+ If pvValue &lt; _ControlModel.SpinValueMin Then pvValue = _ControlModel.SpinValueMin
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;SpinValueMax&quot;) Then
+ If pvValue &gt; _ControlModel.SpinValueMax Then pvValue = _ControlModel.SpinValueMax
+ End If
+ If oSession.HasUnoProperty(_ControlModel, &quot;SpinValue&quot;) Then _ControlModel.SpinValue = pvValue
+ Case CTLTIMEFIELD
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_DATE) Then GoTo Finally
+ If oSession.HasUnoProperty(_ControlModel, &quot;Time&quot;) Then
+ Set vSet = New com.sun.star.util.Time
+ vSet.Hours = Hour(pvValue)
+ vSet.Minutes = Minute(pvValue)
+ vSet.Seconds = Second(pvValue)
+ _ControlModel.Time = vSet
+ End If
+ Case Else : GoTo CatchType
+ End Select
+ &apos; FINAL COMMITMENT
+ If oSession.HasUNOMethod(_ControlModel, &quot;commit&quot;) Then _ControlModel.commit() &apos; f.i. checkboxes have no commit method ??
+ Case UCase(&quot;Visible&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Visible&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If oSession.HasUnoMethod(_ControlView, &quot;setVisible&quot;) Then
+ If pvValue Then _ControlModel.EnableVisible = True
+ _ControlView.setVisible(pvValue)
+ End If
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bSet = False
+ GoTo Finally
+CatchType:
+ If Len(_ParentForm._FormDocumentName) &gt; 0 Then sFormName = _ParentForm._FormDocumentName &amp; &quot;.&quot; Else sFormName = &quot;&quot;
+ ScriptForge.SF_Exception.RaiseFatal(FORMCONTROLTYPEERROR, _Name, sFormName &amp; _FormName, _ControlType, psProperty)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_FormControl._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[FORMCONTROL]: Name, Type (formname)
+ _Repr = &quot;[FORMCONTROL]: &quot; &amp; _Name &amp; &quot;, &quot; &amp; _ControlType &amp; &quot; (&quot; &amp; _FormName &amp; &quot;)&quot;
+
+End Function &apos; SFDocuments.SF_FormControl._Repr
+
+REM ============================================ END OF SFDOCUMENTS.SF_FORMCONTROL
+</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 000000000..5baf37afb
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Register.xba
@@ -0,0 +1,546 @@
+<?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 ================================================================= DEFINITIONS
+
+&apos;&apos;&apos; Strategy for management of Form and FormControl events:
+&apos;&apos;&apos; ------------------------------------------------------
+&apos;&apos;&apos; At the contrary of Dialogs and DialogControls, which are always started from some code,
+&apos;&apos;&apos; Forms and FormControls will be initiated most often by the user, even if the SFDocuments library
+&apos;&apos;&apos; allows to start forms programmatically
+&apos;&apos;&apos;
+&apos;&apos;&apos; For Forms started programmatically, the corresponding objects are built top-down
+&apos;&apos;&apos; Event management of forms and their controls requires to being able to rebuild Form
+&apos;&apos;&apos; and FormControl objects bottom-up
+&apos;&apos;&apos;
+&apos;&apos;&apos; To avoid multiple rebuilds requested by multiple events,
+&apos;&apos;&apos; 1. The active form objects are cached in a global array of _FormCache types
+&apos;&apos;&apos; 2. FormControl objects are cached in Form objects
+&apos;&apos;&apos; 3. The bottom-up rebuild is executed only once, at instance creation
+
+Type _FormCache
+ Terminated As Boolean
+ XUnoForm As Object
+ BasicForm As Object
+End Type
+
+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;Base&quot;, &quot;SFDocuments.SF_Register._NewDocument&quot;) &apos; Same reference, distinction is made inside the function
+ .RegisterService(&quot;Calc&quot;, &quot;SFDocuments.SF_Register._NewDocument&quot;) &apos; Same reference, distinction is made inside the function
+ .RegisterService(&quot;Writer&quot;, &quot;SFDocuments.SF_Register._NewDocument&quot;) &apos; Same reference, distinction is made inside the function
+ .RegisterEventManager(&quot;DocumentEvent&quot;, &quot;SFDocuments.SF_Register._EventManager&quot;) &apos; Reference to the events manager
+ .RegisterEventManager(&quot;FormEvent&quot;, &quot;SFDocuments.SF_Register._FormEventManager&quot;)&apos; Reference to the form and controls events manager
+ End With
+
+End Sub &apos; SFDocuments.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _AddFormToCache(ByRef pvUnoForm As Object _
+ , ByRef pvBasicForm As Object _
+ ) As Long
+&apos;&apos;&apos; Add a new entry in the cache array with the references of the actual Form
+&apos;&apos;&apos; If relevant, the last entry of the cache is reused.
+&apos;&apos;&apos; The cache is located in the global _SF_ variable
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvUnoForm: com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
+&apos;&apos;&apos; pvBasicForm: its corresponding Basic object
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The index of the new or modified entry
+
+Dim vCache As New _FormCache &apos; Entry to be added
+Dim lIndex As Long &apos; UBound of _SF_.SFForms
+Dim vCacheArray As Variant &apos; Alias of _SF_.SFForms
+
+Try:
+ vCacheArray = _SF_.SFForms
+
+ If IsEmpty(vCacheArray) Then vCacheArray = Array()
+ lIndex = UBound(vCacheArray)
+ If lIndex &lt; LBound(vCacheArray) Then
+ ReDim vCacheArray(0 To 0)
+ lIndex = 0
+ ElseIf Not vCacheArray(lIndex).Terminated Then &apos; Often last entry can be reused
+ lIndex = lIndex + 1
+ ReDim Preserve vCacheArray(0 To lIndex)
+ End If
+
+ With vCache
+ .Terminated = False
+ Set .XUnoForm = pvUnoForm
+ Set .BasicForm = pvBasicForm
+ End With
+ Set vCacheArray(lIndex) = vCache
+
+ _SF_.SFForms = vCacheArray
+
+Finally:
+ _AddFormToCache = lIndex
+ Exit Function
+End Function &apos; SFDocuments.SF_Register._AddFormToCache
+
+REM -----------------------------------------------------------------------------
+Private Sub _CleanCacheEntry(ByVal plIndex As Long)
+&apos;&apos;&apos; Clean the plIndex-th entry in the Forms cache
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; plIndex: must fit within the actual boundaries of the cache, otherwise the request is ignored
+
+Dim vCache As New _FormCache &apos; Cleaned entry
+
+ With _SF_
+ If Not IsArray(.SFForms) Then Exit Sub
+ If plIndex &lt; LBound(.SFForms) Or plIndex &gt; UBound(.SFForms) Then Exit Sub
+
+ With vCache
+ .Terminated = True
+ Set .XUnoForm = Nothing
+ Set .BasicForm = Nothing
+ End With
+ .SFForms(plIndex) = vCache
+ End With
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDocuments.SF_Register._CleanCacheEntry
+
+REM -----------------------------------------------------------------------------
+Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
+&apos;&apos;&apos; Returns a Document, Calc or Base 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
+ Set oSource = SF_Register._NewDocument(vEvent.Source)
+ End If
+
+Finally:
+ Set _EventManager = oSource
+ Exit Function
+End Function &apos; SFDocuments.SF_Register._EventManager
+
+REM -----------------------------------------------------------------------------
+Private Function _FindFormInCache(ByRef poForm As Object) As Object
+&apos;&apos;&apos; Find the Form based on its XUnoForm
+&apos;&apos;&apos; The Form must not be terminated
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The corresponding Basic Form part or Nothing
+
+Dim oBasicForm As Object &apos; Return value
+Dim oCache As _FormCache &apos; Entry in the cache
+
+ Set oBasicForm = Nothing
+
+Try:
+ With _SF_
+ If Not IsEmpty(.SFForms) Then
+ For Each oCache In .SFForms
+ If EqualUnoObjects(poForm, oCache.XUnoForm) And Not oCache.Terminated Then
+ Set oBasicForm = oCache.BasicForm
+ Exit For
+ End If
+ Next oCache
+ End If
+ End With
+
+Finally:
+ Set _FindFormInCache = oBasicForm
+ Exit Function
+End Function &apos; SFDocuments.SF_Register._FindFormInCache
+
+REM -----------------------------------------------------------------------------
+Public Function _FormEventManager(Optional ByRef pvArgs As Variant) As Object
+&apos;&apos;&apos; Returns a Form or FormControl object corresponding with the form or control
+&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.lang.EventObject
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the output of a Form, FormControl service or Nothing
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Sub TriggeredByEvent(ByRef poEvent As Object)
+&apos;&apos;&apos; Dim oForm As Object
+&apos;&apos;&apos; Set oForm = CreateScriptService(&quot;SFDocuments.FormEvent&quot;, poEvent)
+&apos;&apos;&apos; If Not IsNull(oForm) Then
+&apos;&apos;&apos; &apos; ... (a valid form or subform has been identified)
+&apos;&apos;&apos; End Sub
+
+Dim oSource As Object &apos; Return value
+Dim vEvent As Variant &apos; Alias of pvArgs(0)
+Dim oControlModel As Object &apos; com.sun.star.awt.XControlModel
+Dim oParent As Object &apos; com.sun.star.form.OGridControlModel or com.sun.star.comp.forms.ODatabaseForm
+Dim sParentType As String &apos; &quot;com.sun.star.form.OGridControlModel&quot; or &quot;com.sun.star.comp.forms.ODatabaseForm&quot;
+Dim oSFParent As Object &apos; The parent as a ScriptForge instance: SF_Form or SF_FormControl
+Dim oSFForm As Object &apos; The grand-parent SF_Form instance
+Dim oSession As Object : Set oSession = ScriptForge.SF_Session
+
+ &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 oSession.HasUnoProperty(vEvent, &quot;Source&quot;) Then
+
+ &apos; FORM EVENT
+ If oSession.UnoObjectType(vEvent.Source) = &quot;com.sun.star.comp.forms.ODatabaseForm&quot; Then
+ Set oSource = SF_Register._NewForm(vEvent.Source, pbForceInit := True)
+
+ &apos; CONTROL EVENT
+ Else
+ &apos; A SF_FormControl instance is always created from its parent, either a form, a subform or a table control
+ Set oControlModel = vEvent.Source.Model &apos; The event source is a control view com.sun.star.awt.XControl
+ Set oParent = oControlModel.Parent
+ sParentType = oSession.UnoObjectType(oParent)
+ Select Case sParentType
+ Case &quot;com.sun.star.form.OGridControlModel&quot;
+ Set oSFForm = SF_Register._NewForm(oParent.Parent, pbForceInit := True)
+ Set oSFParent = oSFForm.Controls(oParent.Name)
+ Case &quot;com.sun.star.comp.forms.ODatabaseForm&quot;
+ Set oSFParent = SF_Register._NewForm(oParent, pbForceInit := True)
+ End Select
+ &apos; The final instance is derived from its parent instance
+ Set oSource = oSFParent.Controls(oControlModel.Name)
+
+ End If
+
+ End If
+
+Finally:
+ Set _FormEventManager = oSource
+ Exit Function
+End Function &apos; SFDocuments.SF_Register._FormEventManager
+
+REM -----------------------------------------------------------------------------
+Public Function _GetEventScriptCode(poObject As Object _
+ , ByVal psEvent As String _
+ , ByVal psName As String _
+ ) As String
+&apos;&apos;&apos; Extract from the parent of poObject the Basic script linked to psEvent.
+&apos;&apos;&apos; Helper function common to forms and form controls
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poObject: a com.sun.star.form.XForm or XControl object
+&apos;&apos;&apos; psEvent: the &quot;On...&quot; name of the event
+&apos;&apos;&apos; psName: the name of the object to be identified from the parent object
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The script to trigger when psEvent occurs
+&apos;&apos;&apos; See Scripting Framework URI Specification : https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+
+Dim vEvents As Variant &apos; List of available events in the parent object
+ &apos; Array of com.sun.star.script.ScriptEventDescriptor
+Dim sEvent As String &apos; The targeted event name
+Dim oParent As Object &apos; The parent object
+Dim lIndex As Long &apos; The index of the targeted event in the events list of the parent object
+Dim sName As String &apos; The corrected UNO event name
+Dim i As Long
+
+ _GetEventScriptCode = &quot;&quot;
+ On Local Error GoTo Catch
+ If Not ScriptForge.SF_Session.HasUnoMethod(poObject, &quot;getParent&quot;) Then GoTo Finally
+
+Try:
+ &apos; Find form index i.e. find control via getByIndex()
+ &apos; The name is known (= psName) but getByIndex() is not in the same sequence as getElementNames()
+ Set oParent = poObject.getParent()
+ lIndex = -1
+ For i = 0 To oParent.getCount() - 1
+ sName = oParent.getByIndex(i).Name
+ If (sName = psName) Then
+ lIndex = i
+ Exit For
+ End If
+ Next i
+ If lIndex &lt; 0 Then GoTo Finally &apos; Not found, should not happen
+
+ &apos; Find script triggered by event
+ vEvents = oParent.getScriptEvents(lIndex) &apos; Returns an array
+ &apos; Fix historical typo error
+ sEvent = Replace(LCase(Mid(psEvent, 3, 1)) &amp; Mid(psEvent, 4), &quot;errorOccurred&quot;, &quot;errorOccured&quot;)
+ For i = 0 To UBound(vEvents)
+ If vEvents(i).EventMethod = sEvent Then
+ _GetEventScriptCode = vEvents(i).ScriptCode
+ Exit For
+ End If
+ Next i
+
+Finally:
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Register._GetEventScriptCode
+
+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_Services.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
+ Set oSuperDocument.[_SubClass] = oDocument
+ 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
+ Set oSuperDocument.[_SubClass] = oDocument
+ Case &quot;Writer&quot;
+ Set oDocument = New SF_Writer
+ Set oSuperDocument = New SF_Document
+ Set oDocument.[_Super] = oSuperDocument &apos; Now both super and subclass are twinned
+ Set oSuperDocument.[_SubClass] = oDocument
+ 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 -----------------------------------------------------------------------------
+Public Function _NewForm(ByRef poForm As Object _
+ , Optional pbForceInit As Boolean _
+ ) As Object
+&apos;&apos;&apos; Returns an existing or a new SF_Form instance based on the argument
+&apos;&apos;&apos; If the instance is new (not found in cache), the minimal members are initialized
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poForm: com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
+&apos;&apos;&apos; pbForceInit: when True, initialize the form instance. Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SF_Form instance
+
+Dim oForm As Object &apos; Return value
+
+Try:
+ Set oForm = SF_Register._FindFormInCache(poForm)
+ If IsNull(oForm) Then &apos; Not found
+ If IsMissing(pbForceInit) Or IsEmpty(pbForceInit) Then pbForceInit = False
+ Set oForm = New SF_Form
+ With oForm
+ ._Name = poForm.Name
+ Set .[Me] = oForm
+ Set ._Form = poForm
+ If pbForceInit Then ._Initialize()
+ End With
+ End If
+
+Finally:
+ Set _NewForm = oForm
+ Exit Function
+End Function &apos; SFDocuments.SF_Register._NewForm
+
+REM -----------------------------------------------------------------------------
+Public Function _RegisterEventScript(poObject As Object _
+ , ByVal psEvent As String _
+ , ByVal psListener As String _
+ , ByVal psScriptCode As String _
+ , ByVal psName As String _
+ ) As Boolean
+&apos;&apos;&apos; Register a script event (psEvent) to poObject (Form, SubForm or Control)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poObject: a com.sun.star.form.XForm or XControl object
+&apos;&apos;&apos; psEvent: the &quot;On...&quot; name of the event
+&apos;&apos;&apos; psListener: the listener name corresponding with the event
+&apos;&apos;&apos; psScriptCode: The script to trigger when psEvent occurs
+&apos;&apos;&apos; See Scripting Framework URI Specification : https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; psName: the name of the object to associate with the event
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+
+Dim oEvent As Object &apos; com.sun.star.script.ScriptEventDescriptor
+Dim sEvent As String &apos; The targeted event name
+Dim oParent As Object &apos; The parent object
+Dim lIndex As Long &apos; The index of the targeted event in the events list of the parent object
+Dim sName As String &apos; The corrected UNO event name
+Dim i As Long
+
+ _RegisterEventScript = False
+ On Local Error GoTo Catch
+ If Not ScriptForge.SF_Session.HasUnoMethod(poObject, &quot;getParent&quot;) Then GoTo Finally
+
+Try:
+ &apos; Find object&apos;s internal index i.e. how to reach it via getByIndex()
+ Set oParent = poObject.getParent()
+ lIndex = -1
+ For i = 0 To oParent.getCount() - 1
+ sName = oParent.getByIndex(i).Name
+ If (sName = psName) Then
+ lIndex = i
+ Exit For
+ End If
+ Next i
+ If lIndex &lt; 0 Then GoTo Finally &apos; Not found, should not happen
+
+ &apos; Fix historical typo error
+ sEvent = Replace(LCase(Mid(psEvent, 3, 1)) &amp; Mid(psEvent, 4), &quot;errorOccurred&quot;, &quot;errorOccured&quot;)
+ &apos; Apply new script code. Erasing it is done with a specific UNO method
+ If psScriptCode = &quot;&quot; Then
+ oParent.revokeScriptEvent(lIndex, psListener, sEvent, &quot;&quot;)
+ Else
+ Set oEvent = CreateUnoStruct(&quot;com.sun.star.script.ScriptEventDescriptor&quot;)
+ With oEvent
+ .ListenerType = psListener
+ .EventMethod = sEvent
+ .ScriptType = &quot;Script&quot; &apos; Better than &quot;Basic&quot;
+ .ScriptCode = psScriptCode
+ End With
+ oParent.registerScriptEvent(lIndex, oEvent)
+ End If
+ _RegisterEventScript = True
+
+Finally:
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Register._RegisterEventScript
+
+REM ============================================== END OF SFDOCUMENTS.SF_REGISTER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Writer.xba b/wizards/source/sfdocuments/SF_Writer.xba
new file mode 100644
index 000000000..eded35de9
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Writer.xba
@@ -0,0 +1,635 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Writer" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDocuments library is one of the associated libraries. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos; SF_Writer
+&apos;&apos;&apos; =========
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SFDocuments library gathers a number of methods and properties making easy
+&apos;&apos;&apos; managing and manipulating LibreOffice documents
+&apos;&apos;&apos;
+&apos;&apos;&apos; Some methods are generic for all types of documents: they are combined in the SF_Document module.
+&apos;&apos;&apos; Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Writer, SF_Base, ...
+&apos;&apos;&apos;
+&apos;&apos;&apos; To workaround the absence of class inheritance in LibreOffice Basic, some redundancy is necessary
+&apos;&apos;&apos; Each subclass MUST implement also the generic methods and properties, even if they only call
+&apos;&apos;&apos; the parent methods and properties.
+&apos;&apos;&apos; They should also duplicate some generic private members as a subset of their own set of members
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SF_Writer module is focused on :
+&apos;&apos;&apos; TBD
+&apos;&apos;&apos;
+&apos;&apos;&apos; The current module is closely related to the &quot;UI&quot; service of the ScriptForge library
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation examples:
+&apos;&apos;&apos; 1) From the UI service
+&apos;&apos;&apos; Dim ui As Object, oDoc As Object
+&apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
+&apos;&apos;&apos; Set oDoc = ui.CreateDocument(&quot;Writer&quot;, ...)
+&apos;&apos;&apos; &apos; or Set oDoc = ui.OpenDocument(&quot;C:\Me\MyFile.odt&quot;)
+&apos;&apos;&apos; 2) Directly if the document is already opened
+&apos;&apos;&apos; Dim oDoc As Object
+&apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.Writer&quot;, &quot;Untitled 1&quot;) &apos; Default = ActiveWindow
+&apos;&apos;&apos; &apos; or Set oDoc = CreateScriptService(&quot;SFDocuments.Writer&quot;, &quot;Untitled 1&quot;) &apos; Untitled 1 is presumed a Writer document
+&apos;&apos;&apos; &apos; The substring &quot;SFDocuments.&quot; in the service name is optional
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; TBD
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/SF_Writer.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const WRITERFORMNOTFOUNDERROR = &quot;WRITERFORMNOTFOUNDERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private [_Super] As Object &apos; Document superclass, which the current instance is a subclass of
+Private ObjectType As String &apos; Must be WRITER
+Private ServiceName As String
+
+&apos; Window component
+Private _Component As Object &apos; com.sun.star.lang.XComponent
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ Set [_Super] = Nothing
+ ObjectType = &quot;WRITER&quot;
+ ServiceName = &quot;SFDocuments.Writer&quot;
+ Set _Component = Nothing
+End Sub &apos; SFDocuments.SF_Writer Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_Writer Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ If Not IsNull([_Super]) Then Set [_Super] = [_Super].Dispose()
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDocuments.SF_Writer Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Forms(Optional ByVal Form As Variant) As Variant
+&apos;&apos;&apos; Return either
+&apos;&apos;&apos; - the list of the Forms contained in the form document
+&apos;&apos;&apos; - a SFDocuments.Form object based on its name or its index
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Form: a form stored in the document given by its name or its index
+&apos;&apos;&apos; When absent, the list of available forms is returned
+&apos;&apos;&apos; To get the first (unique ?) form stored in the form document, set Form = 0
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; WRITERFORMNOTFOUNDERROR Form not found
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A zero-based array of strings if Form is absent
+&apos;&apos;&apos; An instance of the SF_Form class if Form exists
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myForm As Object, myList As Variant
+&apos;&apos;&apos; myList = oDoc.Forms()
+&apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;myForm&quot;)
+
+Dim oForm As Object &apos; The new Form class instance
+Dim oMainForm As Object &apos; com.sun.star.comp.sdb.Content
+Dim oXForm As Object &apos; com.sun.star.form.XForm
+Dim vFormNames As Variant &apos; Array of form names
+Dim oForms As Object &apos; Forms collection
+Const cstDrawPage = 0 &apos; Only 1 drawpage in a Writer document
+
+Const cstThisSub = &quot;SFDocuments.Writer.Forms&quot;
+Const cstSubArgs = &quot;[Form=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Form) Or IsEmpty(Form) Then Form = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Start from the document component and go down to forms
+ Set oForms = _Component.DrawPages(cstDrawPage).Forms
+ vFormNames = oForms.getElementNames()
+
+ If Len(Form) = 0 Then &apos; Return the list of valid form names
+ Forms = vFormNames
+ Else
+ If VarType(Form) = V_STRING Then &apos; Find the form by name
+ If Not ScriptForge.SF_Array.Contains(vFormNames, Form, CaseSensitive := True) Then GoTo CatchNotFound
+ Set oXForm = oForms.getByName(Form)
+ Else &apos; Find the form by index
+ If Form &lt; 0 Or Form &gt;= oForms.Count Then GoTo CatchNotFound
+ Set oXForm = oForms.getByIndex(Form)
+ End If
+ &apos; Create the new Form class instance
+ Set oForm = SF_Register._NewForm(oXForm)
+ With oForm
+ Set .[_Parent] = [Me]
+ ._FormType = ISDOCFORM
+ Set ._Component = _Component
+ ._Initialize()
+ End With
+ Set Forms = oForm
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ ScriptForge.SF_Exception.RaiseFatal(WRITERFORMNOTFOUNDERROR, Form, _FileIdent())
+End Function &apos; SFDocuments.SF_Writer.Forms
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant _
+ , 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.Writer.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)
+ ElseIf Len(ObjectName) = 0 Then
+ GetProperty = _PropertyGet(PropertyName)
+ Else
+ GetProperty = _PropertyGet(PropertyName, ObjectName)
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Writer.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Writer service as an array
+
+ Methods = Array( _
+ &quot;Forms&quot; _
+ , &quot;PrintOut&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Writer.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function PrintOut(Optional ByVal Pages As Variant _
+ , Optional ByVal Copies As Variant _
+ , Optional ByVal PrintBackground As Variant _
+ , Optional ByVal PrintBlankPages As Variant _
+ , Optional ByVal PrintEvenPages As Variant _
+ , Optional ByVal PrintOddPages As Variant _
+ , Optional ByVal PrintImages As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Send the content of the document to the printer.
+&apos;&apos;&apos; The printer might be defined previously by default, by the user or by the SetPrinter() method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
+&apos;&apos;&apos; Copies: the number of copies
+&apos;&apos;&apos; PrintBackground: print the background image when True (default)
+&apos;&apos;&apos; PrintBlankPages: when False (default), omit empty pages
+&apos;&apos;&apos; PrintEvenPages: print the left pages when True (default)
+&apos;&apos;&apos; PrintOddPages: print the right pages when True (default)
+&apos;&apos;&apos; PrintImages: print the graphic objects when True (default)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.PrintOut(&quot;1-4;10;15-18&quot;, Copies := 2, PrintImages := False)
+
+Dim bPrint As Boolean &apos; Return value
+Dim vPrintOptions As Variant &apos; com.sun.star.text.DocumentSettings
+
+Const cstThisSub = &quot;SFDocuments.Writer.PrintOut&quot;
+Const cstSubArgs = &quot;[Pages=&quot;&quot;&quot;&quot;], [Copies=1], [PrintBackground=True], [PrintBlankPages=False], [PrintEvenPages=True]&quot; _
+ &amp; &quot;, [PrintOddPages=True], [PrintImages=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bPrint = False
+
+Check:
+ If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
+ If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
+ If IsMissing(PrintBackground) Or IsEmpty(PrintBackground) Then PrintBackground = True
+ If IsMissing(PrintBlankPages) Or IsEmpty(PrintBlankPages) Then PrintBlankPages = False
+ If IsMissing(PrintEvenPages) Or IsEmpty(PrintEvenPages) Then PrintEvenPages = True
+ If IsMissing(PrintOddPages) Or IsEmpty(PrintOddPages) Then PrintOddPages = True
+ If IsMissing(PrintImages) Or IsEmpty(PrintImages) Then PrintImages = True
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Copies, &quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(PrintBackground, &quot;PrintBackground&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(PrintBlankPages, &quot;PrintBlankPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(PrintEvenPages, &quot;PrintEvenPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(PrintOddPages, &quot;PrintOddPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(PrintImages, &quot;PrintImages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ vPrintOptions = _Component.createInstance(&quot;com.sun.star.text.DocumentSettings&quot;)
+ With vPrintOptions
+ .PrintPageBackground = PrintBackground
+ .PrintEmptyPages = PrintBlankPages
+ .PrintLeftPages = PrintEvenPages
+ .PrintRightPages = PrintOddPages
+ .PrintGraphics = PrintImages
+ .PrintDrawings = PrintImages
+ End With
+
+ bPrint = [_Super].PrintOut(Pages, Copies, _Component)
+
+Finally:
+ PrintOut = bPrint
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Writer.PrintOut
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Writer class as an array
+
+ Properties = Array( _
+ &quot;CustomProperties&quot; _
+ , &quot;Description&quot; _
+ , &quot;DocumentProperties&quot; _
+ , &quot;DocumentType&quot; _
+ , &quot;ExportFilters&quot; _
+ , &quot;ImportFilters&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_Writer.Properties
+
+REM -----------------------------------------------------------------------------
+Private Function SetProperty(Optional ByVal psProperty As String _
+ , Optional ByVal pvValue As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set the new value of the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+&apos;&apos;&apos; pvValue: the new value of the given property
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+
+Dim bSet As Boolean &apos; Return value
+Static oSession As Object &apos; Alias of SF_Session
+Dim cstThisSub As String
+Const cstSubArgs = &quot;Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSet = False
+
+ cstThisSub = &quot;SFDocuments.Writer.set&quot; &amp; psProperty
+ If IsMissing(pvValue) Then pvValue = Empty
+ &apos;ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Validation done in Property Lets
+
+ If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;CustomProperties&quot;)
+ CustomProperties = pvValue
+ Case UCase(&quot;Description&quot;)
+ Description = pvValue
+ Case UCase(&quot;Keywords&quot;)
+ Keywords = pvValue
+ Case UCase(&quot;Subject&quot;)
+ Subject = pvValue
+ Case UCase(&quot;Title&quot;)
+ Title = pvValue
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ SetProperty = bSet
+ &apos;ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Writer.SetProperty
+
+REM ======================================================= SUPERCLASS PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get CustomProperties() As Variant
+ CustomProperties = [_Super].GetProperty(&quot;CustomProperties&quot;)
+End Property &apos; SFDocuments.SF_Writer.CustomProperties
+
+REM -----------------------------------------------------------------------------
+Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
+ [_Super].CustomProperties = pvCustomProperties
+End Property &apos; SFDocuments.SF_Writer.CustomProperties
+
+REM -----------------------------------------------------------------------------
+Property Get Description() As Variant
+ Description = [_Super].GetProperty(&quot;Description&quot;)
+End Property &apos; SFDocuments.SF_Writer.Description
+
+REM -----------------------------------------------------------------------------
+Property Let Description(Optional ByVal pvDescription As Variant)
+ [_Super].Description = pvDescription
+End Property &apos; SFDocuments.SF_Writer.Description
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentProperties() As Variant
+ DocumentProperties = [_Super].GetProperty(&quot;DocumentProperties&quot;)
+End Property &apos; SFDocuments.SF_Writer.DocumentProperties
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentType() As String
+ DocumentType = [_Super].GetProperty(&quot;DocumentType&quot;)
+End Property &apos; SFDocuments.SF_Writer.DocumentType
+
+REM -----------------------------------------------------------------------------
+Property Get ExportFilters() As Variant
+ ExportFilters = [_Super].GetProperty(&quot;ExportFilters&quot;)
+End Property &apos; SFDocuments.SF_Writer.ExportFilters
+
+REM -----------------------------------------------------------------------------
+Property Get ImportFilters() As Variant
+ ImportFilters = [_Super].GetProperty(&quot;ImportFilters&quot;)
+End Property &apos; SFDocuments.SF_Writer.ImportFilters
+
+REM -----------------------------------------------------------------------------
+Property Get IsBase() As Boolean
+ IsBase = [_Super].GetProperty(&quot;IsBase&quot;)
+End Property &apos; SFDocuments.SF_Writer.IsBase
+
+REM -----------------------------------------------------------------------------
+Property Get IsCalc() As Boolean
+ IsCalc = [_Super].GetProperty(&quot;IsCalc&quot;)
+End Property &apos; SFDocuments.SF_Writer.IsCalc
+
+REM -----------------------------------------------------------------------------
+Property Get IsDraw() As Boolean
+ IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
+End Property &apos; SFDocuments.SF_Writer.IsDraw
+
+REM -----------------------------------------------------------------------------
+Property Get IsImpress() As Boolean
+ IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
+End Property &apos; SFDocuments.SF_Writer.IsImpress
+
+REM -----------------------------------------------------------------------------
+Property Get IsMath() As Boolean
+ IsMath = [_Super].GetProperty(&quot;IsMath&quot;)
+End Property &apos; SFDocuments.SF_Writer.IsMath
+
+REM -----------------------------------------------------------------------------
+Property Get IsWriter() As Boolean
+ IsWriter = [_Super].GetProperty(&quot;IsWriter&quot;)
+End Property &apos; SFDocuments.SF_Writer.IsWriter
+
+REM -----------------------------------------------------------------------------
+Property Get Keywords() As Variant
+ Keywords = [_Super].GetProperty(&quot;Keywords&quot;)
+End Property &apos; SFDocuments.SF_Writer.Keywords
+
+REM -----------------------------------------------------------------------------
+Property Let Keywords(Optional ByVal pvKeywords As Variant)
+ [_Super].Keywords = pvKeywords
+End Property &apos; SFDocuments.SF_Writer.Keywords
+
+REM -----------------------------------------------------------------------------
+Property Get Readonly() As Variant
+ Readonly = [_Super].GetProperty(&quot;Readonly&quot;)
+End Property &apos; SFDocuments.SF_Writer.Readonly
+
+REM -----------------------------------------------------------------------------
+Property Get Subject() As Variant
+ Subject = [_Super].GetProperty(&quot;Subject&quot;)
+End Property &apos; SFDocuments.SF_Writer.Subject
+
+REM -----------------------------------------------------------------------------
+Property Let Subject(Optional ByVal pvSubject As Variant)
+ [_Super].Subject = pvSubject
+End Property &apos; SFDocuments.SF_Writer.Subject
+
+REM -----------------------------------------------------------------------------
+Property Get Title() As Variant
+ Title = [_Super].GetProperty(&quot;Title&quot;)
+End Property &apos; SFDocuments.SF_Writer.Title
+
+REM -----------------------------------------------------------------------------
+Property Let Title(Optional ByVal pvTitle As Variant)
+ [_Super].Title = pvTitle
+End Property &apos; SFDocuments.SF_Writer.Title
+
+REM -----------------------------------------------------------------------------
+Property Get XComponent() As Variant
+ XComponent = [_Super].GetProperty(&quot;XComponent&quot;)
+End Property &apos; SFDocuments.SF_Writer.XComponent
+
+REM ========================================================== SUPERCLASS METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate() As Boolean
+ Activate = [_Super].Activate()
+End Function &apos; SFDocuments.SF_Writer.Activate
+
+REM -----------------------------------------------------------------------------
+Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
+ CloseDocument = [_Super].CloseDocument(SaveAsk)
+End Function &apos; SFDocuments.SF_Writer.CloseDocument
+
+REM -----------------------------------------------------------------------------
+Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ ) As Object
+ Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function &apos; SFDocuments.SF_Writer.CreateMenu
+
+REM -----------------------------------------------------------------------------
+Public Function ExportAsPDF(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Pages As Variant _
+ , Optional ByVal Password As Variant _
+ , Optional ByVal Watermark As Variant _
+ ) As Boolean
+ ExportAsPDF = [_Super].ExportAsPDF(FileName, Overwrite, Pages, Password, Watermark)
+End Function &apos; SFDocuments.SF_Writer.ExportAsPDF
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function &apos; SFDocuments.SF_Writer.RemoveMenu
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant _
+ , ParamArray Args As Variant _
+ )
+ [_Super].RunCommand(Command, Args)
+End Sub &apos; SFDocuments.SF_Writer.RunCommand
+
+REM -----------------------------------------------------------------------------
+Public Function Save() As Boolean
+ Save = [_Super].Save()
+End Function &apos; SFDocuments.SF_Writer.Save
+
+REM -----------------------------------------------------------------------------
+Public Function SaveAs(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Password As Variant _
+ , Optional ByVal FilterName As Variant _
+ , Optional ByVal FilterOptions As Variant _
+ ) As Boolean
+ SaveAs = [_Super].SaveAs(FileName, Overwrite, Password, FilterName, FilterOptions)
+End Function &apos; SFDocuments.SF_Writer.SaveAs
+
+REM -----------------------------------------------------------------------------
+Public Function SaveCopyAs(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Password As Variant _
+ , Optional ByVal FilterName As Variant _
+ , Optional ByVal FilterOptions As Variant _
+ ) As Boolean
+ SaveCopyAs = [_Super].SaveCopyAs(FileName, Overwrite, Password, FilterName, FilterOptions)
+End Function &apos; SFDocuments.SF_Writer.SaveCopyAs
+
+REM -----------------------------------------------------------------------------
+Public Function SetPrinter(Optional ByVal Printer As Variant _
+ , Optional ByVal Orientation As Variant _
+ , Optional ByVal PaperFormat As Variant _
+ ) As Boolean
+ SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
+End Function &apos; SFDocuments.SF_Writer.SetPrinter
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _FileIdent() As String
+&apos;&apos;&apos; Returns a file identification from the information that is currently available
+&apos;&apos;&apos; Useful e.g. for display in error messages
+
+ _FileIdent = [_Super]._FileIdent()
+
+End Function &apos; SFDocuments.SF_Writer._FileIdent
+
+REM -----------------------------------------------------------------------------
+Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
+ , Optional ByVal pbError As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if the document has not been closed manually or incidentally since the last use
+&apos;&apos;&apos; If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pbForUpdate: if True (default = False), check additionally if document is open for editing
+&apos;&apos;&apos; pbError: if True (default), raise a fatal error
+
+Dim bAlive As Boolean &apos; Return value
+
+ If IsMissing(pbForUpdate) Then pbForUpdate = False
+ If IsMissing(pbError) Then pbError = True
+
+Try:
+ bAlive = [_Super]._IsStillAlive(pbForUpdate, pbError)
+
+Finally:
+ _IsStillAlive = bAlive
+ Exit Function
+End Function &apos; SFDocuments.SF_Writer._IsStillAlive
+
+REM -----------------------------------------------------------------------------
+Private Function _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 cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ _PropertyGet = False
+
+ cstThisSub = &quot;SFDocuments.Writer.get&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+ Select Case psProperty
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFDocuments.SF_Writer._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_Writer instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[DOCUMENT]: Type/File&quot;
+
+ _Repr = &quot;[Writer]: &quot; &amp; [_Super]._FileIdent()
+
+End Function &apos; SFDocuments.SF_Writer._Repr
+
+REM ============================================ END OF SFDOCUMENTS.SF_WRITER
+</script:module> \ 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 000000000..47cca670f
--- /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-2022 Jean-Pierre LEDURE, Rafael LIMA, 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 000000000..62e84ea5c
--- /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 000000000..ff4495124
--- /dev/null
+++ b/wizards/source/sfdocuments/script.xlb
@@ -0,0 +1,14 @@
+<?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:element library:name="SF_Form"/>
+ <library:element library:name="SF_FormControl"/>
+ <library:element library:name="SF_Writer"/>
+ <library:element library:name="SF_Chart"/>
+ <library:element library:name="SF_DocumentListener"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/sfunittests/SF_Register.xba b/wizards/source/sfunittests/SF_Register.xba
new file mode 100644
index 000000000..360abba50
--- /dev/null
+++ b/wizards/source/sfunittests/SF_Register.xba
@@ -0,0 +1,202 @@
+<?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 SFUnitTests 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
+
+Private Const UNITTESTLIBRARYERROR = &quot;UNITTESTLIBRARYERROR&quot;
+
+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;UnitTest&quot;, &quot;SFUnitTests.SF_Register._NewUnitTest&quot;) &apos; Reference to the function initializing the service
+ End With
+
+End Sub &apos; SFUnitTests.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _NewUnitTest(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the SF_UnitTest class
+&apos; Args:
+&apos;&apos;&apos; Location: if empty, the location of the library is presumed to be in GlobalScope.BasicLibraries
+&apos;&apos;&apos; Alternatives are:
+&apos;&apos;&apos; - the name of a document: see SF_UI.WindowName
+&apos;&apos;&apos; - an explicit SFDocuments.Document instance
+&apos;&apos;&apos; - the component containing the library, typically ThisComponent
+&apos;&apos;&apos; LibraryName: the name of the library containing the test code
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The instance or Nothing
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNITTESTLIBRARYNOTFOUND The library could not be found
+
+Dim oUnitTest As Object &apos; Return value
+Dim vLocation As Variant &apos; Alias of pvArgs(0)
+Dim vLibraryName As Variant &apos; alias of pvArgs(1)
+Dim vLocations As Variant &apos; &quot;user&quot;, &quot;share&quot; or document
+Dim sLocation As String &apos; A single location
+Dim sTargetLocation As String &apos; &quot;user&quot; or the document name
+Dim vLanguages As Variant &apos; &quot;Basic&quot;, &quot;Python&quot;, ... programming languages
+Dim sLanguage As String &apos; A single programming language
+Dim vLibraries As Variant &apos; Library names
+Dim sLibrary As String &apos; A single library
+Dim vModules As Variant &apos; Module names
+Dim sModule As String &apos; A single module
+Dim vModuleNames As Variant &apos; Module names
+Dim oRoot As Object &apos; com.sun.star.script.browse.BrowseNodeFactory
+Dim iLibrary As Integer &apos; The index of the target location in vLibraries
+
+Dim FSO As Object &apos; SF_FileSystem
+Dim i As Integer, j As Integer, k As Integer, l As Integer
+
+Const cstService = &quot;SFUnitTests.UnitTest&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
+ If UBound(pvArgs) &gt;= 0 Then vLocation = pvArgs(0) Else vLocation = &quot;&quot;
+ If IsEmpty(vLocation) Then vLocation = &quot;&quot;
+ If UBound(pvArgs) &gt;= 1 Then vLibraryName = pvArgs(1) Else vLibraryName = &quot;&quot;
+ If IsEmpty(vLibraryName) Then vLibraryName = &quot;&quot;
+ If Not ScriptForge.SF_Utils._Validate(vLocation, &quot;Location&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(vLibraryName, &quot;LibraryName&quot;, V_STRING) Then GoTo Finally
+
+ Set oUnitTest = Nothing
+ Set FSO = CreateScriptService(&quot;ScriptForge.FileSystem&quot;)
+
+ &apos; Determine the library container hosting the test code
+
+ &apos; Browsing starts from root element
+ Set oRoot = SF_Utils._GetUNOService(&quot;BrowseNodeFactory&quot;).createView(com.sun.star.script.browse.BrowseNodeFactoryViewTypes.MACROORGANIZER)
+
+ If Len(vLibraryName) &gt; 0 Then
+
+ &apos; Determine the target location, as a string. The location is either:
+ &apos; - the last component of a document&apos;s file name
+ &apos; - &quot;user&quot; = My Macros &amp; Dialogs
+ If VarType(vLocation) = ScriptForge.V_OBJECT Then
+ sTargetLocation = FSO.GetName(vLocation.URL)
+ ElseIf Len(vLocation) = 0 Then
+ sTargetLocation = &quot;user&quot; &apos; Testing code is presumed NOT in &quot;share&quot;
+ Else
+ sTargetLocation = FSO.GetName(vLocation)
+ End If
+
+ &apos; Exploration is done via tree nodes
+ iLibrary = -1
+ If Not IsNull(oRoot) Then
+ If oRoot.hasChildNodes() Then
+ vLocations = oRoot.getChildNodes()
+ For i = 0 To UBound(vLocations)
+ sLocation = vLocations(i).getName()
+ If sLocation = sTargetLocation Then
+ If vLocations(i).hasChildNodes() Then
+ vLanguages = vLocations(i).getChildNodes()
+ For j = 0 To UBound(vLanguages)
+ sLanguage = vLanguages(j).getName()
+ &apos; Consider Basic libraries only
+ If sLanguage = &quot;Basic&quot; Then
+ If vLanguages(j).hasChildNodes() Then
+ vLibraries = vLanguages(j).getChildNodes()
+ For k = 0 To UBound(vLibraries)
+ sLibrary = vLibraries(k).getName()
+ &apos; Consider the targeted library only
+ If sLibrary = vLibraryName Then
+ iLibrary = k
+ If vLibraries(k).hasChildNodes() Then
+ vModules = vLibraries(k).getChildNodes()
+ vModuleNames = Array()
+ For l = 0 To UBound(vModules)
+ sModule = vModules(l).getName()
+ vModuleNames = ScriptForge.SF_Array.Append(vModuleNames, sModule)
+ Next l
+ End If
+ Exit For
+ End If
+ Next k
+ End If
+ End If
+ If iLibrary &gt;= 0 Then Exit For
+ Next j
+ End If
+ End If
+ If iLibrary &gt;= 0 Then Exit For
+ Next i
+ End If
+ End If
+ If iLibrary &lt; 0 Then GoTo CatchLibrary
+
+ End If
+
+Try:
+ &apos; Create the unittest Basic object and initialize its attributes
+ Set oUnitTest = New SF_UnitTest
+ With oUnitTest
+ Set .[Me] = oUnitTest
+ If Len(vLibraryName) &gt; 0 Then
+ .LibrariesContainer = sTargetLocation
+ .Scope = Iif(sTargetLocation = &quot;user&quot;, &quot;application&quot;, &quot;document&quot;)
+ .Libraries = vLibraries
+ .LibraryName = sLibrary
+ .LibraryIndex = iLibrary
+ .Modules = vModules
+ .ModuleNames = vModuleNames
+ ._ExecutionMode = .FULLMODE
+ ._WhenAssertionFails = .FAILSTOPSUITE
+ &apos; Launch the test timer
+ .TestTimer = CreateScriptService(&quot;ScriptForge.Timer&quot;, True)
+ Else
+ ._ExecutionMode = .SIMPLEMODE
+ ._WhenAssertionFails = .FAILIMMEDIATESTOP
+ End If
+ End With
+
+Finally:
+ Set _NewUnitTest = oUnitTest
+ Exit Function
+Catch:
+ GoTo Finally
+CatchLibrary:
+ ScriptForge.SF_Exception.RaiseFatal(UNITTESTLIBRARYERROR, vLibraryName)
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_Register._NewUnitTest
+
+REM ============================================== END OF SFUNITTESTS.SF_REGISTER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfunittests/SF_UnitTest.xba b/wizards/source/sfunittests/SF_UnitTest.xba
new file mode 100644
index 000000000..5007fb6a7
--- /dev/null
+++ b/wizards/source/sfunittests/SF_UnitTest.xba
@@ -0,0 +1,1818 @@
+<?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_UnitTest" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+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_UnitTest
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; Class providing a framework to execute and check sets of unit tests.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The UnitTest unit testing framework was originally inspired by unittest.py in Python
+&apos;&apos;&apos; and has a similar flavor as major unit testing frameworks in other languages.
+&apos;&apos;&apos;
+&apos;&apos;&apos; It supports test automation, sharing of setup and shutdown code for tests,
+&apos;&apos;&apos; aggregation of tests into collections.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Both the
+&apos;&apos;&apos; - code describing the unit tests
+&apos;&apos;&apos; - code to be tested
+&apos;&apos;&apos; must be written exclusively in Basic (the code might call functions written in other languages).
+&apos;&apos;&apos; Even if either code may be contained in the same module, a much better practice is to
+&apos;&apos;&apos; store them in separate libraries.
+&apos;&apos;&apos; Typically:
+&apos;&apos;&apos; - in a same document when the code to be tested is contained in that document
+&apos;&apos;&apos; - either in a &quot;test&quot; document or in a &quot;My Macros&quot; library when the code
+&apos;&apos;&apos; to be tested is a shared library (My Macros or LibreOffice Macros).
+&apos;&apos;&apos; The code to be tested may be released as an extension. It does not need to make
+&apos;&apos;&apos; use of ScriptForge services in any way.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The test reporting device is the Console. Read about the console in the ScriptForge.Exception service.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; - Test Case
+&apos;&apos;&apos; A test case is the individual unit of testing.
+&apos;&apos;&apos; It checks for a specific response to a particular set of inputs.
+&apos;&apos;&apos; A test case in the UnitTest service is represented by a Basic Sub.
+&apos;&apos;&apos; The name of the Sub starts conventionally with &quot;Test_&quot;.
+&apos;&apos;&apos; The test fails if one of the included AssertXXX methods returns False
+&apos;&apos;&apos; - Test Suite
+&apos;&apos;&apos; A test suite is a collection of test cases that should be executed together.
+&apos;&apos;&apos; A test suite is represented by a Basic module.
+&apos;&apos;&apos; A suite may include the tasks needed to prepare one or more tests, and any associated cleanup actions.
+&apos;&apos;&apos; This may involve, for example, creating temporary files or directories, opening a document, loading libraries.
+&apos;&apos;&apos; Conventionally those tasks are part pf the SetUp&apos;) and TearDown() methods.
+&apos;&apos;&apos; - Unit test
+&apos;&apos;&apos; A full unit test is a set of test suites (each suite in a separate Basic module),
+&apos;&apos;&apos; each of them being a set of test cases (each case is located in a separate Basic Sub).
+&apos;&apos;&apos;
+&apos;&apos;&apos; Two modes:
+&apos;&apos;&apos; Beside the normal mode (&quot;full mode&quot;), using test suites and test cases, a second mode exists, called &quot;simple mode&quot;
+&apos;&apos;&apos; limited to the use exclusively of the Assert...() methods.
+&apos;&apos;&apos; Their boolean returned value may support the execution of limited unit tests.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation examples:
+&apos;&apos;&apos; In full mode, the service creation is external to test cases
+&apos;&apos;&apos; Dim myUnitTest As Variant
+&apos;&apos;&apos; myUnitTest = CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos; &apos; Test code is in the library &quot;Tests&quot; located in the current document
+&apos;&apos;&apos; In simple mode, the service creation is internal to every test case
+&apos;&apos;&apos; Dim myUnitTest As Variant
+&apos;&apos;&apos; myUnitTest = CreateScriptService(&quot;UnitTest&quot;)
+&apos;&apos;&apos; With myUnitTest
+&apos;&apos;&apos; If Not .AssertTrue(...) Then ... &apos; Only calls to the Assert...() methods are allowed
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; .Dispose()
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Minimalist full mode example
+&apos;&apos;&apos; Code to be tested (stored in library &quot;Standard&quot; of document &quot;MyDoc.ods&quot;) :
+&apos;&apos;&apos; Function ArraySize(arr As Variant) As Long
+&apos;&apos;&apos; If IsArray(arr) Then ArraySize = UBound(arr) - LBound(arr) + 1 Else ArraySize = -1
+&apos;&apos;&apos; End Function
+&apos;&apos;&apos; Test code (stored in module &quot;AllTests&quot; of library &quot;Tests&quot; of document &quot;MyDoc.ods&quot;) :
+&apos;&apos;&apos; Sub Main() &apos; Sub to trigger manually, f.i. from the Tools + Run Macro tabbed bar
+&apos;&apos;&apos; GlobalScope.BasicLibraries.loadLibrary(&quot;ScriptForge&quot;)
+&apos;&apos;&apos; Dim test : test = CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos; test.RunTest(&quot;AllTests&quot;) &apos; AllTests is a module name ; test cases are named &quot;Test_*&quot; (default)
+&apos;&apos;&apos; test.Dispose()
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos; REM ------------------------------------------------------------------------------
+&apos;&apos;&apos; Sub Setup(test) &apos; The unittest service is passed as argument
+&apos;&apos;&apos; &apos; Optional Sub to initialize processing of the actual test suite
+&apos;&apos;&apos; Dim exc : exc = CreateScriptService(&quot;Exception&quot;)
+&apos;&apos;&apos; exc.Console(Modal := False) &apos; Watch test progress in the console
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos; REM ------------------------------------------------------------------------------
+&apos;&apos;&apos; Sub Test_ArraySize(test)
+&apos;&apos;&apos; On Local Error GoTo CatchErr
+&apos;&apos;&apos; test.AssertEqual(ArraySize(10), -1, &quot;When not array&quot;)
+&apos;&apos;&apos; test.AssertEqual(ArraySize(Array(1, 2, 3)), 3, &quot;When simple array&quot;)
+&apos;&apos;&apos; test.AssertEqual(ArraySize(DimArray(3)), 4, &quot;When array with empty items&quot;)
+&apos;&apos;&apos; Exit Sub
+&apos;&apos;&apos; CatchErr:
+&apos;&apos;&apos; test.ReportError(&quot;ArraySize() is corrupt&quot;)
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos; REM ------------------------------------------------------------------------------
+&apos;&apos;&apos; Sub TearDown(test)
+&apos;&apos;&apos; &apos; Optional Sub to finalize processing of the actual test suite
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos;
+&apos;&apos;&apos; Error handling
+&apos;&apos;&apos; To support the debugging of the tested code, the UnitTest service, in cases of
+&apos;&apos;&apos; - assertion failure
+&apos;&apos;&apos; - Basic run-time error in the tested code
+&apos;&apos;&apos; - Basic run-time error in the testing code (the unit tests)
+&apos;&apos;&apos; will comment the error location and description in a message box and in the console log,
+&apos;&apos;&apos; providing every test case (in either mode) implements an error handler containing at least:
+&apos;&apos;&apos; Sub Test_Case1(test As Variant)
+&apos;&apos;&apos; On Local Error GoTo Catch
+&apos;&apos;&apos; &apos; ... (AssertXXX(), Fail(), ...)
+&apos;&apos;&apos; Exit Sub
+&apos;&apos;&apos; Catch:
+&apos;&apos;&apos; test.ReportError()
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_unittest.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+Private Const UNITTESTMETHODERROR = &quot;UNITTESTMETHODERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be &quot;UNITTEST&quot;
+Private ServiceName As String
+
+&apos; Testing code
+Private LibrariesContainer As String &apos; Document or user Basic library containing the test library
+Private Scope As String &apos; Scope when running a Basic script with Session.ExecuteBasicScript()
+Private Libraries As Variant &apos; Set of libraries
+Private LibraryName As String &apos; Name of the library containing the test code
+Private LibraryIndex As Integer &apos; Index in Libraries
+Private Modules As Variant &apos; Set of modules
+Private ModuleNames As Variant &apos; Set of module names
+Private MethodNames As Variant &apos; Set of methods in a given module
+
+&apos; Internals
+Private _Verbose As Boolean &apos; When True, every assertion is reported,failing or not
+Private _LongMessage As Boolean &apos; When False, only the message provided by the tester is considered
+ &apos; When True (default), that message is appended to the standard message
+Private _WhenAssertionFails As Integer &apos; Determines what to do when a test fails
+
+&apos; Test status
+Private _Status As Integer &apos; 0 = standby
+ &apos; 1 = test suite started
+ &apos; 2 = setup started
+ &apos; 3 = test case started
+ &apos; 4 = teardown started
+Private _ExecutionMode As Integer &apos; 1 = Test started with RunTest()
+ &apos; 2 = Test started with CreateScriptService() Only Assert() methods allowed
+Private _Module As String &apos; Exact name of module currently running
+Private _TestCase As String &apos; Exact name of test case currently running
+Private _ReturnCode As Integer &apos; 0 = Normal end
+ &apos; 1 = Assertion failed
+ &apos; 2 = Skip request (in Setup() only)
+ &apos;-1 = abnormal end
+Private _FailedAssert As String &apos; Assert function that returned a failure
+
+&apos; Timers
+Private TestTimer As Object &apos; Started by CreateScriptService()
+Private SuiteTimer As Object &apos; Started by RunTest()
+Private CaseTimer As Object &apos; Started by new case
+
+&apos; Services
+Private Exception As Object &apos; SF_Exception
+Private Session As Object &apos; SF_Session
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos; When assertion fails constants: error is reported + ...
+Global Const FAILIGNORE = 0 &apos; Ignore the failure
+Global Const FAILSTOPSUITE = 1 &apos; Module TearDown is executed, then next suite may be started (default in full mode)
+Global Const FAILIMMEDIATESTOP = 2 &apos; Stop immediately (default in simple mode)
+
+&apos; Unit tests status (internal use only =&gt; not Global)
+Const STATUSSTANDBY = 0 &apos; No test active
+Const STATUSSUITESTARTED = 1 &apos; RunTest() started
+Const STATUSSETUP = 2 &apos; A Setup() method is running
+Const STATUSTESTCASE = 3 &apos; A test case is running
+Const STATUSTEARDOWN = 4 &apos; A TearDown() method is running
+
+&apos; Return codes
+Global Const RCNORMALEND = 0 &apos; Normal end of test or test not started
+Global Const RCASSERTIONFAILED = 1 &apos; An assertion within a test case returned False
+Global Const RCSKIPTEST = 2 &apos; A SkipTest() was issued by a Setup() method
+Global Const RCABORTTEST = 3 &apos; Abnormal end of test
+
+&apos; Execution modes
+Global Const FULLMODE = 1 &apos; 1 = Test started with RunTest()
+Global Const SIMPLEMODE = 2 &apos; 2 = Test started with CreateScriptService() Only Assert() methods allowed
+
+Const INVALIDPROCEDURECALL = &quot;5&quot; &apos; Artificial error raised when an assertion fails
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;UNITTEST&quot;
+ ServiceName = &quot;SFUnitTests.UnitTest&quot;
+ LibrariesContainer = &quot;&quot;
+ Scope = &quot;&quot;
+ Libraries = Array()
+ LibraryName = &quot;&quot;
+ LibraryIndex = -1
+ _Verbose = False
+ _LongMessage = True
+ _WhenAssertionFails = -1
+ _Status = STATUSSTANDBY
+ _ExecutionMode = SIMPLEMODE
+ _Module = &quot;&quot;
+ _TestCase = &quot;&quot;
+ _ReturnCode = RCNORMALEND
+ _FailedAssert = &quot;&quot;
+ Set TestTimer = Nothing
+ Set SuiteTimer = Nothing
+ Set CaseTimer = Nothing
+ Set Exception = CreateScriptService(&quot;ScriptForge.Exception&quot;)
+ Set Session = CreateScriptService(&quot;ScriptForge.Session&quot;)
+End Sub &apos; SFUnitTests.SF_UnitTest Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ If Not IsNull(CaseTimer) Then CaseTimer = CaseTimer.Dispose()
+ If Not IsNull(SuiteTimer) Then SuiteTimer = SuiteTimer.Dispose()
+ If Not IsNull(TestTimer) Then TestTimer = TestTimer.Dispose()
+ Call Class_Initialize()
+End Sub &apos; SFUnitTests.SF_UnitTest Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFUnitTests.SF_UnitTest Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get LongMessage() As Variant
+&apos;&apos;&apos; When False, only the message provided by the tester is considered
+&apos;&apos;&apos; When True (default), that message is appended to the standard message
+ LongMessage = _PropertyGet(&quot;LongMessage&quot;)
+End Property &apos; SFUnitTests.SF_UnitTest.LongMessage (get)
+
+REM -----------------------------------------------------------------------------
+Property Let LongMessage(Optional ByVal pvLongMessage As Variant)
+&apos;&apos;&apos; Set the updatable property LongMessage
+ _PropertySet(&quot;LongMessage&quot;, pvLongMessage)
+End Property &apos; SFUnitTests.SF_UnitTest.LongMessage (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ReturnCode() As Integer
+&apos;&apos;&apos; RCNORMALEND = 0 &apos; Normal end of test or test not started
+&apos;&apos;&apos; RCASSERTIONFAILED = 1 &apos; An assertion within a test case returned False
+&apos;&apos;&apos; RCSKIPTEST = 2 &apos; A SkipTest() was issued by a Setup() method
+&apos;&apos;&apos; RCABORTTEST = 3 &apos; Abnormal end of test
+ ReturnCode = _PropertyGet(&quot;ReturnCode&quot;)
+End Property &apos; SFUnitTests.SF_UnitTest.ReturnCode (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Verbose() As Variant
+&apos;&apos;&apos; The Verbose property indicates if all assertions (True AND False) are reported
+ Verbose = _PropertyGet(&quot;Verbose&quot;)
+End Property &apos; SFUnitTests.SF_UnitTest.Verbose (get)
+
+REM -----------------------------------------------------------------------------
+Property Let Verbose(Optional ByVal pvVerbose As Variant)
+&apos;&apos;&apos; Set the updatable property Verbose
+ _PropertySet(&quot;Verbose&quot;, pvVerbose)
+End Property &apos; SFUnitTests.SF_UnitTest.Verbose (let)
+
+REM -----------------------------------------------------------------------------
+Property Get WhenAssertionFails() As Variant
+&apos;&apos;&apos; What when an AssertXXX() method returns False
+&apos;&apos;&apos; FAILIGNORE = 0 &apos; Ignore the failure
+&apos;&apos;&apos; FAILSTOPSUITE = 1 &apos; Module TearDown is executed, then next suite may be started (default in FULL mode)
+&apos;&apos;&apos; FAILIMMEDIATESTOP = 2 &apos; Stop immediately (default in SIMPLE mode)
+&apos;&apos;&apos; In simple mode, only FAILIGNORE and FAILIMMEDIATESTOP are allowed.
+&apos;&apos;&apos; In both modes, when WhenAssertionFails has not the value FAILIGNORE,
+&apos;&apos;&apos; each test case MUST have a run-time error handler calling the ReportError() method.
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Sub Test_sometest(Optional test)
+&apos;&apos;&apos; On Local Error GoTo CatchError
+&apos;&apos;&apos; &apos; ... one or more assert verbs
+&apos;&apos;&apos; Exit Sub
+&apos;&apos;&apos; CatchError:
+&apos;&apos;&apos; test.ReportError()
+&apos;&apos;&apos; End Sub
+ WhenAssertionFails = _PropertyGet(&quot;WhenAssertionFails&quot;)
+End Property &apos; SFUnitTests.SF_UnitTest.WhenAssertionFails (get)
+
+REM -----------------------------------------------------------------------------
+Property Let WhenAssertionFails(Optional ByVal pvWhenAssertionFails As Variant)
+&apos;&apos;&apos; Set the updatable property WhenAssertionFails
+ _PropertySet(&quot;WhenAssertionFails&quot;, pvWhenAssertionFails)
+End Property &apos; SFUnitTests.SF_UnitTest.WhenAssertionFails (let)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function AssertAlmostEqual(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Tolerance As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A and B are numerical values and are found close to each other.
+&apos;&apos;&apos; It is typically used to compare very large or very small numbers.
+&apos;&apos;&apos; Equality is confirmed when
+&apos;&apos;&apos; - A and B can be converted to doubles
+&apos;&apos;&apos; - The absolute difference between a and b, relative to the larger absolute value of a or b,
+&apos;&apos;&apos; is lower or equal to the tolerance. The default tolerance is 1E-09,
+&apos;&apos;&apos; Examples: 1E+12 and 1E+12 + 100 are almost equal
+&apos;&apos;&apos; 1E-20 and 2E-20 are not almost equal
+&apos;&apos;&apos; 100 and 95 are almost equal when Tolerance = 0.05
+
+Dim bAssert As Boolean &apos; Return value
+Const cstTolerance = 1E-09
+Const cstThisSub = &quot;UnitTest.AssertAlmostEqual&quot;
+Const cstSubArgs = &quot;A, B, [Tolerance=1E-09], [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Tolerance) Then Tolerance = cstTolerance
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Tolerance, &quot;Tolerance&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertAlmostEqual&quot;, True, A, B, Message, Tolerance)
+
+Finally:
+ AssertAlmostEqual = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertAlmostEqual
+
+REM -----------------------------------------------------------------------------
+Public Function AssertEqual(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A and B are found equal.
+&apos;&apos;&apos; Equality is confirmed when
+&apos;&apos;&apos; If A and B are scalars:
+&apos;&apos;&apos; They should have the same VarType or both be numeric
+&apos;&apos;&apos; Booleans and numeric values are compared with the = operator
+&apos;&apos;&apos; Strings are compared with the StrComp() builtin function. The comparison is case-sensitive
+&apos;&apos;&apos; Dates and times are compared up to the second
+&apos;&apos;&apos; Null, Empty and Nothing are not equal, but AssertEqual(Nothing, Nothing) returns True
+&apos;&apos;&apos; UNO objects are compared with the EqualUnoObjects() method
+&apos;&apos;&apos; Basic objects are NEVER equal
+&apos;&apos;&apos; If A and B are arrays:
+&apos;&apos;&apos; They should have the same number of dimensions (maximum 2)
+&apos;&apos;&apos; The lower and upper bounds must be identical for each dimension
+&apos;&apos;&apos; Two empty arrays are equal
+&apos;&apos;&apos; Their items must be equal one by one
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertEqual&quot;, True, A, B, Message)
+
+Finally:
+ AssertEqual = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertEqual
+
+REM -----------------------------------------------------------------------------
+Public Function AssertFalse(Optional ByRef A As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is a Boolean and its value is False
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertFalse&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertFalse&quot;, True, A, Empty, Message)
+
+Finally:
+ AssertFalse = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertFalse
+
+REM -----------------------------------------------------------------------------
+Public Function AssertGreater(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is greater than B.
+&apos;&apos;&apos; To compare A and B:
+&apos;&apos;&apos; They should have the same VarType or both be numeric
+&apos;&apos;&apos; Eligible datatypes are String, Date or numeric.
+&apos;&apos;&apos; String comparisons are case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertGreater&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertGreater&quot;, True, A, B, Message)
+
+Finally:
+ AssertGreater = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertGreater
+
+REM -----------------------------------------------------------------------------
+Public Function AssertGreaterEqual(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is greater than or equal to B.
+&apos;&apos;&apos; To compare A and B:
+&apos;&apos;&apos; They should have the same VarType or both be numeric
+&apos;&apos;&apos; Eligible datatypes are String, Date or numeric.
+&apos;&apos;&apos; String comparisons are case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertGreaterEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertGreaterEqual&quot;, True, A, B, Message)
+
+Finally:
+ AssertGreaterEqual = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertGreaterEqual
+
+REM -----------------------------------------------------------------------------
+Public Function AssertIn(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A, a string, is found within B
+&apos;&apos;&apos; B may be a 1D array, a ScriptForge dictionary or a string.
+&apos;&apos;&apos; When B is an array, A may be a date or a numeric value.
+&apos;&apos;&apos; String comparisons are case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertIn&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertIn&quot;, True, A, B, Message)
+
+Finally:
+ AssertIn = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertIn
+
+REM -----------------------------------------------------------------------------
+Public Function AssertIsInstance(Optional ByRef A As Variant _
+ , Optional ByRef ObjectType As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is an object instance of the class ObjectType or a variable of type ObjectType.
+&apos;&apos;&apos; A may be:
+&apos;&apos;&apos; - a ScriptForge object
+&apos;&apos;&apos; ObjectType is a string like &quot;DICTIONARY&quot;, &quot;calc&quot;, &quot;Dialog&quot;, &quot;exception&quot;, etc.
+&apos;&apos;&apos; - a UNO object
+&apos;&apos;&apos; ObjectType is a string identical with values returned by the SF_Session.UnoObjectType()
+&apos;&apos;&apos; - any variable, providing it is neither an object nor an array
+&apos;&apos;&apos; ObjectType is a string identifying a value returned by the TypeName() builtin function
+&apos;&apos;&apos; - an array
+&apos;&apos;&apos; ObjectType is expected to be &quot;array&quot;
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertIsInstance&quot;
+Const cstSubArgs = &quot;A, ObjectType, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(ObjectType) Then ObjectType = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(ObjectType, &quot;ObjectType&quot;, V_STRING) Then GoTo Catch
+
+
+Try:
+ bAssert = _Assert(&quot;AssertIsInstance&quot;, True, A, Empty, Message, ObjectType)
+
+Finally:
+ AssertIsInstance = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertIsInstance
+
+REM -----------------------------------------------------------------------------
+Public Function AssertIsNothing(Optional ByRef A As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is an object that has the Nothing value
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertIsNothing&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertIsNothing&quot;, True, A, Empty, Message)
+
+Finally:
+ AssertIsNothing = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertIsNothing
+
+REM -----------------------------------------------------------------------------
+Public Function AssertIsNull(Optional ByRef A As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A has the Null value
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertIsNull&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertIsNull&quot;, True, A, Empty, Message)
+
+Finally:
+ AssertIsNull = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertIsNull
+
+REM -----------------------------------------------------------------------------
+Public Function AssertLess(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is less than B.
+&apos;&apos;&apos; To compare A and B:
+&apos;&apos;&apos; They should have the same VarType or both be numeric
+&apos;&apos;&apos; Eligible datatypes are String, Date or numeric.
+&apos;&apos;&apos; String comparisons are case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertLess&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertLess&quot;, False, A, B, Message)
+
+Finally:
+ AssertLess = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertLess
+
+REM -----------------------------------------------------------------------------
+Public Function AssertLessEqual(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is less than or equal to B.
+&apos;&apos;&apos; To compare A and B:
+&apos;&apos;&apos; They should have the same VarType or both be numeric
+&apos;&apos;&apos; Eligible datatypes are String, Date or numeric.
+&apos;&apos;&apos; String comparisons are case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertLessEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertLessEqual&quot;, False, A, B, Message)
+
+Finally:
+ AssertLessEqual = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertLessEqual
+
+REM -----------------------------------------------------------------------------
+Public Function AssertLike(Optional ByRef A As Variant _
+ , Optional ByRef Pattern As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if string A matches a given pattern containing wildcards
+&apos;&apos;&apos; Admitted wildcard are: the &quot;?&quot; represents any single character
+&apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos; The comparison is case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertLike&quot;
+Const cstSubArgs = &quot;A, Pattern, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Pattern) Then Pattern = &quot;&quot;
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Pattern, &quot;Pattern&quot;, V_STRING) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertLike&quot;, True, A, Empty, Message, Pattern)
+
+Finally:
+ AssertLike = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertLike
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotAlmostEqual(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Tolerance As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A and B are numerical values and are not found close to each other.
+&apos;&apos;&apos; Read about almost equality in the comments linked to the AssertEqual() method.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstTolerance = 1E-09
+Const cstThisSub = &quot;UnitTest.AssertNotAlmostEqual&quot;
+Const cstSubArgs = &quot;A, B, [Tolerance=1E-09], [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Tolerance) Then Tolerance = cstTolerance
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Tolerance, &quot;Tolerance&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertNotAlmostEqual&quot;, False, A, B, Message, Tolerance)
+
+Finally:
+ AssertNotAlmostEqual = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotAlmostEqual
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotEqual(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A and B are found unequal.
+&apos;&apos;&apos; Read about equality in the comments linked to the AssertEqual() method.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotEqual&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertNotEqual&quot;, False, A, B, Message)
+
+Finally:
+ AssertNotEqual = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotEqual
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotIn(Optional ByRef A As Variant _
+ , Optional ByRef B As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A, a string, is not found within B
+&apos;&apos;&apos; B may be a 1D array, a ScriptForge dictionary or a string.
+&apos;&apos;&apos; When B is an array, A may be a date or a numeric value.
+&apos;&apos;&apos; String comparisons are case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotIn&quot;
+Const cstSubArgs = &quot;A, B, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(B) Then B = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertNotIn&quot;, False, A, B, Message)
+
+Finally:
+ AssertNotIn = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotIn
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotInstance(Optional ByRef A As Variant _
+ , Optional ByRef ObjectType As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is an object instance of the class ObjectType or a variable of type ObjectType.
+&apos;&apos;&apos; More details to be read under the AssertInstance() function.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotInstance&quot;
+Const cstSubArgs = &quot;A, ObjectType, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(ObjectType) Then ObjectType = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(ObjectType, &quot;ObjectType&quot;, V_STRING) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertNotInstance&quot;, False, A, Empty, Message, ObjectType)
+
+Finally:
+ AssertNotInstance = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotInstance
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotLike(Optional ByRef A As Variant _
+ , Optional ByRef Pattern As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True if A is not a string or does not match a given pattern containing wildcards
+&apos;&apos;&apos; Admitted wildcard are: the &quot;?&quot; represents any single character
+&apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos; The comparison is case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotLike&quot;
+Const cstSubArgs = &quot;A, Pattern, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Pattern) Then Pattern = &quot;&quot;
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Pattern, &quot;Pattern&quot;, V_STRING) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertNotLike&quot;, False, A, Empty, Message, Pattern)
+
+Finally:
+ AssertNotLike = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotLike
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotNothing(Optional ByRef A As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True except when A is an object that has the Nothing value
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotNothing&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertNotNothing&quot;, False, A, Empty, Message)
+
+Finally:
+ AssertNotNothing = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotNothing
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotNull(Optional ByRef A As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True except when A has the Null value
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotNull&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertNotNull&quot;, False, A, Empty, Message)
+
+Finally:
+ AssertNotNull = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotNull
+
+REM -----------------------------------------------------------------------------
+Public Function AssertNotRegex(Optional ByRef A As Variant _
+ , Optional ByRef Regex As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is not a string or does not match the given regular expression.
+&apos;&apos;&apos; The comparison is case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertNotRegex&quot;
+Const cstSubArgs = &quot;A, Regex, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Regex) Then Regex = &quot;&quot;
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertNotRegex&quot;, False, A, Empty, Message, Regex)
+
+Finally:
+ AssertNotRegex = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertNotRegex
+
+REM -----------------------------------------------------------------------------
+Public Function AssertRegex(Optional ByRef A As Variant _
+ , Optional ByRef Regex As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when string A matches the given regular expression.
+&apos;&apos;&apos; The comparison is case-sensitive.
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertRegex&quot;
+Const cstSubArgs = &quot;A, Regex, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Regex) Then Regex = &quot;&quot;
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Regex, &quot;Regex&quot;, V_STRING) Then GoTo Catch
+
+Try:
+ bAssert = _Assert(&quot;AssertRegex&quot;, True, A, Empty, Message, Regex)
+
+Finally:
+ AssertRegex = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ bAssert = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.AssertRegex
+
+REM -----------------------------------------------------------------------------
+Public Function AssertTrue(Optional ByRef A As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Returns True when A is a Boolean and its value is True
+
+Dim bAssert As Boolean &apos; Return value
+Const cstThisSub = &quot;UnitTest.AssertTrue&quot;
+Const cstSubArgs = &quot;A, [Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(A) Then A = Empty
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;AssertTrue&quot;, True, A, Empty, Message)
+
+Finally:
+ AssertTrue = bAssert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest.AssertTrue
+
+REM -----------------------------------------------------------------------------
+Public Sub Fail(Optional ByVal Message As Variant)
+&apos;&apos;&apos; Forces a test failure
+
+Dim bAssert As Boolean &apos; Fictive return value
+Const cstThisSub = &quot;UnitTest.Fail&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ bAssert = _Assert(&quot;Fail&quot;, False, Empty, Empty, Message)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; SFUnitTests.SF_UnitTest.Fail
+
+REM -----------------------------------------------------------------------------
+Public Sub Log(Optional ByVal Message As Variant)
+&apos;&apos;&apos; Records the given message in the test report (console)
+
+Dim bAssert As Boolean &apos; Fictive return value
+Dim bVerbose As Boolean : bVerbose = _Verbose
+Const cstThisSub = &quot;UnitTest.Log&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+
+Try:
+ &apos; Force the display of the message in the console
+ _Verbose = True
+ bAssert = _Assert(&quot;Log&quot;, True, Empty, Empty, Message)
+ _Verbose = bVerbose
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; SFUnitTests.SF_UnitTest.Log
+
+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
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myUnitTest.GetProperty(&quot;Duration&quot;)
+
+Const cstThisSub = &quot;UnitTest.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&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; SFUnitTests.SF_UnitTest.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list or methods of the UnitTest class as an array
+
+ Methods = Array( _
+ &quot;AssertAlmostEqual&quot; _
+ , &quot;AssertEqual&quot; _
+ , &quot;AssertFalse&quot; _
+ , &quot;AssertGreater&quot; _
+ , &quot;AssertGreaterEqual&quot; _
+ , &quot;AssertIn&quot; _
+ , &quot;AssertIsInstance&quot; _
+ , &quot;AssertIsNothing&quot; _
+ , &quot;AssertLike&quot; _
+ , &quot;AssertNotRegex&quot; _
+ , &quot;AssertIsNull&quot; _
+ , &quot;AssertLess&quot; _
+ , &quot;AssertLessEqual&quot; _
+ , &quot;AssertNotAlmostEqual&quot; _
+ , &quot;AssertNotEqual&quot; _
+ , &quot;AssertNotIn&quot; _
+ , &quot;AssertNotInstance&quot; _
+ , &quot;AssertNotLike&quot; _
+ , &quot;AssertNotNothing&quot; _
+ , &quot;AssertNotNull&quot; _
+ , &quot;AssertRegex&quot; _
+ , &quot;AssertTrue&quot; _
+ , &quot;Fail&quot; _
+ , &quot;Log&quot; _
+ , &quot;RunTest&quot; _
+ , &quot;SkipTest&quot; _
+ )
+
+End Function &apos; SFUnitTests.SF_UnitTest.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the UnitTest class as an array
+
+ Properties = Array( _
+ &quot;LongMessage&quot; _
+ , &quot;ReturnCode&quot; _
+ , &quot;Verbose&quot; _
+ , &quot;WhenAssertionFails&quot; _
+ )
+
+End Function &apos; SFUnitTests.SF_UnitTest.Properties
+
+REM -----------------------------------------------------------------------------
+Public Sub ReportError(Optional ByVal Message As Variant)
+&apos;&apos;&apos; DIsplay a message box with the current property values of the &quot;Exception&quot; service.
+&apos;&apos;&apos; Depending on the WhenAssertionFails property, a Raise() or RaiseWarning()
+&apos;&apos;&apos; is issued. The Raise() method stops completely the Basic running process.
+&apos;&apos;&apos; The ReportError() method is presumed present in a user script in an error
+&apos;&apos;&apos; handling part of the actual testcase.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Message: a string to replace or to complete the standard message description
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; See the Test_ArraySize() sub in the module&apos;s heading example
+
+Dim sLine As String &apos; Line number where the error occurred
+Dim sError As String &apos; Exception description
+Dim sErrorCode As String &apos; Exception number
+Const cstThisSub = &quot;UnitTest.ReportError&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+Check:
+ If IsMissing(Message) Or IsEmpty(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If VarType(Message) &lt;&gt; V_STRING Then Message = &quot;&quot;
+
+Try:
+ sLine = &quot;ln &quot; &amp; CStr(Exception.Source)
+ If _ExecutionMode = FULLMODE Then sLine = _Module &amp; &quot;.&quot; &amp; _TestCase &amp; &quot; &quot; &amp; sLine
+ If Len(Message) &gt; 0 Then
+ sError = Message
+ Else
+ If Exception.Number = INVALIDPROCEDURECALL Then
+ sError = &quot;Test case failure&quot;
+ sErrorCode = &quot;ASSERTIONFAILED&quot;
+ Else
+ sError = Exception.Description
+ sErrorCode = CStr(Exception.Number)
+ End If
+ End If
+
+ Select Case _WhenAssertionFails
+ Case FAILIGNORE
+ Case FAILSTOPSUITE
+ Exception.RaiseWarning(sErrorCode, sLine, sError)
+ Case FAILIMMEDIATESTOP
+ Exception.Raise(sErrorCode, sLine, sError)
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; SFUnitTests.SF_UnitTest.ReportError
+REM -----------------------------------------------------------------------------
+Public Function RunTest(Optional ByVal TestSuite As Variant _
+ , Optional ByVal TestCasePattern As Variant _
+ , Optional ByVal Message As Variant _
+ ) As Integer
+&apos;&apos;&apos; Execute a test suite pointed out by a module name.
+&apos;&apos;&apos; Each test case will be run independently from each other.
+&apos;&apos;&apos; The names of the test cases to be run may be selected with a string pattern.
+&apos;&apos;&apos; The test is &quot;orchestrated&quot; by this method:
+&apos;&apos;&apos; 1. Execute the optional Setup() method present in the module
+&apos;&apos;&apos; 2. Execute once each test case, in any order
+&apos;&apos;&apos; 3, Execute the optional TearDown() method present in the module
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; TestSuite: the name of the module containing the set of test cases to run
+&apos;&apos;&apos; TestCasePattern: the pattern that the test cases must match. The comparison is not case-sensitive.
+&apos;&apos;&apos; Non-matching functions and subs are ignored.
+&apos;&apos;&apos; Admitted wildcard are: the &quot;?&quot; represents any single character
+&apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos; The default pattern is &quot;Test_*&quot;
+&apos;&apos;&apos; Message: the message to be displayed in the console when the test starts.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; One of the return codes of the execution (RCxxx constants)
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; GlobalScope.BasicLibraries.loadLibrary(&quot;ScriptForge&quot;)
+&apos;&apos;&apos; Dim test : test = CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos; test.RunTest(&quot;AllTests&quot;) &apos; AllTests is a module name ; test cases are named &quot;Test_*&quot; (default)
+
+Dim iRun As Integer &apos; Return value
+Dim sRunMessage As String &apos; Reporting
+Dim iModule As Integer &apos; Index of module currently running
+Dim vMethods As Variant &apos; Set of methods
+Dim sMethod As String &apos; A single method
+Dim iMethod As Integer &apos; Index in MethodNames
+Dim m As Integer
+
+Const cstThisSub = &quot;UnitTest.RunTest&quot;
+Const cstSubArgs = &quot;TestSuite, [TestCasePattern=&quot;&quot;Test_*&quot;&quot;], [Message=&quot;&quot;&quot;&quot;]&quot;
+
+ iRun = RCNORMALEND
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(TestCasePattern) Or IsEmpty(TestCasePattern) Then TestCasePattern = &quot;Test_*&quot;
+ If IsMissing(Message) Or IsEmpty(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(TestSuite, &quot;TestSuite&quot;, V_STRING, ModuleNames) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(TestCasePattern, &quot;TestCasePattern&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Message, &quot;Message&quot;, V_STRING) Then GoTo Catch
+
+ &apos; A RunTest() is forbidden inside a test suite or when simple mode
+ If _Status &lt;&gt; STATUSSTANDBY Or _ExecutionMode &lt;&gt; FULLMODE Then GoTo CatchMethod
+
+ &apos; Ignore any call when an abnormal end has been encountered
+ If _ReturnCode = RCABORTTEST Then GoTo Catch
+
+Try:
+ iModule = ScriptForge.SF_Array.IndexOf(ModuleNames, TestSuite, CaseSensitive := False, SortOrder := &quot;ASC&quot;)
+ _Module = ModuleNames(iModule)
+
+ &apos; Start timer
+ If Not IsNull(SuiteTimer) Then SuiteTimer = SuiteTimer.Dispose()
+ Set SuiteTimer = CreateScriptService(&quot;ScriptForge.Timer&quot;, True)
+
+ &apos; Report the start of a new test suite
+ sRunMessage = &quot;RUNTEST ENTER testsuite=&apos;&quot; &amp; LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;&apos;, pattern=&apos;&quot; &amp; TestCasePattern &amp; &quot;&apos;&quot;
+ _ReportMessage(sRunMessage, Message)
+ _Status = STATUSSUITESTARTED
+
+ &apos; Collect all the methods of the module
+ If Modules(iModule).hasChildNodes() Then
+ vMethods = Modules(iModule).getChildNodes()
+ MethodNames = Array()
+ For m = 0 To UBound(vMethods)
+ sMethod = vMethods(m).getName()
+ MethodNames = ScriptForge.SF_Array.Append(MethodNames, sMethod)
+ Next m
+ End If
+
+ &apos; Execute the Setup() method, if it exists
+ iMethod = ScriptForge.SF_Array.IndexOf(MethodNames, &quot;Setup&quot;, CaseSensitive := False, SortOrder := &quot;ASC&quot;)
+ If iMethod &gt;= 0 Then
+ _TestCase = MethodNames(iMethod) &apos; _TestCase is used in ReportError()
+ If Not _ExecuteScript(_TestCase) Then GoTo Catch
+ End If
+
+ &apos; Execute the test cases that match the pattern
+ For iMethod = 0 To UBound(MethodNames)
+ If _ReturnCode = RCSKIPTEST Or _ReturnCode = RCASSERTIONFAILED Then Exit For
+ sMethod = MethodNames(iMethod)
+ If ScriptForge.SF_String.IsLike(sMethod, TestCasePattern, CaseSensitive := False) Then
+ _TestCase = sMethod
+ &apos; Start timer
+ If Not IsNull(CaseTimer) Then CaseTimer = CaseTimer.Dispose()
+ Set CaseTimer = CreateScriptService(&quot;ScriptForge.Timer&quot;, True)
+ If Not _ExecuteScript(sMethod) Then GoTo Catch
+ CaseTimer.Terminate()
+ _TestCase = &quot;&quot;
+ End If
+ Next iMethod
+
+ If _ReturnCode &lt;&gt; RCSKIPTEST Then
+ &apos; Execute the TearDown() method, if it exists
+ iMethod = ScriptForge.SF_Array.IndexOf(MethodNames, &quot;TearDown&quot;, CaseSensitive := False, SortOrder := &quot;ASC&quot;)
+ If iMethod &gt;= 0 Then
+ _TestCase = MethodNames(iMethod) &apos; _TestCase is used in ReportError()
+ If Not _ExecuteScript(_TestCase) Then GoTo Catch
+ End If
+ End If
+
+ &apos; Report the end of the current test suite
+ sRunMessage = &quot;RUNTEST EXIT testsuite=&apos;&quot; &amp; LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;&apos; &quot; &amp; _Duration(&quot;Suite&quot;, True)
+ _ReportMessage(sRunMessage, Message)
+
+ &apos; Stop timer
+ SuiteTimer.Terminate()
+
+ &apos; Housekeeping
+ MethodNames = Array()
+ _Module = &quot;&quot;
+ _Status = STATUSSTANDBY
+
+Finally:
+ _ReturnCode = iRun
+ RunTest = iRun
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ iRun = RCABORTTEST
+ GoTo Finally
+CatchMethod:
+ ScriptForge.SF_Exception.RaiseFatal(UNITTESTMETHODERROR, &quot;RunTest&quot;)
+ GoTo Catch
+End Function &apos; SFUnitTests.SF_UnitTest.RunTest
+
+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;UnitTest.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ SetProperty = False
+
+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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function SkipTest(Optional ByVal Message As Variant) As Boolean
+&apos;&apos;&apos; Interrupt the running test suite. The TearDown() method is NOT executed.
+&apos;&apos;&apos; The SkipTest() method is normally meaningful only in a Setup() method when not all the
+&apos;&apos;&apos; conditions to run the test are met.
+&apos;&apos;&apos; It is up to the Setup() script to exit shortly after the SkipTest() call..
+&apos;&apos;&apos; The method may also be executed in a test case. Next test cases will not be executed.
+&apos;&apos;&apos; Remember however that the test cases are executed is an arbitrary order.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Message: the message to be displayed in the console
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; GlobalScope.BasicLibraries.loadLibrary(&quot;ScriptForge&quot;)
+&apos;&apos;&apos; Dim test : test = CreateScriptService(&quot;UnitTest&quot;, ThisComponent, &quot;Tests&quot;)
+&apos;&apos;&apos; test.SkipTest(&quot;AllTests&quot;) &apos; AllTests is a module name ; test cases are named &quot;Test_*&quot; (default)
+
+Dim bSkip As Boolean &apos; Return value
+Dim sSkipMessage As String &apos; Reporting
+
+Const cstThisSub = &quot;UnitTest.SkipTest&quot;
+Const cstSubArgs = &quot;[Message=&quot;&quot;&quot;&quot;]&quot;
+
+ bSkip = False
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(Message) Or IsEmpty(Message) Then Message = &quot;&quot;
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Unconditional !
+ If Not ScriptForge.SF_Utils._Validate(Message, &quot;Message&quot;, V_STRING) Then GoTo Catch
+
+ &apos; A SkipTest() is forbidden when simple mode
+ If _ExecutionMode &lt;&gt; FULLMODE Then GoTo CatchMethod
+
+ &apos; Ignore any call when an abnormal end has been encountered
+ If _ReturnCode = RCABORTTEST Then GoTo Catch
+
+Try:
+ If _Status = STATUSSETUP Or _Status = STATUSTESTCASE Then
+ _ReturnCode = RCSKIPTEST
+ bSkip = True
+ &apos; Exit message
+ sSkipMessage = &quot; SKIPTEST testsuite=&apos;&quot; &amp; LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;&apos; &quot; &amp; _Duration(&quot;Suite&quot;, True)
+ _ReportMessage(sSkipMessage, Message)
+ End If
+
+Finally:
+ SkipTest = bSkip
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ _ReturnCode = RCABORTTEST
+ GoTo Finally
+CatchMethod:
+ ScriptForge.SF_Exception.RaiseFatal(UNITTESTMETHODERROR, &quot;SkipTest&quot;)
+ GoTo Catch
+End Function &apos; SFUnitTests.SF_UnitTest.SkipTest
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _Assert(ByVal psAssert As String _
+ , ByVal pvReturn As Variant _
+ , ByRef A As Variant _
+ , ByRef B As Variant _
+ , Optional ByVal pvMessage As Variant _
+ , Optional ByVal pvArg As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Evaluation of the assertion and management of the success or the failure
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psAssert: the assertion verb as a string
+&apos;&apos;&apos; pvReturn: may be True, False or Empty
+&apos;&apos;&apos; When True (resp. False), the assertion must be evaluated as True (resp. False)
+&apos;&apos;&apos; e.g. AssertEqual() will call _Assert(&quot;AssertEqual&quot;, True, ...)
+&apos;&apos;&apos; AssertNotEqual() will call _Assert(&quot;AssertNotEqual&quot;, False, ...)
+&apos;&apos;&apos; Empty may be used for recursive calls of the function (for comparing arrays, ...)
+&apos;&apos;&apos; A: always present
+&apos;&apos;&apos; B: may be empty
+&apos;&apos;&apos; pvMessage: the message to display on the console
+&apos;&apos;&apos; pvArg: optional additional argument of the assert function
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when success
+
+Dim bAssert As Boolean &apos; Return value
+Dim bEval As Boolean &apos; To be compared with pvReturn
+Dim iVarTypeA As Integer &apos; Alias of _VarTypeExt(A)
+Dim iVarTypeB As Integer &apos; Alias of _VarTypeExt(B)
+Dim oVarTypeObjA As Object &apos; SF_Utils.ObjectDescriptor
+Dim oVarTypeObjB As Object &apos; SF_Utils.ObjectDescriptor
+Dim oUtils As Object : Set oUtils = ScriptForge.SF_Utils
+Dim iDims As Integer &apos; Number of dimensions of array
+Dim oAliasB As Object &apos; Alias of B to bypass the &quot;Object variable not set&quot; issue
+Dim dblA As Double &apos; Alias of A
+Dim dblB As Double &apos; Alias of B
+Dim dblTolerance As Double &apos; Alias of pvArg
+Dim oString As Object : Set oString = ScriptForge.SF_String
+Dim sArgName As String &apos; Argument description
+Dim i As Long, j As Long
+
+Check:
+ bAssert = False
+ If IsMissing(pvMessage) Then pvMessage = &quot;&quot;
+ If Not oUtils._Validate(pvMessage, &quot;Message&quot;, V_STRING) Then GoTo Finally
+ If IsMissing(pvArg) Then pvArg = &quot;&quot;
+
+Try:
+ iVarTypeA = oUtils._VarTypeExt(A)
+ iVarTypeB = oUtils._VarTypeExt(B)
+ sArgName = &quot;&quot;
+
+ Select Case UCase(psAssert)
+ Case UCase(&quot;AssertAlmostEqual&quot;), UCase(&quot;AssertNotAlmostEqual&quot;)
+ bEval = ( iVarTypeA = iVarTypeB And iVarTypeA = ScriptForge.V_NUMERIC )
+ If bEval Then
+ dblA = CDbl(A)
+ dblB = CDbl(B)
+ dblTolerance = Abs(CDbl(pvArg))
+ bEval = ( Abs(dblA - dblB) &lt;= (dblTolerance * Iif(Abs(dblA) &gt; Abs(DblB), Abs(dblA), Abs(dblB))) )
+ End If
+ Case UCase(&quot;AssertEqual&quot;), UCase(&quot;AssertNotEqual&quot;)
+ If Not IsArray(A) Then
+ bEval = ( iVarTypeA = iVarTypeB )
+ If bEval Then
+ Select Case iVarTypeA
+ Case V_EMPTY, V_NULL
+ Case V_STRING
+ bEval = ( StrComp(A, B, 1) = 0 )
+ Case ScriptForge.V_NUMERIC, ScriptForge.V_BOOLEAN
+ bEval = ( A = B )
+ Case V_DATE
+ bEval = ( Abs(DateDiff(&quot;s&quot;, A, B)) = 0 )
+ Case ScriptForge.V_OBJECT
+ Set oVarTypeObjA = oUtils._VarTypeObj(A)
+ Set oVarTypeObjB = oUtils._VarTypeObj(B)
+ bEval = ( oVarTypeObjA.iVarType = oVarTypeObjB.iVarType )
+ If bEval Then
+ Select Case oVarTypeObjA.iVarType
+ Case ScriptForge.V_NOTHING
+ Case ScriptForge.V_UNOOBJECT
+ bEval = EqualUnoObjects(A, B)
+ Case ScriptForge.V_SFOBJECT, ScriptForge.V_BASICOBJECT
+ bEval = False
+ End Select
+ End If
+ End Select
+ End If
+ Else &apos; Compare arrays
+ bEval = IsArray(B)
+ If bEval Then
+ iDims = ScriptForge.SF_Array.CountDims(A)
+ bEval = ( iDims = ScriptForge.SF_Array.CountDims(B) And iDims &lt;= 2 )
+ If bEval Then
+ Select Case iDims
+ Case -1, 0 &apos; Scalars (not possible) or empty arrays
+ Case 1 &apos; 1D array
+ bEval = ( LBound(A) = LBound(B) And UBound(A) = UBound(B) )
+ If bEval Then
+ For i = LBound(A) To UBound(A)
+ bEval = _Assert(psAssert, Empty, A(i), B(i))
+ If Not bEval Then Exit For
+ Next i
+ End If
+ Case 2 &apos; 2D array
+ bEval = ( LBound(A, 1) = LBound(B, 1) And UBound(A, 1) = UBound(B, 1) _
+ And LBound(A, 2) = LBound(B, 2) And UBound(A, 2) = UBound(B, 2) )
+ If bEval Then
+ For i = LBound(A, 1) To UBound(A, 1)
+ For j = LBound(A, 2) To UBound(A, 2)
+ bEval = _Assert(psAssert, Empty, A(i, j), B(i, j))
+ If Not bEval Then Exit For
+ Next j
+ If Not bEval Then Exit For
+ Next i
+ End If
+ End Select
+ End If
+ End If
+ End If
+ Case UCase(&quot;AssertFalse&quot;)
+ If iVarTypeA = ScriptForge.V_BOOLEAN Then bEval = Not A Else bEval = False
+ Case UCase(&quot;AssertGreater&quot;), UCase(&quot;AssertLessEqual&quot;)
+ bEval = ( iVarTypeA = iVarTypeB _
+ And (iVarTypeA = ScriptForge.V_NUMERIC Or iVarTypeA = V_STRING Or iVarTypeA = V_DATE) )
+ If bEval Then bEval = ( A &gt; B )
+ Case UCase(&quot;AssertGreaterEqual&quot;), UCase(&quot;AssertLess&quot;)
+ bEval = ( iVarTypeA = iVarTypeB _
+ And (iVarTypeA = ScriptForge.V_NUMERIC Or iVarTypeA = V_STRING Or iVarTypeA = V_DATE) )
+ If bEval Then bEval = ( A &gt;= B )
+ Case UCase(&quot;AssertIn&quot;), UCase(&quot;AssertNotIn&quot;)
+ Set oVarTypeObjB = oUtils._VarTypeObj(B)
+ Select Case True
+ Case iVarTypeA = V_STRING And iVarTypeB = V_STRING
+ bEval = ( Len(A) &gt; 0 And Len(B) &gt; 0 )
+ If bEval Then bEval = ( InStr(1, B, A, 0) &gt; 0 )
+ Case (iVarTypeA = V_DATE Or iVarTypeA = V_STRING Or iVarTypeA = ScriptForge.V_NUMERIC) _
+ And iVarTypeB &gt;= ScriptForge.V_ARRAY
+ bEval = ( ScriptForge.SF_Array.CountDims(B) = 1 )
+ If bEval Then bEval = ScriptForge.SF_Array.Contains(B, A, CaseSensitive := True)
+ Case oVarTypeObjB.iVarType = ScriptForge.V_SFOBJECT And oVarTypeObjB.sObjectType = &quot;DICTIONARY&quot;
+ bEval = ( Len(A) &gt; 0 )
+ If bEval Then
+ Set oAliasB = B
+ bEval = ScriptForge.SF_Array.Contains(oAliasB.Keys(), A, CaseSensitive := True)
+ End If
+ Case Else
+ bEval = False
+ End Select
+ Case UCase(&quot;AssertIsInstance&quot;), UCase(&quot;AssertNotInstance&quot;)
+ Set oVarTypeObjA = oUtils._VarTypeObj(A)
+ sArgName = &quot;ObjectType&quot;
+ With oVarTypeObjA
+ Select Case .iVarType
+ Case ScriptForge.V_UNOOBJECT
+ bEval = ( pvArg = .sObjectType )
+ Case ScriptForge.V_SFOBJECT
+ bEval = ( UCase(pvArg) = UCase(.sObjectType) Or UCase(pvArg) = &quot;SF_&quot; &amp; UCase(.sObjectType) _
+ Or UCase(pvArg) = UCase(.sServiceName) )
+ Case ScriptForge.V_NOTHING, ScriptForge.V_BASICOBJECT
+ bEval = False
+ Case &gt;= ScriptForge.V_ARRAY
+ bEval = ( UCase(pvArg) = &quot;ARRAY&quot; )
+ Case Else
+ bEval = ( UCase(TypeName(A)) = UCase(pvArg) )
+ End Select
+ End With
+ Case UCase(&quot;AssertIsNothing&quot;), UCase(&quot;AssertNotNothing&quot;)
+ bEval = ( iVarTypeA = ScriptForge.V_OBJECT )
+ If bEval Then bEval = ( A Is Nothing )
+ Case UCase(&quot;AssertIsNull&quot;), UCase(&quot;AssertNotNull&quot;)
+ bEval = ( iVarTypeA = V_NULL )
+ Case UCase(&quot;AssertLike&quot;), UCase(&quot;AssertNotLike&quot;)
+ sArgName = &quot;Pattern&quot;
+ bEval = ( iVarTypeA = V_STRING And Len(pvArg) &gt; 0 )
+ If bEval Then bEval = oString.IsLike(A, pvArg, CaseSensitive := True)
+ Case UCase(&quot;AssertRegex&quot;), UCase(&quot;AssertNotRegex&quot;)
+ sArgName = &quot;Regex&quot;
+ bEval = ( iVarTypeA = V_STRING And Len(pvArg) &gt; 0 )
+ If bEval Then bEval = oString.IsRegex(A, pvArg, CaseSensitive := True)
+ Case UCase(&quot;AssertTrue&quot;)
+ If iVarTypeA = ScriptForge.V_BOOLEAN Then bEval = A Else bEval = False
+ Case UCase(&quot;FAIL&quot;), UCase(&quot;Log&quot;)
+ bEval = True
+ Case Else
+ End Select
+
+ &apos; Check the result of the assertion vs. what it should be
+ If IsEmpty(pvReturn) Then
+ bAssert = bEval &apos; Recursive call =&gt; Reporting and failure management are done by calling _Assert() procedure
+ Else &apos; pvReturn is Boolean =&gt; Call from user script
+ bAssert = Iif(pvReturn, bEval, Not bEval)
+ &apos; Report the assertion evaluation
+ If _Verbose Or Not bAssert Then
+ _ReportMessage(&quot; &quot; &amp; psAssert _
+ &amp; Iif(IsEmpty(A), &quot;&quot;, &quot; = &quot; &amp; bAssert &amp; &quot;, A = &quot; &amp; oUtils._Repr(A)) _
+ &amp; Iif(IsEmpty(B), &quot;&quot;, &quot;, B = &quot; &amp; oUtils._Repr(B)) _
+ &amp; Iif(Len(sArgName) = 0, &quot;&quot;, &quot;, &quot; &amp; sArgName &amp; &quot; = &quot; &amp; pvArg) _
+ , pvMessage)
+ End If
+ &apos; Manage assertion failure
+ If Not bAssert Then
+ _FailedAssert = psAssert
+ Select Case _WhenAssertionFails
+ Case FAILIGNORE &apos; Do nothing
+ Case Else
+ _ReturnCode = RCASSERTIONFAILED
+ &apos; Cause artificially a run-time error
+ Dim STRINGBADUSE As String
+
+ &apos;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ &apos;+ To avoid a run-time error on next executable statement, +
+ &apos;+ insert an error handler in the code of your test case: +
+ &apos;+ Like in next code: +
+ &apos;+ On Local Error GoTo Catch +
+ &apos;+ ... +
+ &apos;+ Catch: +
+ &apos;+ myTest.ReportError() +
+ &apos;+ Exit Sub +
+ &apos;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ STRINGBADUSE = Right(&quot;&quot;, -1) &apos; Raises &quot;#5 - Invalid procedure call&quot; error
+
+ End Select
+ End If
+ End If
+
+Finally:
+ _Assert = bAssert
+ Exit Function
+
+End Function &apos; SFUnitTests.SF_UnitTest._Assert
+
+REM -----------------------------------------------------------------------------
+Private Function _Duration(ByVal psTimer As String _
+ , Optional ByVal pvBrackets As Variant _
+ ) As String
+&apos;&apos;&apos; Return the Duration property of the given timer
+&apos;&apos;&apos; or the empty string if the timer is undefined or not started
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psTimer: &quot;Test&quot;, &quot;Suite&quot; or &quot;TestCase&quot;
+&apos;&apos;&apos; pbBrackets: surround with brackets when True. Default = False
+
+Dim sDuration As String &apos; Return value
+Dim oTimer As Object &apos; Alias of psTimer
+
+Check:
+ If IsMissing(pvBrackets) Or IsEmpty(pvBrackets) Then pvBrackets = False
+
+Try:
+ Select Case psTimer
+ Case &quot;Test&quot; : Set oTimer = TestTimer
+ Case &quot;Suite&quot; : Set oTimer = SuiteTimer
+ Case &quot;TestCase&quot;, &quot;Case&quot; : Set oTimer = CaseTimer
+ End Select
+ If Not IsNull(oTimer) Then
+ sDuration = CStr(oTimer.Duration) &amp; &quot; &quot;
+ If pvBrackets Then sDuration = &quot;(&quot; &amp; Trim(sDuration) &amp; &quot; sec)&quot;
+ Else
+ sDuration = &quot;&quot;
+ End If
+
+Finally:
+ _Duration = sDuration
+End Function &apos; SFUnitTests.SF_UnitTest._Duration
+
+REM -----------------------------------------------------------------------------
+Private Function _ExecuteScript(psMethod As String) As Boolean
+&apos;&apos;&apos; Run the given method and report start and stop
+&apos;&apos;&apos; The targeted method is presumed not to return anything (Sub)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMethod: the scope, the library and the module are predefined in the instance internals
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+
+Dim bExecute As Boolean &apos; Return value
+Dim sRun As String &apos; SETUP, TEARDOWN or TESTCASE
+
+ On Local Error GoTo Catch
+ bExecute = True
+
+Try:
+ &apos; Set status before the effective execution
+ sRun = UCase(psMethod)
+ Select Case UCase(psMethod)
+ Case &quot;SETUP&quot; : _Status = STATUSSETUP
+ Case &quot;TEARDOWN&quot; : _Status = STATUSTEARDOWN
+ Case Else : _Status = STATUSTESTCASE
+ sRun = &quot;TESTCASE&quot;
+ End Select
+
+ &apos; Report and execute
+ _ReportMessage(&quot; &quot; &amp; sRun &amp; &quot; &quot; &amp; LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;.&quot; &amp; psMethod &amp; &quot;() ENTER&quot;)
+ Session.ExecuteBasicScript(Scope, LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;.&quot; &amp; psMethod, [Me])
+ _ReportMessage(&quot; &quot; &amp; sRun &amp; &quot; &quot; &amp; LibraryName &amp; &quot;.&quot; &amp; _Module &amp; &quot;.&quot; &amp; psMethod &amp; &quot;() EXIT&quot; _
+ &amp; Iif(_STATUS = STATUSTESTCASE, &quot; &quot; &amp; _Duration(&quot;Case&quot;, True), &quot;&quot;))
+ &apos; Reset status
+ _Status = STATUSSUITESTARTED
+
+Finally:
+ _ExecuteScript = bExecute
+ Exit Function
+Catch:
+ bExecute = False
+ _ReturnCode = RCABORTTEST
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest._ExecuteScript
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String)
+&apos;&apos;&apos; Return the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+
+Dim cstThisSub As String
+Dim cstSubArgs As String
+
+ cstThisSub = &quot;UnitTest.get&quot; &amp; psProperty
+ cstSubArgs = &quot;&quot;
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;LongMessage&quot;)
+ _PropertyGet = _LongMessage
+ Case UCase(&quot;ReturnCode&quot;)
+ _PropertyGet = _ReturnCode
+ Case UCase(&quot;Verbose&quot;)
+ _PropertyGet = _Verbose
+ Case UCase(&quot;WhenAssertionFails&quot;)
+ _PropertyGet = _WhenAssertionFails
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFUnitTests.SF_UnitTest._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(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
+Dim vWhenFailure As Variant &apos; WhenAssertionFails allowed values
+Dim cstThisSub As String
+Const cstSubArgs = &quot;Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSet = False
+
+ cstThisSub = &quot;SFUnitTests.UnitTest.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;LongMessage&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;LongMessage&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ _LongMessage = pvValue
+ Case UCase(&quot;Verbose&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Verbose&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ _Verbose = pvValue
+ Case UCase(&quot;WhenAssertionFails&quot;)
+ If _ExecutionMode = SIMPLEMODE Then vWhenFailure = Array(0, 3) Else vWhenFailure = Array(0, 1, 2, 3)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;WhenAssertionFails&quot;, ScriptForge.V_NUMERIC, vWhenFailure) Then GoTo Finally
+ _WhenAssertionFails = pvValue
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _ReportMessage(ByVal psSysMessage As String _
+ , Optional ByVal pvMessage As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Report in the console:
+&apos;&apos;&apos; - either the standard message
+&apos;&apos;&apos; - either the user message when not blank
+&apos;&apos;&apos; - or both
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psSysMessage: the standard message as built by the calling routine
+&apos;&apos;&apos; psMessage: the message provided by the user script
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+
+Dim bReport As Boolean &apos; Return value
+Dim sIndent As String &apos; Indentation spaces
+
+ bReport = False
+ On Local Error GoTo Catch
+ If IsMissing(pvMessage) Or IsEmpty(pvMessage) Then pvMessage = &quot;&quot;
+
+Try:
+ Select Case True
+ Case Len(pvMessage) = 0
+ Exception.DebugPrint(psSysMessage)
+ Case _LongMessage
+ Exception.DebugPrint(psSysMessage, pvMessage)
+ Case Else
+ Select Case _Status
+ Case STATUSSTANDBY, STATUSSUITESTARTED : sIndent = &quot;&quot;
+ Case STATUSSUITESTARTED : sIndent = Space(2)
+ Case Else : sIndent = Space(4)
+ End Select
+ Exception.DebugPrint(sIndent &amp; pvMessage)
+ End Select
+
+Finally:
+ _ReportMessage = bReport
+ Exit Function
+Catch:
+ bReport = False
+ GoTo Finally
+End Function &apos; SFUnitTests.SF_UnitTest._ReportMessage
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the UnitTest instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[UnitTest]
+
+Const cstUnitTest = &quot;[UnitTest]&quot;
+Const cstMaxLength = 50 &apos; Maximum length for items
+
+ _Repr = cstUnitTest
+
+End Function &apos; SFUnitTests.SF_UnitTest._Repr
+
+REM ============================================== END OF SFUNITTESTS.SF_UNITTEST
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfunittests/__License.xba b/wizards/source/sfunittests/__License.xba
new file mode 100644
index 000000000..a8e6a7779
--- /dev/null
+++ b/wizards/source/sfunittests/__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-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFUnitTests 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/sfunittests/dialog.xlb b/wizards/source/sfunittests/dialog.xlb
new file mode 100644
index 000000000..2d4a57045
--- /dev/null
+++ b/wizards/source/sfunittests/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="SFUnitTests" library:readonly="false" library:passwordprotected="false"/> \ No newline at end of file
diff --git a/wizards/source/sfunittests/script.xlb b/wizards/source/sfunittests/script.xlb
new file mode 100644
index 000000000..3292dc12c
--- /dev/null
+++ b/wizards/source/sfunittests/script.xlb
@@ -0,0 +1,7 @@
+<?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="SFUnitTests" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="__License"/>
+ <library:element library:name="SF_UnitTest"/>
+ <library:element library:name="SF_Register"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_Menu.xba b/wizards/source/sfwidgets/SF_Menu.xba
new file mode 100644
index 000000000..e21168536
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_Menu.xba
@@ -0,0 +1,590 @@
+<?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_Menu" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFWidgets 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_Menu
+&apos;&apos;&apos; ============
+&apos;&apos;&apos; Display a menu in the menubar of a document or a form document.
+&apos;&apos;&apos; After use, the menu will not be saved neither in the application settings, nor in the document.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The menu will be displayed, as usual, when its header in the menubar is clicked.
+&apos;&apos;&apos; When one of its items is selected, there are 3 alternative options:
+&apos;&apos;&apos; - a UNO command (like &quot;.uno:About&quot;) is triggered
+&apos;&apos;&apos; - a user script is run receiving a standard argument defined in this service
+&apos;&apos;&apos; - one of above combined with a toggle of the status of the item
+&apos;&apos;&apos;
+&apos;&apos;&apos; The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Menu items are either:
+&apos;&apos;&apos; - usual items
+&apos;&apos;&apos; - checkboxes
+&apos;&apos;&apos; - radio buttons
+&apos;&apos;&apos; - a menu separator
+&apos;&apos;&apos; Menu items can be decorated with icons and tooltips.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; SubmenuCharacter: the character or the character string that identifies how menus are cascading
+&apos;&apos;&apos; Default = &quot;&gt;&quot;
+&apos;&apos;&apos; Can be set when invoking the Menu service
+&apos;&apos;&apos; ShortcutCharacter: the underline access key character
+&apos;&apos;&apos; Default = &quot;~&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; Menus and submenus
+&apos;&apos;&apos; To create a menu with submenus, use the character defined in the
+&apos;&apos;&apos; SubmenuCharacter property while creating the menu entry to define where it will be
+&apos;&apos;&apos; placed. For instance, consider the following menu/submenu hierarchy.
+&apos;&apos;&apos; Item A
+&apos;&apos;&apos; Item B &gt; Item B.1
+&apos;&apos;&apos; Item B.2
+&apos;&apos;&apos; ------ (line separator)
+&apos;&apos;&apos; Item C &gt; Item C.1 &gt; Item C.1.1
+&apos;&apos;&apos; Item C.1.2
+&apos;&apos;&apos; Item C &gt; Item C.2 &gt; Item C.2.1
+&apos;&apos;&apos; Item C.2.2
+&apos;&apos;&apos; Next code will create the menu/submenu hierarchy
+&apos;&apos;&apos; With myMenu
+&apos;&apos;&apos; .AddItem(&quot;Item A&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;---&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.2&quot;)
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation:
+&apos;&apos;&apos; Dim ui As Object, oDoc As Object, myMenu As Object
+&apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
+&apos;&apos;&apos; Set oDoc = ui.GetDocument(ThisComponent)
+&apos;&apos;&apos; Set myMenu = oDoc.CreateMenu(&quot;My own menu&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/SF_Menu.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private ObjectType As String &apos; Must be MENU
+Private ServiceName As String
+
+
+&apos; Menu descriptors
+Private Component As Object &apos; the com.sun.star.lang.XComponent hosting the menu in its menubar
+Private MenuBar As Object &apos; com.sun.star.awt.XMenuBar or stardiv.Toolkit.VCLXMenuBar
+Private SubmenuChar As String &apos; Delimiter in menu trees
+Private MenuHeader As String &apos; Header of the menu
+Private MenuId As Integer &apos; Menu numeric identifier in the menubar
+Private MenuPosition As Integer &apos; Position of the menu on the menubar &gt;= 1
+Private PopupMenu As Object &apos; The underlying popup menu as a SF_PopupMenu object
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const _UnderlineAccessKeyChar = &quot;~&quot;
+Private Const _DefaultSubmenuChar = &quot;&gt;&quot;
+Private Const cstUnoPrefix = &quot;.uno:&quot;
+Private Const cstScriptArg = &quot;:::&quot;
+Private Const cstNormal = &quot;N&quot;
+Private Const cstCheck = &quot;C&quot;
+Private Const cstRadio = &quot;R&quot;
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ ObjectType = &quot;MENU&quot;
+ ServiceName = &quot;SFWidgets.Menu&quot;
+ Set Component = Nothing
+ Set MenuBar = Nothing
+ SubmenuChar = _DefaultSubmenuChar
+ MenuHeader = &quot;&quot;
+ MenuId = -1
+ MenuPosition = 0
+ Set PopupMenu = Nothing
+End Sub &apos; SFWidgets.SF_Menu Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFWidgets.SF_Menu Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ PopupMenu.Dispose()
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFWidgets.SF_Menu Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ShortcutCharacter() As Variant
+&apos;&apos;&apos; The ShortcutCharacter property specifies character preceding the underline access key
+ ShortcutCharacter = _PropertyGet(&quot;ShortcutCharacter&quot;)
+End Property &apos; SFWidgets.SF_Menu.ShortcutCharacter (get)
+
+REM -----------------------------------------------------------------------------
+Property Get SubmenuCharacter() As Variant
+&apos;&apos;&apos; The SubmenuCharacter property specifies the character string indicating
+&apos;&apos;&apos; a sub-menu in a popup menu item
+ SubmenuCharacter = _PropertyGet(&quot;SubmenuCharacter&quot;)
+End Property &apos; SFWidgets.SF_Menu.SubmenuCharacter (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function AddCheckBox(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Status As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ , Optional ByVal Command As Variant _
+ , Optional ByVal Script As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry as a checkbox
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name identifying the item. Default = the last component of MenuItem.
+&apos;&apos;&apos; Status: when True the item is selected. Default = False
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: A menu command like &quot;.uno:About&quot;. The validity of the command is not checked.
+&apos;&apos;&apos; Script: a Basic or Python script (determined by its URI notation) to be run when the item is clicked
+&apos;&apos;&apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Next string argument will be passed to the called script : a comma-separated string of 4 components:
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the clicked menu item
+&apos;&apos;&apos; - the numeric identifier of the clicked menu item
+&apos;&apos;&apos; - &quot;1&quot; when the status is &quot;checked&quot;, otherwise &quot;0&quot;
+&apos;&apos;&apos; Arguments Command and Script are mutually exclusive.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim iId As Integer
+&apos;&apos;&apos; iId = myMenu.AddCheckBox(&quot;Menu top&gt;Checkbox item&quot;, Status := True, Command := &quot;Bold&quot;)
+
+Dim iId As Integer &apos; Return value
+Dim sCommand As String &apos; Alias of either Command or Script
+
+
+Const cstThisSub = &quot;SFWidgets.Menu.AddCheckBox&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;], [Command=&quot;&quot;&quot;&quot;], [Script=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Status) Or IsEmpty(Status) Then Status = False
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If IsMissing(Command) Or IsEmpty(Command) Then Command = &quot;&quot;
+ If IsMissing(Script) Or IsEmpty(Script) Then Script = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Status, &quot;Status&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Catch
+ End If
+
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then sCommand = Command Else sCommand = cstUnoPrefix &amp; Command
+ Else
+ sCommand = Script &amp; cstScriptArg &amp; MenuHeader
+ End If
+
+Try:
+ iId = PopupMenu._AddItem(MenuItem, Name, cstCheck, Status, Icon, Tooltip, sCommand)
+
+Finally:
+ AddCheckBox = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.AddCheckBox
+
+REM -----------------------------------------------------------------------------
+Public Function AddItem(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ , Optional ByVal Command As Variant _
+ , Optional ByVal Script As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to &quot;---&quot;, a line separator is inserted and all other arguments are ignored
+&apos;&apos;&apos; Name: The name identifying the item. Default = the last component of MenuItem.
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: A menu command like &quot;.uno:About&quot;. The validity of the command is not checked.
+&apos;&apos;&apos; Script: a Basic or Python script (determined by its URI notation) to be run when the item is clicked
+&apos;&apos;&apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Next string argument will be passed to the called script : a comma-separated string of 4 components:
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the clicked menu item
+&apos;&apos;&apos; - the numeric identifier of the clicked menu item
+&apos;&apos;&apos; - &quot;0&quot;
+&apos;&apos;&apos; Arguments Command and Script are mutually exclusive.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim iId1 As Integer, iId2 As Integer
+&apos;&apos;&apos; iId1 = myMenu.AddItem(&quot;Menu top&gt;Normal item 1&quot;, Icon := &quot;cmd.sc_cut.png&quot;, Command := &quot;About&quot;)
+&apos;&apos;&apos; iId2 = myMenu.AddItem(&quot;Menu top&gt;Normal item 2&quot;, Script := &quot;vnd.sun.star.script:myLib.Module1.ThisSub?language=Basic&amp;location=document&quot;)
+
+Dim iId As Integer &apos; Return value
+Dim sCommand As String &apos; Alias of either Command or Script
+
+Const cstThisSub = &quot;SFWidgets.Menu.AddItem&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;], [Command=&quot;&quot;&quot;&quot;], [Script=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If IsMissing(Command) Or IsEmpty(Command) Then Command = &quot;&quot;
+ If IsMissing(Script) Or IsEmpty(Script) Then Script = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Catch
+ End If
+
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then sCommand = Command Else sCommand = cstUnoPrefix &amp; Command
+ Else
+ sCommand = Script &amp; cstScriptArg &amp; MenuHeader
+ End If
+
+Try:
+ iId = PopupMenu._AddItem(MenuItem, Name, cstNormal, False, Icon, Tooltip, sCommand)
+
+Finally:
+ AddItem = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.AddItem
+
+REM -----------------------------------------------------------------------------
+Public Function AddRadioButton(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Status As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ , Optional ByVal Command As Variant _
+ , Optional ByVal Script As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry as a radio button
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hieAddCheckBoxrarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name identifying the item. Default = the last component of MenuItem.
+&apos;&apos;&apos; Status: when True the item is selected. Default = False
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: A menu command like &quot;.uno:About&quot;. The validity of the command is not checked.
+&apos;&apos;&apos; Script: a Basic or Python script (determined by its URI notation) to be run when the item is clicked
+&apos;&apos;&apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Next string argument will be passed to the called script : a comma-separated string of 4 components:
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the clicked menu item
+&apos;&apos;&apos; - the numeric identifier of theclicked menu item
+&apos;&apos;&apos; - &quot;1&quot; when the status is &quot;checked&quot;, otherwise &quot;0&quot;
+&apos;&apos;&apos; Arguments Command and Script are mutually exclusive.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim iId As Integer
+&apos;&apos;&apos; iId = myMenu.AddRadioButton(&quot;Menu top&gt;Radio item&quot;, Status := True, Command := &quot;Bold&quot;)
+
+Dim iId As Integer &apos; Return value
+Dim sCommand As String &apos; Alias of either Command or Script
+
+Const cstThisSub = &quot;SFWidgets.Menu.AddRadioButton&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;], [Command=&quot;&quot;&quot;&quot;], [Script=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Status) Or IsEmpty(Status) Then Status = False
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If IsMissing(Command) Or IsEmpty(Command) Then Command = &quot;&quot;
+ If IsMissing(Script) Or IsEmpty(Script) Then Script = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Status, &quot;Status&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Catch
+ End If
+
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then sCommand = Command Else sCommand = cstUnoPrefix &amp; Command
+ Else
+ sCommand = Script &amp; cstScriptArg &amp; MenuHeader
+ End If
+
+Try:
+ iId = PopupMenu._AddItem(MenuItem, Name, cstRadio, Status, Icon, Tooltip, sCommand)
+
+Finally:
+ AddRadioButton = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.AddRadioButton
+
+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;SFWidgets.Menu.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; SFWidgets.SF_Menu.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;AddCheckBox&quot; _
+ , &quot;AddItem&quot; _
+ , &quot;AddRadioButton&quot; _
+ )
+
+End Function &apos; SFWidgets.SF_Menu.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer a.AddItem(&quot;B&gt;B1&quot;)class as an array
+
+ Properties = Array( _
+ &quot;ShortcutCharacter&quot; _
+ , &quot;SubmenuCharacter&quot; _
+ )
+
+End Function &apos; SFWidgets.SF_Menu.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;SFWidgets.Menu.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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize(ByRef poComponent As Object _
+ , psMenuHeader As String _
+ , psBefore As String _
+ , piBefore As Integer _
+ , psSubmenuChar As String _
+ )
+&apos;&apos;&apos; Complete the object creation process:
+&apos;&apos;&apos; - Initialize the internal properties
+&apos;&apos;&apos; - Initialize the menubar
+&apos;&apos;&apos; - Determine the position and the internal id of the new menu
+&apos;&apos;&apos; - Create the menu and its attached popup menu
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poComponent: the parent component where the menubar is to be searched for
+&apos;&apos;&apos; psMenuHeader: the header of the new menu. May or not contain a tilde &quot;~&quot;
+&apos;&apos;&apos; psBefore, piBefore: the menu before which to create the new menu, as a string or as a number
+&apos;&apos;&apos; psSubmenuChar: the submenus separator
+
+Dim oLayout As Object &apos; com.sun.star.comp.framework.LayoutManager
+Dim sName As String &apos; Menu name
+Dim iMenuId As Integer &apos; Menu identifier
+Dim i As Integer
+Const cstTilde = &quot;~&quot;
+
+Try:
+ &apos; Initialize the menubar
+ Set oLayout = poComponent.CurrentController.Frame.LayoutManager
+ Set MenuBar = oLayout.getElement(&quot;private:resource/menubar/menubar&quot;).XMenuBar
+
+ &apos; Determine the new menu identifier and its position
+ &apos; Identifier = largest current identifier + 1
+ MenuHeader = psMenuHeader
+ With MenuBar
+ For i = 0 To .ItemCount - 1
+ iMenuId = .getItemId(i)
+ If iMenuId &gt;= MenuId Then MenuId = iMenuId + 1
+ If piBefore &gt; 0 And piBefore = i + 1 Then
+ MenuPosition = piBefore
+ Else
+ sName = .getItemText(iMenuId)
+ If sName = psBefore Or Replace(sName, cstTilde, &quot;&quot;) = psBefore Then MenuPosition = i + 1
+ End If
+ Next i
+ If MenuPosition = 0 Then MenuPosition = .ItemCount + 1
+ End With
+
+ &apos; Store the submenu character
+ If Len(psSubmenuChar) &gt; 0 Then SubmenuChar = psSubmenuChar
+
+ &apos; Create the menu and the attached top popup menu
+ MenuBar.insertItem(MenuId, MenuHeader, 0, MenuPosition - 1)
+ PopupMenu = SFWidgets.SF_Register._NewPopupMenu(Array(Nothing, 0, 0, SubmenuChar))
+ PopupMenu.MenubarMenu = True &apos; Special indicator for menus depending on menubar
+ MenuBar.setPopupMenu(MenuId, PopupMenu.MenuRoot)
+
+ &apos; Initialize the listener on the top branch
+ SFWidgets.SF_MenuListener.SetMenuListener(PopupMenu.MenuRoot)
+
+Finally:
+ Exit Sub
+End Sub &apos; SFWidgets.SF_Menu._Initialize
+
+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 vGet As Variant &apos; Return value
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFWidgets.Menu.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ _PropertyGet = Null
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;ShortcutCharacter&quot;)
+ _PropertyGet = _UnderlineAccessKeyChar
+ Case UCase(&quot;SubmenuCharacter&quot;)
+ _PropertyGet = SubmenuChar
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_Menu instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Menu]: Name, Type (dialogname)
+ _Repr = &quot;[Menu]: &quot; &amp; SF_String.Represent(PopupMenu.MenuTree.Keys()) &amp; &quot;, &quot; &amp; SF_String.Represent(PopupMenu.MenuIdentification.Items())
+
+End Function &apos; SFWidgets.SF_Menu._Repr
+
+REM ============================================ END OF SFWIDGETS.SF_MENU
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_MenuListener.xba b/wizards/source/sfwidgets/SF_MenuListener.xba
new file mode 100644
index 000000000..6045f2dd8
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_MenuListener.xba
@@ -0,0 +1,129 @@
+<?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_MenuListener" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFWidgets 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_MenuListener
+&apos;&apos;&apos; ===============
+&apos;&apos;&apos; The current module is dedicated to the management of menu events + listeners, triggered by user actions,
+&apos;&apos;&apos; which cannot be defined with the Basic IDE
+&apos;&apos;&apos;
+&apos;&apos;&apos; Concerned listeners:
+&apos;&apos;&apos; com.sun.star.awt.XMenuListener
+&apos;&apos;&apos; allowing a user to select a menu command in user menus preset in the menubar
+&apos;&apos;&apos;
+&apos;&apos;&apos; The described events/listeners are processed by UNO listeners
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ============================================================= PRIVATE MEMBERS
+
+Dim MenuListener As Object &apos; com.sun.star.awt.XMenuListener
+
+REM =========================================================== PRIVATE CONSTANTS
+
+Private Const _MenuListenerPrefix = &quot;_SFMENU_&quot;
+Private Const _MenuListener = &quot;com.sun.star.awt.XMenuListener&quot;
+Private Const cstUnoPrefix = &quot;.uno:&quot;
+Private Const cstScriptArg = &quot;:::&quot;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Sub SetMenuListener(poSubmenu As Object)
+&apos;&apos;&apos; Arm a menu listener on a submenu
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poSubmenu: the targeted submenu
+
+Try:
+ If IsNull(MenuListener) Then Set MenuListener = CreateUnoListener(_MenuListenerPrefix, _MenuListener)
+ poSubmenu.addMenuListener(MenuListener)
+
+Finally:
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener.SetMenuListener
+
+REM ============================================================= PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Sub _SFMENU_itemSelected(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+&apos;&apos;&apos; Execute the command or the script associated with the actually selected item
+&apos;&apos;&apos; When a script, next argument is provided:
+&apos;&apos;&apos; a comma-separated string with 4 components
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the selected menu entry (without tilde &quot;~&quot;)
+&apos;&apos;&apos; - the numeric identifier of the selected menu entry
+&apos;&apos;&apos; - the new status of the selected menu entry (&quot;0&quot; or &quot;1&quot;). Always &quot;0&quot; for usual items.
+
+Dim iMenuId As Integer
+Dim oMenu As Object &apos; stardiv.Toolkit.VCLXPopupMenu
+Dim sCommand As String &apos; Command associated with menu entry
+Dim bType As Boolean &apos; True when status is meaningful: item is radio button or checkbox
+Dim bStatus As Boolean &apos; Status of the menu item, always False for normal items
+Dim oFrame As Object &apos; com.sun.star.comp.framework.Frame
+Dim oDispatcher As Object &apos; com.sun.star.frame.DispatchHelper
+Dim oSession As Object &apos; SF_Session service
+Dim vScript As Variant &apos; Split command in script/argument
+Dim oArgs() As new com.sun.star.beans.PropertyValue
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Try:
+ iMenuId = poEvent.MenuId
+ oMenu = poEvent.Source
+
+ With oMenu
+ &apos; Collect command (script or menu command) and status radiobuttons and checkboxes
+ sCommand = .getCommand(iMenuId)
+ bStatus = .isItemChecked(iMenuId)
+ End With
+
+ If Len(sCommand) &gt; 0 Then
+ If Left(sCommand, Len(cstUnoPrefix)) = cstUnoPrefix Then
+ &apos; Execute uno command
+ Set oFrame = StarDesktop.CurrentComponent.CurrentController.Frame &apos; A menu has been clicked necessarily in the current window
+ Set oDispatcher = ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
+ oDispatcher.executeDispatch(oFrame, sCommand, &quot;&quot;, 0, oArgs())
+ oFrame.activate()
+ Else
+ &apos; Execute script
+ Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ vScript = Split(sCommand, cstScriptArg)
+ oSession._ExecuteScript(vScript(0), vScript(1) &amp; &quot;,&quot; &amp; Iif(bStatus, &quot;1&quot;, &quot;0&quot;)) &apos; Return value is ignored
+ End If
+ End If
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemSelected
+
+REM -----------------------------------------------------------------------------
+Sub _SFMENU_itemHighlighted(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemHighlighted
+
+Sub _SFMENU_itemActivated(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemActivated
+
+Sub _SFMENU_itemDeactivated(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemDeactivated
+
+Sub _SFMENU_disposing(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_disposing
+
+REM ============================================ END OF SFDIALOGS.SF_DIALOGLISTENER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_PopupMenu.xba b/wizards/source/sfwidgets/SF_PopupMenu.xba
new file mode 100644
index 000000000..3d5ba65a8
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_PopupMenu.xba
@@ -0,0 +1,801 @@
+<?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_PopupMenu" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFWidgets 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_PopupMenu
+&apos;&apos;&apos; ============
+&apos;&apos;&apos; Display a popup menu anywhere and any time
+&apos;&apos;&apos;
+&apos;&apos;&apos; A popup menu is usually triggered by a mouse action (typically a right-click) on a dialog, a form
+&apos;&apos;&apos; or one of their controls. In this case the menu will be displayed below the clicked area.
+&apos;&apos;&apos; When triggered by other events, including in the normal flow of a user script, the script should
+&apos;&apos;&apos; provide the coordinates of the topleft edge of the menu versus the actual component.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
+&apos;&apos;&apos; The Execute() method returns the item selected by the user.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Menu items are either:
+&apos;&apos;&apos; - usual items
+&apos;&apos;&apos; - checkboxes
+&apos;&apos;&apos; - radio buttons
+&apos;&apos;&apos; - a menu separator
+&apos;&apos;&apos; Menu items can be decorated with icons and tooltips.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; SubmenuCharacter: the character or the character string that identifies how menus are cascading
+&apos;&apos;&apos; Default = &quot;&gt;&quot;
+&apos;&apos;&apos; Can be set when invoking the PopupMenu service
+&apos;&apos;&apos; ShortcutCharacter: the underline access key character
+&apos;&apos;&apos; Default = &quot;~&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation:
+&apos;&apos;&apos; Sub OpenMenu(Optional poMouseEvent As Object)
+&apos;&apos;&apos; Dim myMenu As Object
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poMouseEvent, , , &quot;&gt;&gt;&quot;) &apos; Usual case
+&apos;&apos;&apos; &apos; or
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, , X, Y, &quot; | &quot;) &apos; Use X and Y coordinates to place the menu
+&apos;&apos;&apos;
+&apos;&apos;&apos; Menus and submenus
+&apos;&apos;&apos; To create a popup menu with submenus, use the character defined in the
+&apos;&apos;&apos; SubmenuCharacter property while creating the menu entry to define where it will be
+&apos;&apos;&apos; placed. For instance, consider the following menu/submenu hierarchy.
+&apos;&apos;&apos; Item A
+&apos;&apos;&apos; Item B &gt; Item B.1
+&apos;&apos;&apos; Item B.2
+&apos;&apos;&apos; ------ (line separator)
+&apos;&apos;&apos; Item C &gt; Item C.1 &gt; Item C.1.1
+&apos;&apos;&apos; Item C.1.2
+&apos;&apos;&apos; Item C &gt; Item C.2 &gt; Item C.2.1
+&apos;&apos;&apos; Item C.2.2
+&apos;&apos;&apos; Next code will create the menu/submenu hierarchy
+&apos;&apos;&apos; With myMenu
+&apos;&apos;&apos; .AddItem(&quot;Item A&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;---&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.2&quot;)
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Example 1: simulate a subset of the View menu in the menubar of the Basic IDE
+&apos;&apos;&apos; Sub OpenMenu(Optional poMouseEvent As Object)
+&apos;&apos;&apos; Dim myMenu As Object, vChoice As Variant
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poMouseEvent)
+&apos;&apos;&apos; With myMenu
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Dialog&quot;)
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Find&quot;, Status := True)
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Status Bar&quot;, Status := True)
+&apos;&apos;&apos; .AddItem(&quot;View&gt;Full Screen&quot;, Name := &quot;FULLSCREEN&quot;)
+&apos;&apos;&apos; vChoice = .Execute(False) &apos; When 1st checkbox is clicked, return &quot;Dialog&quot;
+&apos;&apos;&apos; &apos; When last item is clicked, return &quot;FULLSCREEN&quot;
+&apos;&apos;&apos; .Dispose()
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Example 2: jump to another sheet of a Calc document
+&apos;&apos;&apos; &apos; Link next Sub to the &quot;Mouse button released&quot; event of a form control of a Calc sheet
+&apos;&apos;&apos; Sub JumpToSheet(Optional poEvent As Object)
+&apos;&apos;&apos; Dim myMenu As Object, sChoice As String, myDoc As Object, vSheets As Variant, sSheet As String
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poEvent)
+&apos;&apos;&apos; Set myDoc = CreateScriptService(&quot;Calc&quot;, ThisComponent)
+&apos;&apos;&apos; vSheets = myDoc.Sheets
+&apos;&apos;&apos; For Each sSheet In vSheets
+&apos;&apos;&apos; myMenu.AddItem(sSheet)
+&apos;&apos;&apos; Next sSheet
+&apos;&apos;&apos; sChoice = myMenu.Execute(False) &apos; Return sheet name, not sheet index
+&apos;&apos;&apos; If sChoice &lt;&gt; &quot;&quot; Then myDoc.Activate(sChoice)
+&apos;&apos;&apos; myDoc.Dispose()
+&apos;&apos;&apos; myMenu.Dispose()
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos;
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_popupmenu.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private ObjectType As String &apos; Must be POPUPMENU
+Private ServiceName As String
+
+
+&apos; Menu descriptors
+Private MenuTree As Variant &apos; Dictionary treename - XPopupMenu pair
+Private MenuIdentification As Variant &apos; Dictionary item ID - item name
+Private SubmenuChar As String &apos; Delimiter in menu trees
+Private MenuRoot As Object &apos; stardiv.vcl.PopupMenu or com.sun.star.awt.XPopupMenu
+Private LastItem As Integer &apos; Every item has its entry number. This is the last one
+Private Rectangle As Object &apos; com.sun.star.awt.Rectangle
+Private PeerWindow As Object &apos; com.sun.star.awt.XWindowPeer
+Private MenubarMenu As Boolean &apos; When True, the actual popup menu depends on a menubar item
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const _UnderlineAccessKeyChar = &quot;~&quot;
+Private Const _DefaultSubmenuChar = &quot;&gt;&quot;
+Private Const _SeparatorChar = &quot;---&quot;
+Private Const _IconsDirectory = &quot;private:graphicrepository/&quot; &apos; Refers to &lt;install folder&gt;/share/config/images_*.zip.
+Private Const cstUnoPrefix = &quot;.uno:&quot;
+Private Const cstNormal = &quot;N&quot;
+Private Const cstCheck = &quot;C&quot;
+Private Const cstRadio = &quot;R&quot;
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ ObjectType = &quot;POPUPMENU&quot;
+ ServiceName = &quot;SFWidgets.PopupMenu&quot;
+ Set MenuTree = Nothing
+ Set MenuIdentification = Nothing
+ SubmenuChar = _DefaultSubmenuChar
+ Set MenuRoot = Nothing
+ LastItem = 0
+ Set Rectangle = Nothing
+ Set PeerWindow = Nothing
+ MenubarMenu = False
+End Sub &apos; SFWidgets.SF_PopupMenu Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFWidgets.SF_PopupMenu Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ If Not IsNull(MenuTree) Then Set MenuTree = MenuTree.Dispose()
+ If Not IsNull(MenuIdentification) Then Set MenuIdentification = MenuIdentification.Dispose()
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFWidgets.SF_PopupMenu Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ShortcutCharacter() As Variant
+&apos;&apos;&apos; The ShortcutCharacter property specifies character preceding the underline access key
+ ShortcutCharacter = _PropertyGet(&quot;ShortcutCharacter&quot;)
+End Property &apos; SFWidgets.SF_PopupMenu.ShortcutCharacter (get)
+
+REM -----------------------------------------------------------------------------
+Property Get SubmenuCharacter() As Variant
+&apos;&apos;&apos; The SubmenuCharacter property specifies the character string indicating
+&apos;&apos;&apos; a sub-menu in a popup menu item
+ SubmenuCharacter = _PropertyGet(&quot;SubmenuCharacter&quot;)
+End Property &apos; SFWidgets.SF_PopupMenu.SubmenuCharacter (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function AddCheckBox(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Status As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name to be returned by the Execute() method if this item is clicked
+&apos;&apos;&apos; Default = the last component of MenuItem
+&apos;&apos;&apos; Status: when True the item is selected. Default = False
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myMenu As Object, iId As Integer
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poEvent)
+&apos;&apos;&apos; iId = myMenu.AddCheckBox(&quot;Menu top&gt;Checkbox item&quot;, Status := True)
+
+Dim iId As Integer &apos; Return value
+
+Const cstThisSub = &quot;SFWidgets.PopupMenu.AddCheckBox&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Status) Or IsEmpty(Status) Then Status = False
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Status, &quot;Status&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ iId = _AddItem(MenuItem, Name, cstCheck, Status, Icon, Tooltip)
+
+Finally:
+ AddCheckBox = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu.AddCheckBox
+
+REM -----------------------------------------------------------------------------
+Public Function AddItem(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to &quot;---&quot;, a line separator is inserted and all other arguments are ignored
+&apos;&apos;&apos; Name: The name to be returned by the Execute() method if this item is clicked
+&apos;&apos;&apos; Default = the last component of MenuItem
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myMenu As Object, iId As Integer
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poEvent)
+&apos;&apos;&apos; iId = myMenu.AddItem(&quot;Menu top&gt;Normal item&quot;, Icon := &quot;cmd.sc_cut.png&quot;)
+
+Dim iId As Integer &apos; Return value
+
+Const cstThisSub = &quot;SFWidgets.PopupMenu.AddItem&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ iId = _AddItem(MenuItem, Name, cstNormal, False, Icon, Tooltip)
+
+Finally:
+ AddItem = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu.AddItem
+
+REM -----------------------------------------------------------------------------
+Public Function AddRadioButton(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Status As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry as a radio button
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hieAddCheckBoxrarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name to be returned by the Execute() method if this item is clicked
+&apos;&apos;&apos; Default = the last component of MenuItem
+&apos;&apos;&apos; Status: when True the item is selected. Default = False
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim myMenu As Object, iId As Integer
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poEvent)
+&apos;&apos;&apos; iId = myMenu.AddRadioButton(&quot;Menu top&gt;Radio item&quot;, Status := True)
+
+Dim iId As Integer &apos; Return value
+
+Const cstThisSub = &quot;SFWidgets.PopupMenu.AddRadioButton&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Status) Or IsEmpty(Status) Then Status = False
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Status, &quot;Status&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ End If
+
+Try:
+ iId = _AddItem(MenuItem, Name, cstRadio, Status, Icon, Tooltip)
+
+Finally:
+ AddRadioButton = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu.AddRadioButton
+
+REM -----------------------------------------------------------------------------
+Public Function Execute(Optional ByVal ReturnId As Variant) As Variant
+&apos;&apos;&apos; Display the popup menu and return the menu item clicked by the user
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ReturnId: When True (default), return the unique ID of the clicked item, otherwise return its name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of clicked item or its name
+&apos;&apos;&apos; The returned value is 0 or &quot;&quot; (depending on ReturnId) when the menu is cancelled
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Sub OpenMenu(Optional poMouseEvent As Object)
+&apos;&apos;&apos; Dim myMenu As Object, vChoice As Variant
+&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poMouseEvent)
+&apos;&apos;&apos; With myMenu
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Dialog&quot;)
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Find&quot;, STatus := True)
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Status Bar&quot;, STatus := True)
+&apos;&apos;&apos; .AddItem(&quot;View&gt;Full Screen&quot;, Name := &quot;FULLSCREEN&quot;)
+&apos;&apos;&apos; vChoice = .Execute(False) &apos; When 1st checkbox is clicked, return &quot;Dialog&quot;
+&apos;&apos;&apos; &apos; When last item is clicked, return &quot;FULLSCREEN&quot;
+&apos;&apos;&apos; End With
+
+Dim vMenuItem As Variant &apos; Return value
+
+Const cstThisSub = &quot;SFWidgets.PopupMenu.Execute&quot;
+Const cstSubArgs = &quot;[ReturnId=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vMenuItem = 0
+
+Check:
+ If IsMissing(ReturnId) Or IsEmpty(ReturnId) Then ReturnId = True
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(ReturnId, &quot;ReturnId&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ End If
+ If Not ReturnId Then vMenuItem = &quot;&quot;
+
+Try:
+ vMenuItem = MenuRoot.Execute(PeerWindow, Rectangle, com.sun.star.awt.PopupMenuDirection.EXECUTE_DEFAULT)
+ If Not ReturnId Then vMenuItem = MenuIdentification.Item(CStr(vMenuItem))
+
+Finally:
+ Execute = vMenuItem
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu.Execute
+
+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;SFWidgets.PopupMenu.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; SFWidgets.SF_PopupMenu.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;AddCheckBox&quot; _
+ , &quot;AddItem&quot; _
+ , &quot;AddRadioButton&quot; _
+ , &quot;Execute&quot; _
+ )
+
+End Function &apos; SFWidgets.SF_PopupMenu.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer a.AddItem(&quot;B&gt;B1&quot;)class as an array
+
+ Properties = Array( _
+ &quot;ShortcutCharacter&quot; _
+ , &quot;SubmenuCharacter&quot; _
+ )
+
+End Function &apos; SFWidgets.SF_PopupMenu.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;SFWidgets.PopupMenu.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:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _AddItem(ByVal MenuItem As String _
+ , ByVal Name As String _
+ , ByVal ItemType As String _
+ , ByVal Status As Boolean _
+ , ByVal Icon As String _
+ , ByVal Tooltip As String _
+ , Optional ByVal Command As String _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name to be returned by the Execute() method if this item is clicked
+&apos;&apos;&apos; Default = the last component of MenuItem
+&apos;&apos;&apos; ItemType: &quot;N&quot;(ormal, &quot;C&quot;(heck) or &quot;R&quot;(adio)
+&apos;&apos;&apos; Status: when True the item is selected
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: only for menubar menus
+&apos;&apos;&apos; Either a uo command like &quot;.uno:About&quot;
+&apos;&apos;&apos; or a script to be run: script URI ::: string argument to be passed to the script
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+
+Dim iId As Integer &apos; Return value
+Dim vSplit As Variant &apos; Split menu item
+Dim sMenu As String &apos; Submenu where to attach the new item, as a string
+Dim oMenu As Object &apos; Submenu where to attach the new item, as an object
+Dim sName As String &apos; The text displayed in the menu box
+Dim oImage As Object &apos; com.sun.star.graphic.XGraphic
+Dim sCommand As String &apos; Alias of Command completed with arguments
+Const cstCommandSep = &quot;,&quot;
+
+ On Local Error GoTo Catch
+ iId = 0
+ If IsMissing(Command) Then Command = &quot;&quot;
+
+Try:
+ &apos; Run through the upper menu tree
+ vSplit = _SplitMenuItem(MenuItem)
+
+ &apos; Create and determine the menu to which to attach the new item
+ sMenu = vSplit(0)
+ Set oMenu = _GetPopupMenu(sMenu) &apos; Run through the upper menu tree and retain the last branch
+
+ &apos; Insert the new item
+ LastItem = LastItem + 1
+ sName = vSplit(1)
+
+ With oMenu
+ If sName = _SeparatorChar Then
+ .insertSeparator(-1)
+ Else
+ Select Case ItemType
+ Case cstNormal
+ .insertItem(LastItem, sName, 0, -1)
+ Case cstCheck
+ .insertItem(LastItem, sName, com.sun.star.awt.MenuItemStyle.CHECKABLE + com.sun.star.awt.MenuItemStyle.AUTOCHECK, -1)
+ .checkItem(LastItem, Status)
+ Case cstRadio
+ .insertItem(LastItem, sName, com.sun.star.awt.MenuItemStyle.RADIOCHECK + com.sun.star.awt.MenuItemStyle.AUTOCHECK, -1)
+ .checkItem(LastItem, Status)
+ End Select
+
+ &apos; Store the ID - Name relation
+ If Len(Name) = 0 Then Name = Replace(sName, _UnderlineAccessKeyChar, &quot;&quot;)
+ MenuIdentification.Add(CStr(LastItem), Name)
+
+ &apos; Add the icon when relevant
+ If Len(Icon) &gt; 0 Then
+ Set oImage = _GetImageFromUrl(_IconsDirectory &amp; Icon)
+ If Not IsNull(oImage) Then .setItemImage(LastItem, oImage, False)
+ End If
+
+ &apos; Add the tooltip when relevant
+ If Len(Tooltip) &gt; 0 Then .setTipHelpText(LastItem, Tooltip)
+
+ &apos; Add the command: UNO command or script to run - menubar menus only
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then
+ sCommand = Command
+ Else
+ sCommand = Command &amp; cstCommandSep &amp; Name &amp; cstCommandSep &amp; CStr(LastItem)
+ End If
+ .setCommand(LastItem, sCommand)
+ End If
+ End If
+ End With
+
+ iId = LastItem
+
+Finally:
+ _AddItem = iId
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu._AddItem
+
+REM -----------------------------------------------------------------------------
+Private Function _GetImageFromURL(ByVal psUrl as String) As Object
+&apos;&apos;&apos; Returns a com.sun.star.graphic.XGraphic instance based on the given URL
+&apos;&apos;&apos; The returned object is intended to be inserted as an icon in the popup menu
+&apos;&apos;&apos; Derived from &quot;Useful Macro Information For OpenOffice&quot; By Andrew Pitonyak
+
+Dim vMediaProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim oGraphicProvider As Object &apos; com.sun.star.graphic.GraphicProvider
+Dim oImage As Object &apos; Return value
+
+ On Local Error GoTo Catch &apos; Ignore errors
+ Set oImage = Nothing
+
+Try:
+ &apos; Create graphic provider instance to load images from files.
+ Set oGraphicProvider = CreateUnoService(&quot;com.sun.star.graphic.GraphicProvider&quot;)
+
+ &apos; Set the URL property so graphic provider is able to load the image
+ Set vMediaProperties = Array(ScriptForge.SF_Utils._MakePropertyValue(&quot;URL&quot;, psURL))
+
+ &apos; Retrieve the com.sun.star.graphic.XGraphic instance
+ Set oImage = oGraphicProvider.queryGraphic(vMediaProperties)
+
+Finally:
+ Set _GetImageFromUrl = oImage
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu._GetImageFromUrl
+
+REM -----------------------------------------------------------------------------
+Private Function _GetPopupMenu(ByVal psSubmenu As String) As Object
+&apos;&apos;&apos; Get the com.sun.star.awt.XPopupMenu object corresponding with the string in argument
+&apos;&apos;&apos; If the menu exists, it is found in the MenuTree dictionary
+&apos;&apos;&apos; If it does not exist, it is created recursively.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psSubmenu: a string like &quot;A&gt;B&quot;
+&apos;&apos;&apos; Returns
+&apos;&apos;&apos; A com.sun.star.awt.XpopupMenu object
+&apos;&apos;&apos; Example
+&apos;&apos;&apos; If psSubmenu = &quot;A&gt;B&gt;C&gt;D&quot;, and only the root menu exists,
+&apos;&apos;&apos; - &quot;A&quot;, &quot;A&gt;B&quot;, &quot;A&gt;B&gt;C&quot;, &quot;A&gt;B&gt;C&gt;D&quot; should be created
+&apos;&apos;&apos; - the popup menu corresponding with &quot;A&gt;B&gt;C&gt;D&quot; should be returned
+
+Dim oPopup As Object &apos; Return value
+Dim vSplit As Variant &apos; An array as returned by _SplitMenuItem()
+Dim sMenu As String &apos; The left part of psSubmenu
+Dim oMenu As Object &apos; com.sun.star.awt.XpopupMenu
+Dim oLastMenu As Object &apos; com.sun.star.awt.XpopupMenu
+Dim i As Long
+
+ Set oPopup = Nothing
+ Set oLastMenu = MenuRoot
+Try:
+ If Len(psSubmenu) = 0 Then &apos; Menu starts at the root
+ Set oPopup = MenuRoot
+ ElseIf MenuTree.Exists(psSubmenu) Then &apos; Shortcut: if the submenu exists, get it directly
+ Set oPopup = MenuTree.Item(psSubmenu)
+ Else &apos; Build the tree
+ vSplit = Split(psSubmenu, SubmenuChar)
+ &apos; Search the successive submenus in the MenuTree dictionary, If not found, create a new entry
+ For i = 0 To UBound(vSplit)
+ sMenu = Join(ScriptForge.SF_Array.Slice(vSplit, 0, i), SubmenuChar)
+ If MenuTree.Exists(sMenu) Then
+ Set oLastMenu = MenuTree.Item(sMenu)
+ Else
+ &apos; Insert the new menu tree item
+ LastItem = LastItem + 1
+ oLastMenu.insertItem(LastItem, vSplit(i), 0, -1)
+ Set oMenu = CreateUnoService(&quot;stardiv.vcl.PopupMenu&quot;)
+ If MenubarMenu Then SFWidgets.SF_MenuListener.SetMenuListener(oMenu)
+ MenuTree.Add(sMenu, oMenu)
+ oLastMenu.setPopupMenu(LastItem, oMenu)
+ Set oLastMenu = oMenu
+ End If
+ Next i
+ Set oPopup = oLastMenu
+ End If
+
+Finally:
+ Set _GetPopupMenu = oPopup
+ Exit Function
+End Function &apos; SFWidgets.SF_PopupMenu._GetPopupMenu
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize(ByRef poPeer As Object _
+ , plXPos As Long _
+ , plYPos As Long _
+ , psSubmenuChar As String _
+ )
+&apos;&apos;&apos; Complete the object creation process:
+&apos;&apos;&apos; - Initialize the dictionaries
+&apos;&apos;&apos; - initialize the root popup menu
+&apos;&apos;&apos; - initialize the display area
+&apos;&apos;&apos; - store the arguments for later use
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poPeer: a peer window
+&apos;&apos;&apos; plXPos, plYPos: the coordinates
+
+Try:
+ &apos; Initialize the dictionaries
+ With ScriptForge.SF_Services
+ Set MenuTree = .CreateScriptService(&quot;Dictionary&quot;)
+ Set MenuIdentification = .CreateScriptService(&quot;Dictionary&quot;)
+ End With
+
+ &apos; Initialize the root of the menu tree
+ Set MenuRoot = CreateUnoService(&quot;stardiv.vcl.PopupMenu&quot;)
+
+ &apos; Setup the display area
+ Set Rectangle = New com.sun.star.awt.Rectangle
+ Rectangle.X = plXPos
+ Rectangle.Y = plYPos
+
+ &apos; Keep the targeted window
+ Set PeerWindow = poPeer
+
+ &apos; Store the submenu character
+ If Len(psSubmenuChar) &gt; 0 Then SubmenuChar = psSubmenuChar
+
+Finally:
+ Exit Sub
+End Sub &apos; SFWidgets.SF_PopupMenu._Initialize
+
+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 vGet As Variant &apos; Return value
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFWidgets.PopupMenu.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ _PropertyGet = Null
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;ShortcutCharacter&quot;)
+ _PropertyGet = _UnderlineAccessKeyChar
+ Case UCase(&quot;SubmenuCharacter&quot;)
+ _PropertyGet = SubmenuChar
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_PopupMenu._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_PopupMenu instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[PopupMenu]: Name, Type (dialogname)
+ _Repr = &quot;[PopupMenu]: &quot; &amp; SF_String.Represent(MenuTree.Keys()) &amp; &quot;, &quot; &amp; SF_String.Represent(MenuIdentification.Items())
+
+End Function &apos; SFWidgets.SF_PopupMenu._Repr
+
+REM -----------------------------------------------------------------------------
+Private Function _SplitMenuItem(ByVal psMenuItem As String ) As Variant
+&apos;&apos;&apos; Split a menu item given as a string and delimited by the submenu character
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMenuItem: a string like &quot;A&gt;B&gt;C&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array: [0] = &quot;A&gt;B&quot;
+&apos;&apos;&apos; [1] = &quot;C&quot;
+
+Dim vReturn(0 To 1) As String &apos; Return value
+Dim vMenus() As Variant &apos; Array of menus
+
+Try:
+ vMenus = Split(psMenuItem, SubmenuChar)
+ vReturn(1) = vMenus(UBound(vMenus))
+ vReturn(0) = Left(psMenuItem, Len(psMenuItem) - Iif(UBound(vMenus) &gt; 0, Len(SubmenuChar), 0) - Len(vReturn(1)))
+
+Finally:
+ _SplitMenuItem = vReturn
+End Function &apos; SFWidgets.SF_PopupMenu._SplitMenuItem
+
+REM ============================================ END OF SFWIDGETS.SF_POPUPMENU
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_Register.xba b/wizards/source/sfwidgets/SF_Register.xba
new file mode 100644
index 000000000..2c58b858d
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_Register.xba
@@ -0,0 +1,184 @@
+<?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 SFWidgets 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; - _NewMenu
+&apos;&apos;&apos; Create a new menu service instance.
+&apos;&apos;&apos; Called from SFDocuments services with CreateMenu()
+&apos;&apos;&apos; - _NewPopupMenu
+&apos;&apos;&apos; Create a new popup menu service instance.
+&apos;&apos;&apos; Called from CreateScriptService()
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ================================================================= DEFINITIONS
+
+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;Menu&quot;, &quot;SFWidgets.SF_Register._NewMenu&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;PopupMenu&quot;, &quot;SFWidgets.SF_Register._NewPopupMenu&quot;) &apos; id.
+ End With
+
+End Sub &apos; SFWidgets.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _NewMenu(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the SF_Menu class
+&apos;&apos;&apos; [called internally from SFDocuments.Document.CreateMenu() ONLY]
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Component: the com.sun.star.lang.XComponent where to find the menubar to plug the new menu in
+&apos;&apos;&apos; Header: the name/header of the menu
+&apos;&apos;&apos; Before: the place where to put the new menu on the menubar (string or number &gt;= 1)
+&apos;&apos;&apos; When not found =&gt; last position
+&apos;&apos;&apos; SubmenuChar: the delimiter used in menu trees. Default = &quot;&gt;&quot;
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oMenu As Object &apos; Return value
+Dim oComponent As Object &apos; The document or formdocument&apos;s component - com.sun.star.lang.XComponent
+Dim sHeader As String &apos; Menu header
+Dim sBefore As String &apos; Position of menu as a string
+Dim iBefore As Integer &apos; as a number
+Dim sSubmenuChar As String &apos; Delimiter in menu trees
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oMenu = Nothing
+
+Check:
+ &apos; Types and number of arguments are not checked because internal call only
+ Set oComponent = pvArgs(0)
+ sHeader = pvArgs(1)
+ Select Case VarType(pvArgs(2))
+ Case V_STRING : sBefore = pvArgs(2)
+ iBefore = 0
+ Case Else : sBefore = &quot;&quot;
+ iBefore = pvArgs(2)
+ End Select
+ sSubmenuChar = pvArgs(3)
+
+Try:
+ If Not IsNull(oComponent) Then
+ Set oMenu = New SF_Menu
+ With oMenu
+ Set .[Me] = oMenu
+ ._Initialize(oComponent, sHeader, sBefore, iBefore, sSubmenuChar)
+ End With
+ End If
+
+Finally:
+ Set _NewMenu = oMenu
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Register._NewMenu
+
+REM -----------------------------------------------------------------------------
+Public Function _NewPopupMenu(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the SF_PopupMenu class
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Event: a mouse event
+&apos;&apos;&apos; If the event has no source or is not a mouse event, the menu is displayed above ThisComponent
+&apos;&apos;&apos; X, Y: forced coordinates
+&apos;&apos;&apos; SubmenuChar: Delimiter used in menu trees
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oMenu As Object &apos; Return value
+Dim Event As Variant &apos; Mouse event
+Dim X As Long &apos; Mouse click coordinates
+Dim Y As Long
+Dim SubmenuChar As String &apos; Delimiter in menu trees
+Dim oSession As Object &apos; ScriptForge.SF_Session
+Dim vUno As Variant &apos; UNO type split into an array
+Dim sEventType As String &apos; Event type, must be &quot;MouseEvent&quot;
+Dim oControl As Object &apos; The dialog or form control view which triggered the event
+
+ 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)
+ If UBound(pvArgs) &gt;= 0 Then Event = pvArgs(0) Else Event = Nothing
+ If IsEmpty(Event) Then Event = Nothing
+ If UBound(pvArgs) &gt;= 1 Then X = pvArgs(1) Else X = 0
+ If UBound(pvArgs) &gt;= 2 Then Y = pvArgs(2) Else Y = 0
+ If UBound(pvArgs) &gt;= 3 Then SubmenuChar = pvArgs(3) Else SubmenuChar = &quot;&quot;
+ If Not ScriptForge.SF_Utils._Validate(Event, &quot;Event&quot;, ScriptForge.V_OBJECT) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(X, &quot;X&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Y, &quot;Y&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SubmenuChar, &quot;SubmenuChar&quot;, V_STRING) Then GoTo Finally
+ Set oMenu = Nothing
+
+Try:
+ Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ Set oControl = Nothing
+ If Not IsNull(Event) Then
+ &apos; Determine the X, Y coordinates
+ vUno = Split(oSession.UnoObjectType(Event), &quot;.&quot;)
+ sEventType = vUno(UBound(vUno))
+ If UCase(sEventType) = &quot;MOUSEEVENT&quot; Then
+ X = Event.X
+ Y = Event.Y
+ &apos; Determine the window peer target
+ If oSession.HasUnoProperty(Event, &quot;Source&quot;) Then Set oControl = Event.Source.Peer
+ End If
+ End If
+ &apos; If not a mouse event, if no control, ...
+ If IsNull(oControl) Then
+ If Not IsNull(ThisComponent) Then Set oControl = ThisComponent.CurrentController.Frame.getContainerWindow()
+ End If
+
+ If Not IsNull(oControl) Then
+ Set oMenu = New SF_PopupMenu
+ With oMenu
+ Set .[Me] = oMenu
+ ._Initialize(oControl, X, Y, SubmenuChar)
+ End With
+ Else
+ Set oMenu = Nothing
+ End If
+
+Finally:
+ Set _NewPopupMenu = oMenu
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Register._NewPopupMenu
+
+REM ============================================== END OF SFWidgets.SF_REGISTER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/__License.xba b/wizards/source/sfwidgets/__License.xba
new file mode 100644
index 000000000..0d0990e37
--- /dev/null
+++ b/wizards/source/sfwidgets/__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-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
+
+REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFWidgets 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/sfwidgets/dialog.xlb b/wizards/source/sfwidgets/dialog.xlb
new file mode 100644
index 000000000..5d45468be
--- /dev/null
+++ b/wizards/source/sfwidgets/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="SFWidgets" library:readonly="false" library:passwordprotected="false"/> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/script.xlb b/wizards/source/sfwidgets/script.xlb
new file mode 100644
index 000000000..40e9f4c23
--- /dev/null
+++ b/wizards/source/sfwidgets/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="SFWidgets" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="__License"/>
+ <library:element library:name="SF_Register"/>
+ <library:element library:name="SF_PopupMenu"/>
+ <library:element library:name="SF_Menu"/>
+ <library:element library:name="SF_MenuListener"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/standard/Module1.xba b/wizards/source/standard/Module1.xba
new file mode 100644
index 000000000..3424c168e
--- /dev/null
+++ b/wizards/source/standard/Module1.xba
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic">REM ***** BASIC *****
+
+Sub Main
+
+End Sub</script:module> \ No newline at end of file
diff --git a/wizards/source/standard/dialog.xlb b/wizards/source/standard/dialog.xlb
new file mode 100644
index 000000000..669529dbc
--- /dev/null
+++ b/wizards/source/standard/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="Standard" library:readonly="false" library:passwordprotected="false"/>
diff --git a/wizards/source/standard/script.xlb b/wizards/source/standard/script.xlb
new file mode 100644
index 000000000..67c9503b7
--- /dev/null
+++ b/wizards/source/standard/script.xlb
@@ -0,0 +1,5 @@
+<?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="Standard" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="Module1"/>
+</library:library>
diff --git a/wizards/source/template/Autotext.xba b/wizards/source/template/Autotext.xba
new file mode 100644
index 000000000..35b3fdf62
--- /dev/null
+++ b/wizards/source/template/Autotext.xba
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Autotext" script:language="StarBasic">Option Explicit
+
+Public UserfieldDataType(14) as String
+Public oDocAuto as Object
+Public BulletList(7) as Integer
+Public sTextFieldNotDefined as String
+Public sGeneralError as String
+
+
+Sub Main()
+ Dim oCursor as Object
+ Dim oStyles as Object
+ Dim oSearchDesc as Object
+ Dim oFoundall as Object
+ Dim oFound as Object
+ Dim i as Integer
+ Dim sFoundString as String
+ Dim sFoundContent as String
+ Dim FieldStringThere as String
+ Dim ULStringThere as String
+ Dim PHStringThere as String
+ On Local Error Goto GENERALERROR
+ &apos; Initialization...
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ If InitResources(&quot;&apos;Template&apos;&quot;) Then
+ sGeneralError = GetResText(&quot;CorrespondenceMsgError&quot;)
+ sTextFieldNotDefined = GetResText(&quot;TextField&quot;)
+ End If
+
+ UserfieldDatatype(0) = &quot;COMPANY&quot;
+ UserfieldDatatype(1) = &quot;FIRSTNAME&quot;
+ UserfieldDatatype(2) = &quot;NAME&quot;
+ UserfieldDatatype(3) = &quot;SHORTCUT&quot;
+ UserfieldDatatype(4) = &quot;STREET&quot;
+ UserfieldDatatype(5) = &quot;COUNTRY&quot;
+ UserfieldDatatype(6) = &quot;ZIP&quot;
+ UserfieldDatatype(7) = &quot;CITY&quot;
+ UserfieldDatatype(8) = &quot;TITLE&quot;
+ UserfieldDatatype(9) = &quot;POSITION&quot;
+ UserfieldDatatype(10) = &quot;PHONE_PRIVATE&quot;
+ UserfieldDatatype(11) = &quot;PHONE_COMPANY&quot;
+ UserfieldDatatype(12) = &quot;FAX&quot;
+ UserfieldDatatype(13) = &quot;EMAIL&quot;
+ UserfieldDatatype(14) = &quot;STATE&quot;
+ BulletList(0) = 149
+ BulletList(1) = 34
+ BulletList(2) = 65
+ BulletList(3) = 61
+ BulletList(4) = 49
+ BulletList(5) = 47
+ BulletList(6) = 79
+ BulletList(7) = 58
+
+ oDocAuto = ThisComponent
+ oStyles = oDocAuto.Stylefamilies.GetByName(&quot;NumberingStyles&quot;)
+
+ &apos; Prepare the Search-Descriptor
+ oSearchDesc = oDocAuto.createsearchDescriptor()
+ oSearchDesc.SearchRegularExpression = True
+ oSearchDesc.SearchWords = True
+ oSearchDesc.SearchString = &quot;&lt;[^&gt;]+&gt;&quot;
+ oFoundall = oDocAuto.FindAll(oSearchDesc)
+
+ &apos;Loop over the foundings
+ For i = 0 To oFoundAll.Count - 1
+ oFound = oFoundAll.GetByIndex(i)
+ sFoundString = oFound.String
+ &apos;Extract the string inside the brackets
+ sFoundContent = FindPartString(sFoundString,&quot;&lt;&quot;,&quot;&gt;&quot;,1)
+ sFoundContent = LTrim(sFoundContent)
+
+ &apos; Define the Cursor and place it on the founding
+ oCursor = oFound.Text.CreateTextCursorbyRange(oFound)
+
+ &apos; Find out, which object is to be created...
+ FieldStringThere = Instr(1,sFoundContent,&quot;Field&quot;)
+ ULStringThere = Instr(1,sFoundContent,&quot;UL&quot;)
+ PHStringThere = Instr(1,sFoundContent,&quot;Placeholder&quot;)
+ If FieldStringThere = 1 Then
+ CreateUserDatafield(oCursor, sFoundContent)
+ ElseIf ULStringThere = 1 Then
+ CreateBullet(oCursor, oStyles)
+ ElseIf PHStringThere = 1 Then
+ CreatePlaceholder(oCursor, sFoundContent)
+ End If
+ Next i
+
+ GENERALERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(sGeneralError,16, GetProductName())
+ Resume LETSGO
+ End If
+ LETSGO:
+End Sub
+
+
+&apos; creates a User - datafield out of a string with the following structure
+&apos; &quot;&lt;field:Company&gt;&quot;
+Sub CreateUserDatafield(oCursor, sFoundContent as String)
+ Dim MaxIndex as Integer
+ Dim sFoundList(3)
+ Dim oUserfield as Object
+ Dim UserInfo as String
+ Dim UserIndex as Integer
+
+ oUserfield = oDocAuto.CreateInstance(&quot;com.sun.star.text.TextField.ExtendedUser&quot;)
+ sFoundList() = ArrayoutofString(sFoundContent,&quot;:&quot;,MaxIndex)
+ UserInfo = UCase(LTrim(sFoundList(1)))
+ UserIndex = IndexInArray(UserInfo, UserfieldDatatype())
+ If UserIndex &lt;&gt; -1 Then
+ oUserField.UserDatatype = UserIndex
+ oCursor.Text.InsertTextContent(oCursor,oUserField,True)
+ oUserField.IsFixed = True
+ Else
+ Msgbox(UserInfo &amp;&quot;: &quot; &amp; sTextFieldNotDefined,16, GetProductName())
+ End If
+End Sub
+
+
+&apos; Creates a Bullet by setting a soft Formatation on the first unsorted List-Templates with a defined
+&apos; Bullet Id
+Sub CreateBullet(oCursor, oStyles as Object)
+ Dim n, m, s as Integer
+ Dim StyleSet as Boolean
+ Dim ostyle as Object
+ Dim StyleName as String
+ Dim alevel()
+ StyleSet = False
+ For s = 0 To Ubound(BulletList())
+ For n = 0 To oStyles.Count - 1
+ ostyle = oStyles.getbyindex(n)
+ StyleName = oStyle.Name
+ alevel() = ostyle.NumberingRules.getbyindex(0)
+ &apos; The properties of the style are stored in a Name-Value-Array()
+ For m = 0 to Ubound(alevel())
+ &apos; Set the first Numbering template without a bulletID
+ If (aLevel(m).Name = &quot;BulletId&quot;) Then
+ If alevel(m).Value = BulletList(s) Then
+ oCursor.NumberingStyle = StyleName
+ oCursor.SetString(&quot;&quot;)
+ exit Sub
+ End if
+ End If
+ Next m
+ Next n
+ Next s
+ If Not StyleSet Then
+ &apos; The Template with the demanded BulletID is not available, so take the first style in the sequence
+ &apos; that has a defined Bullet ID
+ oCursor.NumberingStyleName = oStyles.GetByIndex(5).Name
+ oCursor.SetString(&quot;&quot;)
+ End If
+End Sub
+
+
+&apos; Creates a placeholder out of a string with the following structure:
+&apos;&lt;placeholder:Showtext:Helptext&gt;
+Sub CreatePlaceholder(oCursor as Object, sFoundContent as String)
+ Dim oPlaceholder as Object
+ Dim MaxIndex as Integer
+ Dim sFoundList(3)
+ oPlaceholder = oDocAuto.CreateInstance(&quot;com.sun.star.text.TextField.JumpEdit&quot;)
+ sFoundList() = ArrayoutofString(sFoundContent, &quot;:&quot; &amp; chr(34),MaxIndex)
+ &apos; Delete The Double-quotes
+ oPlaceholder.Hint = DeleteStr(sFoundList(2),chr(34))
+ oPlaceholder.placeholder = DeleteStr(sFoundList(1),chr(34))
+ oCursor.Text.InsertTextContent(oCursor,oPlaceholder,True)
+End Sub
+
+
+</script:module>
diff --git a/wizards/source/template/Correspondence.xba b/wizards/source/template/Correspondence.xba
new file mode 100644
index 000000000..01da7f3d8
--- /dev/null
+++ b/wizards/source/template/Correspondence.xba
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Correspondence" script:language="StarBasic">Option Explicit
+
+Public msgNoTextmark$, msgError$
+Public sAddressbook$
+Public Table
+Public sCompany$, sFirstName$, sLastName$, sStreet$, sPostalCode$, sCity$, sState$, sInitials$, sPosition$
+Public DialogExited
+Public oDocument, oText, oBookMarks, oBookMark, oBookMarkCursor, oBookText as Object
+Public bTemplate, bDBFields as Boolean
+
+Sub Main
+ bTemplate = true
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ TemplateDialog = LoadDialog(&quot;Template&quot;, &quot;TemplateDialog&quot;)
+ DialogModel = TemplateDialog.Model
+ DialogModel.Step = 2
+ DialogModel.Optmerge.State = True
+ LoadLanguageCorrespondence()
+ TemplateDialog.Execute
+ TemplateDialog.Dispose()
+End Sub
+
+
+Sub Placeholder
+ bTemplate = false
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ LoadLanguageCorrespondence()
+ bDBFields = false
+ OK()
+End Sub
+
+
+Sub Database
+ bTemplate = false
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ LoadLanguageCorrespondence()
+ bDBFields = true
+ OK()
+End Sub
+
+
+Function LoadLanguageCorrespondence() as Boolean
+ If InitResources(&quot;&apos;Template&apos;&quot;) Then
+ msgNoTextmark$ = GetResText(&quot;CorrespondenceDialog_0&quot;) &amp; Chr(13) &amp; Chr(10) &amp; GetResText(&quot;CorrespondenceNoTextmark_1&quot;)
+ msgError$ = GetResText(&quot;CorrespondenceMsgError&quot;)
+ If bTemplate Then
+ DialogModel.Title = GetResText(&quot;CorrespondenceDialog_3&quot;)
+ DialogModel.CmdCancel.Label = GetResText(&quot;STYLES_2&quot;)
+ DialogModel.CmdCorrGoOn.Label = GetResText(&quot;STYLES_3&quot;)
+ DialogModel.OptSingle.Label = GetResText(&quot;CorrespondenceDialog_1&quot;)
+ DialogModel.Optmerge.Label = GetResText(&quot;CorrespondenceDialog_2&quot;)
+ DialogModel.FrmLetter.Label = GetResText(&quot;CorrespondenceDialog_0&quot;)
+ End If
+ LoadLanguageCorrespondence() = True
+ Else
+ msgbox(&quot;Warning: Resource could not be loaded!&quot;)
+ End If
+End Function
+
+
+Function GetFieldName(oFieldKnot as Object, GeneralFieldName as String)
+ If oFieldKnot.HasByName(GeneralFieldName) Then
+ GetFieldName = oFieldKnot.GetByName(GeneralFieldName).AssignedFieldName
+ Else
+ GetFieldName = &quot;&quot;
+ End If
+End Function
+
+
+Sub OK
+Dim ParaBreak
+Dim sDocLang as String
+Dim oSearchDesc as Object
+Dim oFoundAll as Object
+Dim oFound as Object
+Dim sFoundContent as String
+Dim sFoundString as String
+Dim sDBField as String
+Dim i as Integer
+Dim oDBAccess as Object
+Dim oAddressDialog as Object
+Dim oAddressPilot as Object
+Dim oFields as Object
+Dim oDocSettings as Object
+Dim oContext as Object
+Dim bDBvalid as Boolean
+ &apos;On Local Error Goto GENERALERROR
+
+ If bTemplate Then
+ bDBFields = DialogModel.Optmerge.State &apos;database or placeholder
+ TemplateDialog.EndExecute()
+ DialogExited = TRUE
+ End If
+
+ If bDBFields Then
+ oDBAccess = GetRegistryKeyContent(&quot;org.openoffice.Office.DataAccess/AddressBook/&quot;)
+ sAddressbook = oDBAccess.DataSourceName
+
+ bDBvalid = false
+ oContext = createUnoService( &quot;com.sun.star.sdb.DatabaseContext&quot; )
+
+ If (not isNull(oContext)) Then
+ &apos;Is the previously assigned address data source still valid?
+ bDBvalid = oContext.hasByName(sAddressbook)
+ end if
+
+ If (bDBvalid = false) Then
+ oAddressPilot = createUnoService(&quot;com.sun.star.ui.dialogs.AddressBookSourcePilot&quot;)
+ oAddressPilot.execute
+
+ oDBAccess = GetRegistryKeyContent(&quot;org.openoffice.Office.DataAccess/AddressBook/&quot;)
+ sAddressbook = oDBAccess.DataSourceName
+ If sAddressbook = &quot;&quot; Then
+ MsgBox(GetResText(&quot;CorrespondenceNoTextmark_1&quot;))
+ Exit Sub
+ End If
+ End If
+ oFields = oDBAccess.GetByName(&quot;Fields&quot;)
+ Table = oDBAccess.GetByName(&quot;Command&quot;)
+ End If
+
+ ParaBreak = com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK
+ oDocument = ThisComponent
+ If bDBFields Then
+ &apos;set the address db as current db at the document
+ oDocSettings = oDocument.createInstance(&quot;com.sun.star.document.Settings&quot;)
+ oDocSettings.CurrentDatabaseDataSource = sAddressbook
+ oDocSettings.CurrentDatabaseCommand = Table
+ oDocSettings.CurrentDatabaseCommandType = 0
+ End If
+ oBookmarks = oDocument.Bookmarks
+ oText = oDocument.Text
+
+ oSearchDesc = oDocument.createsearchDescriptor()
+ oSearchDesc.SearchRegularExpression = True
+ oSearchDesc.SearchWords = True
+ oSearchDesc.SearchString = &quot;&lt;[^&gt;]+&gt;&quot;
+ oFoundall = oDocument.FindAll(oSearchDesc)
+
+ &apos;Loop over the foundings
+ For i = oFoundAll.Count -1 To 0 Step -1
+ oFound = oFoundAll.GetByIndex(i)
+ sFoundString = oFound.String
+ &apos;Extract the string inside the brackets
+ sFoundContent = FindPartString(sFoundString,&quot;&lt;&quot;,&quot;&gt;&quot;,1)
+ sFoundContent = LTrim(sFoundContent)
+ &apos; Define the Cursor and place it on the founding
+ oBookmarkCursor = oFound.Text.CreateTextCursorbyRange(oFound)
+ oBookText = oFound.Text
+ If bDBFields Then
+ sDBField = GetFieldname(oFields, sFoundContent)
+ If sDBField &lt;&gt; &quot;&quot; Then
+ InsertDBField(sAddressbook, Table, sDBField)
+ Else
+ InsertPlaceholder(sFoundContent)
+ End If
+ Else
+ InsertPlaceholder(sFoundContent)
+ End If
+ Next i
+ If bDBFields Then
+ &apos;Open the DB beamer with the right DB
+ Dim oDisp as Object
+ Dim oTransformer
+ Dim aURL as new com.sun.star.util.URL
+ aURL.complete = &quot;.component:DB/DataSourceBrowser&quot;
+ oTransformer = createUnoService(&quot;com.sun.star.util.URLTransformer&quot;)
+ oTransformer.parseStrict(aURL)
+ oDisp = oDocument.getCurrentController.getFrame.queryDispatch(aURL, &quot;_beamer&quot;, com.sun.star.frame.FrameSearchFlag.CHILDREN + com.sun.star.frame.FrameSearchFlag.CREATE)
+ Dim aArgs(3) as new com.sun.star.beans.PropertyValue
+ aArgs(1).Name = &quot;DataSourceName&quot;
+ aArgs(1).Value = sAddressbook
+ aArgs(2).Name = &quot;CommandType&quot;
+ aArgs(2).Value = com.sun.star.sdb.CommandType.TABLE
+ aArgs(3).Name = &quot;Command&quot;
+ aArgs(3).Value = Table
+ oDisp.dispatch(aURL, aArgs())
+ End If
+
+ GENERALERROR:
+ If Err &lt;&gt; 0 Then
+ Msgbox(msgError$,16, GetProductName())
+ Resume LETSGO
+ End If
+ LETSGO:
+
+End Sub
+
+
+Sub InsertDBField(sDBName as String, sTableName as String, sColName as String)
+Dim oFieldMaster, oField as Object
+ If sColname &lt;&gt; &quot;&quot; Then
+ oFieldMaster = oDocument.createInstance(&quot;com.sun.star.text.FieldMaster.Database&quot;)
+ oField = oDocument.createInstance(&quot;com.sun.star.text.TextField.Database&quot;)
+ oFieldMaster.DataBaseName = sDBName
+ oFieldMaster.DataBaseName = sDBName
+ oFieldMaster.DataTableName = sTableName
+ oFieldMaster.DataColumnName = sColName
+ oField.AttachTextfieldmaster (oFieldMaster)
+ oBookText.InsertTextContent(oBookMarkCursor, oField, True)
+ oField.Content = &quot;&lt;&quot; &amp; sColName &amp; &quot;&gt;&quot;
+ End If
+End Sub
+
+
+Sub InsertPlaceholder(sColName as String)
+Dim oFieldMaster as Object
+Dim bCorrectField as Boolean
+ If sColname &lt;&gt; &quot;&quot; Then
+ bCorrectField = True
+ oFieldMaster = oDocument.createInstance(&quot;com.sun.star.text.TextField.JumpEdit&quot;)
+ Select Case sColName
+ Case &quot;Company&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_1&quot;)
+ Case &quot;Department&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_2&quot;)
+ Case &quot;FirstName&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_3&quot;)
+ Case &quot;LastName&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_4&quot;)
+ Case &quot;Street&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_5&quot;)
+ Case &quot;Country&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_6&quot;)
+ Case &quot;Zip&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_7&quot;)
+ Case &quot;City&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_8&quot;)
+ Case &quot;Title&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_9&quot;)
+ Case &quot;Position&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_10&quot;)
+ Case &quot;AddrForm&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_11&quot;)
+ Case &quot;Code&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_12&quot;)
+ Case &quot;AddrFormMail&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_13&quot;)
+ Case &quot;PhonePriv&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_14&quot;)
+ Case &quot;PhoneComp&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_15&quot;)
+ Case &quot;Fax&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_16&quot;)
+ Case &quot;EMail&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_17&quot;)
+ Case &quot;URL&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_18&quot;)
+ Case &quot;Note&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_19&quot;)
+ Case &quot;Altfield1&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_20&quot;)
+ Case &quot;Altfield2&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_21&quot;)
+ Case &quot;Altfield3&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_22&quot;)
+ Case &quot;Altfield4&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_23&quot;)
+ Case &quot;Id&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_24&quot;)
+ Case &quot;State&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_25&quot;)
+ Case &quot;PhoneOffice&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_26&quot;)
+ Case &quot;Pager&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_27&quot;)
+ Case &quot;PhoneCell&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_28&quot;)
+ Case &quot;PhoneOther&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_29&quot;)
+ Case &quot;CalendarURL&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_30&quot;)
+ Case &quot;InviteParticipant&quot;
+ oFieldMaster.PlaceHolder = getResText(&quot;CorrespondenceFields_31&quot;)
+ Case Else
+ bCorrectField = False
+ End Select
+ If bCorrectField Then
+ oFieldMaster.Hint = getResText(&quot;CorrespondenceFields_0&quot;)
+ oBookText.InsertTextContent(oBookMarkCursor, oFieldMaster, True)
+ End If
+ End If
+End Sub
+</script:module>
diff --git a/wizards/source/template/DialogStyles.xdl b/wizards/source/template/DialogStyles.xdl
new file mode 100644
index 000000000..ec5f71423
--- /dev/null
+++ b/wizards/source/template/DialogStyles.xdl
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="DialogStyles" dlg:left="170" dlg:top="93" dlg:width="120" dlg:height="169" dlg:help-url="HID:WIZARDS_HID_DLGSTYLES_DIALOG" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="0" dlg:left="5" dlg:top="150" dlg:width="50" dlg:height="13" dlg:help-url="HID:WIZARDS_HID_DLGSTYLES_CANCEL" dlg:value="cmdCancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Template.Samples.RestoreCurrentStyles?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdOk" dlg:tab-index="1" dlg:left="65" dlg:top="150" dlg:width="50" dlg:height="12" dlg:help-url="HID:WIZARDS_HID_DLGSTYLES_OKAY" dlg:value="cmdOk">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Template.Samples.CloseStyleDialog?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:menulist dlg:id="lbStyles" dlg:tab-index="2" dlg:left="5" dlg:top="5" dlg:width="110" dlg:height="133" dlg:help-url="HID:WIZARDS_HID_DLGSTYLES_LISTBOX">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Template.Samples.SelectStyle?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:menulist>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/template/ModuleAgenda.xba b/wizards/source/template/ModuleAgenda.xba
new file mode 100644
index 000000000..a17fb68cd
--- /dev/null
+++ b/wizards/source/template/ModuleAgenda.xba
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ModuleAgenda" script:language="StarBasic">&apos; All variables must be declared before use
+Option Explicit
+
+&apos; Used for &quot;disabling&quot; the cancel button of the dialog
+Public DialogExited As Boolean
+Dim DlgAgenda_gMyName as String
+Public TemplateDialog as Object
+Public DialogModel as Object
+Public sTrueContent as String
+Public Bookmarkname as String
+
+
+
+Sub Initialize()
+&apos; User sets the type of minutes
+ BasicLibraries.LoadLibrary( &quot;Tools&quot; )
+ TemplateDialog = LoadDialog(&quot;Template&quot;, &quot;TemplateDialog&quot;)
+ DialogModel = TemplateDialog.Model
+ DialogModel.Step = 1
+ LoadLanguageAgenda()
+ DialogModel.OptAgenda2.State = TRUE
+ GetOptionValues()
+ DialogExited = FALSE
+ TemplateDialog.Execute
+End Sub
+
+
+Sub LoadLanguageAgenda()
+ If InitResources(&quot;&apos;Template&apos;&quot;) Then
+ DlgAgenda_gMyName = GetResText(&quot;AgendaDlgName&quot;)
+ DialogModel.CmdCancel.Label = GetResText(&quot;STYLES_2&quot;)
+ DialogModel.CmdAgdGoon.Label = GetResText(&quot;STYLES_3&quot;)
+&apos; DlgAgenda_gMsgNoCancel$ = GetResText(&quot;AgendaDlgNoCancel&quot;)
+ DialogModel.FrmAgenda.Label = GetResText(&quot;AgendaDlgFrame&quot;)
+ DialogModel.OptAgenda1.Label = GetResText(&quot;AgendaDlgButton1&quot;)
+ DialogModel.OptAgenda2.Label = GetResText(&quot;AgendaDlgButton2&quot;)
+&apos; DialogModel.OptAgenda1.State = 1
+ End If
+End Sub
+
+
+Sub ModifyTemplate()
+Dim oDocument, oBookmarks, oBookmark, oBookmarkCursor, oTextField as Object
+Dim i as Integer
+
+ oDocument = ThisComponent
+ oBookMarks = oDocument.Bookmarks
+
+ On Local Error Goto NOBOOKMARK
+ TemplateDialog.EndExecute
+ DialogExited = TRUE
+ oBookmarkCursor = CreateBookmarkCursor(oDocument, BookmarkName)
+ oBookmarkCursor.Text.insertString(oBookmarkCursor,&quot;&quot;,True)
+ &apos; Delete all the Bookmarks except for the one named &quot;NextTopic&quot;
+ For i = oBookmarks.Count-1 To 0 Step -1
+ oBookMark = oBookMarks.GetByIndex(i)
+ If oBookMark.Name &lt;&gt; &quot;NextTopic&quot; Then
+ oBookMark.Dispose()
+ End If
+ Next i
+ oBookMarkCursor = CreateBookmarkCursor(oDocument, &quot;NextTopic&quot;)
+ If Not IsNull(oBookMarkCursor) Then
+ oTextField = oBookMarkCursor.TextField
+&apos; oTextField.TrueContent = sTrueContent
+ oTextField.Content = sTrueContent
+ End If
+
+ NOBOOKMARK:
+ If Err &lt;&gt; 0 Then
+ RESUME NEXT
+ End If
+End Sub
+
+
+Sub NewTopic
+&apos; Add a new topic to the agenda
+Dim oDocument, oBookmarks, oBookmark, oBookmarkCursor, oTextField as Object
+Dim oBaustein, oAutoText, oAutoGroup as Object
+Dim i as Integer
+
+ oDocument = ThisComponent
+ oBookMarkCursor = CreateBookMarkCursor(oDocument, &quot;NextTopic&quot;)
+ oTextField = oBookMarkCursor.TextField
+ oAutoText = CreateUnoService(&quot;com.sun.star.text.AutoTextContainer&quot;)
+ If oAutoText.HasbyName(&quot;template&quot;) Then
+ oAutoGroup = oAutoText.GetbyName(&quot;template&quot;)
+ If oAutoGroup.HasbyName(oTextField.Content) Then
+ oBaustein = oAutoGroup.GetbyName(oTextField.Content)
+ oBaustein.ApplyTo(oBookMarkCursor)
+ Else
+ Msgbox(&quot;AutoText &apos;&quot; &amp; oTextField.Content &amp; &quot;&apos; is not existing. Cannot insert additional topic!&quot;)
+ End If
+ Else
+ Msgbox(&quot;AutoGroupField template is not existing. Cannot insert additional topic!&quot;, 16, DlgAgenda_gMyName )
+ End If
+End Sub
+
+
+
+&apos; Add initials, date and time at bottom of agenda, disable and hide command buttons
+Sub FinishAgenda
+Dim BtnAddAgendaTopic As Object
+Dim BtnFinishAgenda As Object
+Dim oUserField, oDateTimeField as Object
+Dim oBookmarkCursor as Object
+Dim oFormats, oLocale as Object
+Dim iDateTimeKey as Integer
+
+ BasicLibraries.LoadLibrary( &quot;Tools&quot; )
+ oDocument = ThisComponent
+
+ oUserField = oDocument.CreateInstance(&quot;com.sun.star.text.TextField.ExtendedUser&quot;)
+ oUserField.UserDatatype = com.sun.star.text.UserDataPart.SHORTCUT
+
+ oDateTimeField = oDocument.CreateInstance(&quot;com.sun.star.text.TextField.DateTime&quot;)
+
+ &apos; Assign Standardformat to Datetime-Textfield
+ oFormats = oDocument.Numberformats
+ oLocale = oDocument.CharLocale
+ iDateTimeKey = oFormats.GetStandardFormat(com.sun.star.util.NumberFormat.DATETIME,oLocale)
+ oDateTimeField.NumberFormat = iDateTimeKey
+
+ oBookmarkCursor = CreateBookmarkCursor(oDocument, &quot;NextTopic&quot;)
+ oBookmarkCursor.Text.InsertTextContent(oBookmarkCursor,oUserField,False)
+ oBookmarkCursor.Text.InsertString(oBookmarkCursor,&quot; &quot;,False)
+ oBookmarkCursor.Text.InsertTextContent(oBookmarkCursor,oDateTimeField,False)
+ BtnAddAgendaTopic = getControlModel(oDocument, &quot;BtnAddAgendaTopic&quot;)
+ BtnFinishAgenda = getControlModel(oDocument, &quot;BtnFinishAgenda&quot;)
+ If Not IsNull(BtnAddAgendaTopic) Then BtnAddAgendaTopic.Enabled = FALSE
+ If Not IsNull(BtnFinishAgenda) Then BtnFinishAgenda.Enabled = FALSE
+End Sub
+
+
+Function CreateBookMarkCursor(oDocument as Object,sBookmarkName as String)
+ oBookMarks = oDocument.Bookmarks
+ If oBookmarks.HasbyName(sBookmarkName) Then
+ oBookMark = oBookMarks.GetbyName(sBookmarkName)
+ CreateBookMarkCursor = oBookMark.Anchor.Text.CreateTextCursorByRange(oBookMark.Anchor)
+ Else
+ Msgbox &quot;Bookmark &quot; &amp; sBookmarkName &amp; &quot; is not defined!&quot;
+ End If
+End Function
+
+
+
+Sub DeleteButtons
+Dim AgendaFinished As Boolean
+Dim BtnAddAgendaTopic As Object
+Dim BtnFinishAgenda As Object
+
+ oDocument = ThisComponent
+
+ BtnAddAgendaTopic = getControlModel(oDocument, &quot;BtnAddAgendaTopic&quot;)
+ BtnFinishAgenda = getControlModel(oDocument, &quot;BtnFinishAgenda&quot;)
+
+ &apos; If buttons could be accessed: If at least one button is disabled, then agenda is finished
+ AgendaFinished = FALSE
+ If Not IsNull(BtnAddAgendaTopic) Then
+ AgendaFinished = (AgendaFinished Or (BtnAddAgendaTopic.Enabled = FALSE))
+ End If
+
+ If Not IsNull(BtnFinishAgenda) Then
+ AgendaFinished = (AgendaFinished Or (BtnFinishAgenda.Enabled = FALSE))
+ End If
+
+ &apos; Delete Buttons, empty rows at end of document &amp; macro bindings if agenda is finished
+ If AgendaFinished Then
+ DisposeControl(oDocument, &quot;BtnAddAgendaTopic&quot;)
+ DisposeControl(oDocument, &quot;BtnFinishAgenda&quot;)
+
+ oBookmarkCursor = CreateBookMarkCursor(oDocument,&quot;NextTopic&quot;)
+ oBookMarkCursor.GotoEnd(True)
+ oBookmarkCursor.Text.insertString(oBookmarkCursor,&quot;&quot;,True)
+
+ AttachBasicMacroToEvent(oDocument,&quot;OnNew&quot;, &quot;&quot;)
+ AttachBasicMacroToEvent(oDocument,&quot;OnSave&quot;, &quot;&quot;)
+ AttachBasicMacroToEvent(oDocument,&quot;OnSaveAs&quot;, &quot;&quot;)
+ AttachBasicMacroToEvent(oDocument,&quot;OnPrint&quot;, &quot;&quot;)
+ End If
+End Sub
+
+
+
+Sub GetOptionValues(Optional aEvent as Object)
+Dim CurTag as String
+Dim Taglist() as String
+ If Not IsMissing(aEvent) Then
+ CurTag = aEvent.Source.Model.Tag
+ Else
+ If DialogModel.OptAgenda1.State = TRUE Then
+ CurTag = DialogModel.OptAgenda1.Tag
+ Else
+ CurTag = DialogModel.OptAgenda2.Tag
+ End If
+ End If
+ Taglist() = ArrayoutOfString(CurTag, &quot;;&quot;)
+ Bookmarkname = TagList(0)
+ sTrueContent = TagList(1)
+End Sub
+
+</script:module>
diff --git a/wizards/source/template/Samples.xba b/wizards/source/template/Samples.xba
new file mode 100644
index 000000000..25ff81bcf
--- /dev/null
+++ b/wizards/source/template/Samples.xba
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Samples" script:language="StarBasic">Option Explicit
+
+Const NumStyles = 18
+Const aTempFileName = &quot;Berend_Ilko_Tom_Stella_Volker.stc&quot;
+Dim oUcbObject as Object
+Public StylesDir as String
+Public StylesDialog as Object
+Public PathSeparator as String
+Public oFamilies as Object
+Public aOptions(0) as New com.sun.star.beans.PropertyValue
+Public sQueryPath as String
+Public NoArgs()as New com.sun.star.beans.PropertyValue
+Public aTempURL as String
+
+Public Files(100) as String
+
+&apos;--------------------------------------------------------------------------------------
+&apos;Calc Style Section starts here
+
+Sub ShowStyles
+&apos;This sub displays the style selection dialog if the current document is a calc document.
+Dim TemplateDir, ActFileTitle, DisplayDummy as String
+Dim sFilterName(0) as String
+Dim StyleNames() as String
+Dim LocalizedStyleNames(NumStyles,2) As String
+Dim LocalizedStyleName As String
+Dim t as Integer
+Dim MaxIndex as Integer
+Dim StyleNameDef As Variant
+ BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ If InitResources(&quot;&apos;Template&apos;&quot;) then
+ oDocument = ThisComponent
+ If oDocument.SupportsService(&quot;com.sun.star.sheet.SpreadsheetDocument&quot;) Then
+ ToggleWindow(False)
+ oUcbObject = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ oFamilies = oDocument.StyleFamilies
+ SaveCurrentStyles(oDocument)
+ StylesDialog = LoadDialog(&quot;Template&quot;, &quot;DialogStyles&quot;)
+ DialogModel = StylesDialog.Model
+ TemplateDir = GetPathSettings(&quot;Template&quot;, False, 0)
+ StylesDir = GetOfficeSubPath(&quot;Template&quot;, &quot;wizard/styles/&quot;)
+ sQueryPath = GetOfficeSubPath(&quot;Template&quot;, &quot;../wizard/bitmap/&quot;)
+ DialogModel.Title = GetResText(&quot;STYLES_0&quot;)
+ DialogModel.cmdCancel.Label = GetResText(&quot;STYLES_2&quot;)
+ DialogModel.cmdOk.Label = GetResText(&quot;STYLES_3&quot;)
+ StyleNameDef = Array("(Standard)", "Autumn Leaves", "Be", "Black and White", "Blackberry Bush", "Blue Jeans", "Fifties Diner", "Glacier", "Green Grapes", "Marine", "Millennium", "Nature", "Neon", "Night", "PC Nostalgia", "Pastel", "Pool Party", "Pumpkin")
+ For t = 0 to NumStyles - 1
+ LocalizedStyleNames(t,0) = StyleNameDef(t)
+ LocalizedStyleNames(t,1) = GetResText(&quot;STYLENAME_&quot; &amp; Trim(Str(t)))
+ Next t
+ Stylenames() = ReadDirectories(StylesDir, False, False, True,)
+ MaxIndex = Ubound(Stylenames())
+ For t = 0 to MaxIndex
+ LocalizedStyleName = StringInMultiArray(LocalizedStyleNames(), StyleNames(t,1), 0, 1)
+ If LocalizedStyleName &lt;&gt; "" Then
+ StyleNames(t,1) = LocalizedStyleName
+ End If
+ Next t
+ BubbleSortList(Stylenames(),True)
+ Dim cStyles(MaxIndex)
+ For t = 0 to MaxIndex
+ Files(t) = StyleNames(t,0)
+ cStyles(t) = StyleNames(t,1)
+ Next t
+ On Local Error Resume Next
+ DialogModel.lbStyles.StringItemList() = cStyles()
+ ToggleWindow(True)
+ StylesDialog.Execute
+ End If
+ End If
+End Sub
+
+
+Sub SelectStyle
+&apos;This sub loads the specific styles from a style document and loads them into the
+&apos;current document.
+Dim StylePath as String
+Dim NewStyle as String
+Dim Position as Integer
+ Position = DialogModel.lbStyles.SelectedItems(0)
+ If Position &gt; -1 Then
+ ToggleWindow(False)
+ StylePath = Files(Position)
+ aOptions(0).Name = &quot;OverwriteStyles&quot;
+ aOptions(0).Value = true
+ oFamilies.loadStylesFromURL(StylePath, aOptions())
+ ToggleWindow(True)
+ End If
+End Sub
+
+
+Sub SaveCurrentStyles(oDocument as Object)
+&apos;This sub stores the current document in the directory to hold temporary files.
+ On Error Goto ErrorOccurred
+ aTempURL = GetPathSettings(&quot;Temp&quot;, False)
+ Dim aRightMost as String
+ aRightMost = Right(aTempURL, 1)
+ if aRightMost = &quot;/&quot; Then
+ aTempURL = aTempURL &amp; aTempFileName
+ Else
+ aTempURL = aTempURL &amp; &quot;/&quot; &amp; aTempFileName
+ End If
+
+ While FileExists(aTempURL)
+ aTempURL=Left(aTempURL,(Len(aTempURL)-4)) &amp; &quot;_1.stc&quot;
+ Wend
+ oDocument.storeToURL(aTempURL, NoArgs())
+ Exit Sub
+
+ErrorOccurred:
+ MsgBox(GetResText(&quot;STYLES_1&quot;), 16, GetResText(&quot;STYLES_0&quot;))
+ On Local Error Goto 0
+End Sub
+
+
+Sub RestoreCurrentStyles
+&apos;This sub retrieves the styles from the temporarily save document
+ ToggleWindow(False)
+ On Local Error Goto NoFile
+ If FileExists(aTempURL) Then
+ aOptions(0).Name = &quot;OverwriteStyles&quot;
+ aOptions(0).Value = true
+ oFamilies.LoadStylesFromURL(aTempURL, aOptions())
+ KillTempFile()
+ End If
+ StylesDialog.EndExecute
+ ToggleWindow(True)
+NOFILE:
+ If Err &lt;&gt; 0 Then
+ Msgbox(&quot;Cannot load Document from &quot; &amp; aTempUrl, 64, GetProductname())
+ End If
+ On Local Error Goto 0
+End Sub
+
+
+Sub CloseStyleDialog
+ KillTempFile()
+ DialogExited = True
+ StylesDialog.Endexecute
+End Sub
+
+
+Sub KillTempFile()
+ If oUcbObject.Exists(aTempUrl) Then
+ oUcbObject.Kill(aTempUrl)
+ End If
+End Sub
+
+</script:module>
diff --git a/wizards/source/template/TemplateDialog.xdl b/wizards/source/template/TemplateDialog.xdl
new file mode 100644
index 000000000..545b92f95
--- /dev/null
+++ b/wizards/source/template/TemplateDialog.xdl
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="TemplateDialog" dlg:left="170" dlg:top="93" dlg:width="220" dlg:height="60" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_DIALOG" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="OptAgenda1" dlg:tab-index="0" dlg:left="12" dlg:top="20" dlg:width="144" dlg:height="10" dlg:page="1" dlg:tag="TOP2;PT1" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_OPTIONAGENDA1" dlg:value="OptAgenda1">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Template.ModuleAgenda.GetOptionValues?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ <dlg:radio dlg:id="OptAgenda2" dlg:tab-index="1" dlg:left="12" dlg:top="34" dlg:width="144" dlg:height="10" dlg:page="1" dlg:tag="TOP1;PT2" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_OPTIONAGENDA2" dlg:value="OptAgenda2">
+ <script:event script:event-name="on-itemstatechange" script:macro-name="vnd.sun.star.script:Template.ModuleAgenda.GetOptionValues?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:radio>
+ </dlg:radiogroup>
+ <dlg:button dlg:id="CmdCorrGoOn" dlg:tab-index="2" dlg:left="164" dlg:top="11" dlg:width="50" dlg:height="14" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_LETTEROKAY" dlg:value="CmdCorrGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="Template.Correspondence.OK" script:language="StarBasic"/>
+ </dlg:button>
+ <dlg:radiogroup>
+ <dlg:radio dlg:id="OptSingle" dlg:tab-index="3" dlg:left="12" dlg:top="20" dlg:width="144" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_OPTIONLETTER1" dlg:value="OptSingle"/>
+ <dlg:radio dlg:id="Optmerge" dlg:tab-index="4" dlg:left="12" dlg:top="34" dlg:width="144" dlg:height="10" dlg:page="2" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_OPTIONLETTER2" dlg:value="Optmerge"/>
+ </dlg:radiogroup>
+ <dlg:button dlg:id="CmdAgdGoon" dlg:tab-index="5" dlg:left="164" dlg:top="11" dlg:width="50" dlg:height="14" dlg:page="1" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_AGENDAOKAY" dlg:value="CmdAgdGoOn">
+ <script:event script:event-name="on-performaction" script:macro-name="Template.ModuleAgenda.ModifyTemplate" script:language="StarBasic"/>
+ </dlg:button>
+ <dlg:button dlg:id="CmdCancel" dlg:tab-index="6" dlg:left="164" dlg:top="28" dlg:width="50" dlg:height="14" dlg:help-url="HID:WIZARDS_HID_DLGCORRESPONDENCE_CANCEL" dlg:value="CmdCancel" dlg:button-type="cancel">
+ <script:event script:event-name="on-performaction" script:macro-name="Template.ModuleAgenda.DisposeDocument" script:language="StarBasic"/>
+ </dlg:button>
+ <dlg:fixedline dlg:id="FrmLetter" dlg:tab-index="7" dlg:left="6" dlg:top="6" dlg:width="150" dlg:height="10" dlg:page="2" dlg:value="FrmLetter"/>
+ <dlg:fixedline dlg:id="FrmAgenda" dlg:tab-index="8" dlg:left="6" dlg:top="6" dlg:width="150" dlg:height="10" dlg:page="1" dlg:value="FrmAgenda"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/template/dialog.xlb b/wizards/source/template/dialog.xlb
new file mode 100644
index 000000000..c5eed37a2
--- /dev/null
+++ b/wizards/source/template/dialog.xlb
@@ -0,0 +1,7 @@
+<?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="Template" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="DialogStyles"/>
+ <library:element library:name="DlgGreeting"/>
+ <library:element library:name="TemplateDialog"/>
+</library:library>
diff --git a/wizards/source/template/script.xlb b/wizards/source/template/script.xlb
new file mode 100644
index 000000000..c89cc3788
--- /dev/null
+++ b/wizards/source/template/script.xlb
@@ -0,0 +1,8 @@
+<?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="Template" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="ModuleAgenda"/>
+ <library:element library:name="Correspondence"/>
+ <library:element library:name="Samples"/>
+ <library:element library:name="Autotext"/>
+ </library:library>
diff --git a/wizards/source/tools/Debug.xba b/wizards/source/tools/Debug.xba
new file mode 100644
index 000000000..fe909c5b8
--- /dev/null
+++ b/wizards/source/tools/Debug.xba
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Debug" script:language="StarBasic">REM ***** BASIC *****
+
+Sub ActivateReadOnlyFlag()
+ SetBasicReadOnlyFlag(True)
+End Sub
+
+
+Sub DeactivateReadOnlyFlag()
+ SetBasicReadOnlyFlag(False)
+End Sub
+
+
+Sub SetBasicReadOnlyFlag(bReadOnly as Boolean)
+Dim i as Integer
+Dim LibName as String
+Dim BasicLibNames() as String
+ BasicLibNames() = BasicLibraries.ElementNames()
+ For i = 0 To Ubound(BasicLibNames())
+ LibName = BasicLibNames(i)
+ If LibName &lt;&gt; &quot;Standard&quot; Then
+ BasicLibraries.SetLibraryReadOnly(LibName, bReadOnly)
+ End If
+ Next i
+End Sub
+
+
+Sub WritedbgInfo(LocObject as Object)
+Dim locUrl as String
+Dim oLocDocument as Object
+Dim oLocText as Object
+Dim oLocCursor as Object
+Dim NoArgs()
+Dim sObjectStrings(2) as String
+Dim sProperties() as String
+Dim n as Integer
+Dim m as Integer
+Dim MaxIndex as Integer
+ sObjectStrings(0) = LocObject.dbg_Properties
+ sObjectStrings(1) = LocObject.dbg_Methods
+ sObjectStrings(2) = LocObject.dbg_SupportedInterfaces
+ LocUrl = &quot;private:factory/swriter&quot;
+ oLocDocument = StarDesktop.LoadComponentFromURL(LocUrl,&quot;_default&quot;,0,NoArgs)
+ oLocText = oLocDocument.text
+ oLocCursor = oLocText.createTextCursor()
+ oLocCursor.gotoStart(False)
+ If Vartype(LocObject) = 9 then &apos; an Object Variable
+ For n = 0 To 2
+ sProperties() = ArrayoutofString(sObjectStrings(n),&quot;;&quot;, MaxIndex)
+ For m = 0 To MaxIndex
+ oLocText.insertString(oLocCursor,sProperties(m),False)
+ oLocText.insertControlCharacter(oLocCursor,com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK,False)
+ Next m
+ Next n
+ Elseif Vartype(LocObject) = 8 Then &apos; a String Variable
+ oLocText.insertString(oLocCursor,LocObject,False)
+ ElseIf Vartype(LocObject) = 1 Then
+ Msgbox(&quot;Variable is Null!&quot;, 16, GetProductName())
+ End If
+End Sub
+
+
+Sub WriteDbgString(LocString as string)
+Dim oLocDesktop as object
+Dim LocUrl as String
+Dim oLocDocument as Object
+Dim oLocCursor as Object
+Dim oLocText as Object
+
+ LocUrl = &quot;private:factory/swriter&quot;
+ oLocDocument = StarDesktop.LoadComponentFromURL(LocUrl,&quot;_default&quot;,0,NoArgs)
+ oLocText = oLocDocument.text
+ oLocCursor = oLocText.createTextCursor()
+ oLocCursor.gotoStart(False)
+ oLocText.insertString(oLocCursor,LocString,False)
+End Sub
+
+
+Sub printdbgInfo(LocObject)
+ If Vartype(LocObject) = 9 then
+ Msgbox LocObject.dbg_properties
+ Msgbox LocObject.dbg_methods
+ Msgbox LocObject.dbg_supportedinterfaces
+ Elseif Vartype(LocObject) = 8 Then &apos; a String Variable
+ Msgbox LocObject
+ ElseIf Vartype(LocObject) = 0 Then
+ Msgbox(&quot;Variable is Null!&quot;, 16, GetProductName())
+ Else
+ Msgbox(&quot;Type of Variable: &quot; &amp; Typename(LocObject), 48, GetProductName())
+ End If
+End Sub
+
+
+Sub ShowArray(LocArray())
+Dim i as integer
+Dim msgstring
+ msgstring = &quot;&quot;
+ For i = Lbound(LocArray()) to Ubound(LocArray())
+ msgstring = msgstring + LocArray(i) + chr(13)
+ Next
+ Msgbox msgstring
+End Sub
+
+
+Sub ShowPropertyValues(oLocObject as Object)
+Dim PropName as String
+Dim sValues as String
+ On Local Error Goto NOPROPERTYSETINFO:
+ sValues = &quot;&quot;
+ For i = 0 To Ubound(oLocObject.PropertySetInfo.Properties)
+ Propname = oLocObject.PropertySetInfo.Properties(i).Name
+ sValues = sValues &amp; PropName &amp; chr(13) &amp; &quot; = &quot; &amp; oLocObject.GetPropertyValue(PropName) &amp; chr(13)
+ Next i
+ Msgbox(sValues , 64, GetProductName())
+ Exit Sub
+
+NOPROPERTYSETINFO:
+ Msgbox(&quot;Sorry, No PropertySetInfo attached to the object&quot;, 16, GetProductName())
+ Resume LEAVEPROC
+ LEAVEPROC:
+End Sub
+
+
+Sub ShowNameValuePair(Pair())
+Dim i as Integer
+Dim ShowString as String
+ ShowString = &quot;&quot;
+ On Local Error Resume Next
+ For i = 0 To Ubound(Pair())
+ ShowString = ShowString &amp; Pair(i).Name &amp; &quot; = &quot;
+ ShowString = ShowString &amp; Pair(i).Value &amp; chr(13)
+ Next i
+ Msgbox ShowString
+End Sub
+
+
+&apos; Retrieves all the Elements of aSequence of an object, with the
+&apos; possibility to define a filter(sfilter &lt;&gt; &quot;&quot;)
+Sub ShowElementNames(oLocElements() as Object, Optional sFiltername as String)
+Dim i as Integer
+Dim NameString as String
+ NameString = &quot;&quot;
+ For i = 0 To Ubound(oLocElements())
+ If Not IsMissIng(sFilterName) Then
+ If Instr(1, oLocElements(i), sFilterName) Then
+ NameString = NameString &amp; oLocElements(i) &amp; chr(13)
+ End If
+ Else
+ NameString = NameString &amp; oLocElements(i) &amp; chr(13)
+ End If
+ Next i
+ Msgbox(NameString, 64, GetProductName())
+End Sub
+
+
+&apos; Retrieves all the supported servicenames of an object, with the
+&apos; possibility to define a filter(sfilter &lt;&gt; &quot;&quot;)
+Sub ShowSupportedServiceNames(oLocObject as Object, Optional sFilterName as String)
+ On Local Error Goto NOSERVICENAMES
+ If IsMissing(sFilterName) Then
+ ShowElementNames(oLocobject.SupportedServiceNames())
+ Else
+ ShowElementNames(oLocobject.SupportedServiceNames(), sFilterName)
+ End If
+ Exit Sub
+
+ NOSERVICENAMES:
+ Msgbox(&quot;Sorry, No &apos;SupportedServiceNames&apos; - Property attached to the object&quot;, 16, GetProductName())
+ Resume LEAVEPROC
+ LEAVEPROC:
+End Sub
+
+
+&apos; Retrieves all the available Servicenames of an object, with the
+&apos; possibility to define a filter(sfilter &lt;&gt; &quot;&quot;)
+Sub ShowAvailableServiceNames(oLocObject as Object, Optional sFilterName as String)
+ On Local Error Goto NOSERVICENAMES
+ If IsMissing(sFilterName) Then
+ ShowElementNames(oLocobject.AvailableServiceNames)
+ Else
+ ShowElementNames(oLocobject.AvailableServiceNames, sFilterName)
+ End If
+ Exit Sub
+
+ NOSERVICENAMES:
+ Msgbox(&quot;Sorry, No &apos;AvailableServiceNames&apos; - Property attached to the object&quot;, 16, GetProductName())
+ Resume LEAVEPROC
+ LEAVEPROC:
+End Sub
+
+
+Sub ShowCommands(oLocObject as Object)
+ On Local Error Goto NOCOMMANDS
+ ShowElementNames(oLocObject.QueryCommands)
+ Exit Sub
+ NOCOMMANDS:
+ Msgbox(&quot;Sorry, No &apos;QueryCommands&apos; - Property attached to the object&quot;, 16, GetProductName())
+ Resume LEAVEPROC
+ LEAVEPROC:
+End Sub
+
+
+Sub ProtectCurrentSheets()
+Dim oDocument as Object
+Dim sDocType as String
+Dim iResult as Integer
+Dim oSheets as Object
+Dim i as Integer
+Dim bDoProtect as Boolean
+ oDocument = StarDesktop.ActiveFrame.Controller.Model
+ sDocType = GetDocumentType(oDocument)
+ If sDocType = &quot;scalc&quot; Then
+ oSheets = oDocument.Sheets
+ bDoProtect = False
+ For i = 0 To oSheets.Count-1
+ If Not oSheets(i).IsProtected Then
+ bDoProtect = True
+ End If
+ Next i
+ If bDoProtect Then
+ iResult = Msgbox( &quot;Do you want to protect all sheets of this document?&quot;,35, GetProductName())
+ If iResult = 6 Then
+ ProtectSheets(oDocument.Sheets)
+ End If
+ End If
+ End If
+End Sub
+
+
+Sub FillDocument()
+ oMyReport = createUNOService(&quot;com.sun.star.wizards.report.CallReportWizard&quot;)
+ oMyReport.trigger(&quot;fill&quot;)
+End Sub
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/tools/DlgOverwriteAll.xdl b/wizards/source/tools/DlgOverwriteAll.xdl
new file mode 100644
index 000000000..b241a9bcc
--- /dev/null
+++ b/wizards/source/tools/DlgOverwriteAll.xdl
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="DlgOverwriteAll" dlg:left="138" dlg:top="75" dlg:width="230" dlg:height="64" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:text dlg:id="lblQueryforSave" dlg:tab-index="0" dlg:left="6" dlg:top="6" dlg:width="218" dlg:height="36" dlg:value="lblQueryforSave" dlg:multiline="true"/>
+ <dlg:button dlg:id="cmdYes" dlg:tab-index="1" dlg:left="6" dlg:top="43" dlg:width="50" dlg:height="14" dlg:value="cmdYes">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.ModuleControls.SetOVERWRITEToQuery?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdYesToAll" dlg:tab-index="2" dlg:left="62" dlg:top="43" dlg:width="50" dlg:height="14" dlg:value="cmdYesToAll">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.ModuleControls.SetOVERWRITEToAlways?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdNo" dlg:tab-index="3" dlg:left="118" dlg:top="43" dlg:width="50" dlg:height="14" dlg:default="true" dlg:value="cmdNo">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tools.ModuleControls.SetOVERWRITEToNever?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="cmdCancel" dlg:tab-index="4" dlg:left="174" dlg:top="43" dlg:width="50" dlg:height="14" dlg:value="cmdCancel" dlg:button-type="cancel"/>
+ </dlg:bulletinboard>
+</dlg:window>
diff --git a/wizards/source/tools/Listbox.xba b/wizards/source/tools/Listbox.xba
new file mode 100644
index 000000000..21f8f44c6
--- /dev/null
+++ b/wizards/source/tools/Listbox.xba
@@ -0,0 +1,370 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Listbox" script:language="StarBasic">Option Explicit
+Dim OriginalList()
+Dim oDialogModel as Object
+
+
+Sub MergeList(SourceListBox() as Object, SecondList() as String)
+Dim i as Integer
+Dim MaxIndex as Integer
+ MaxIndex = Ubound(SecondList())
+ OriginalList() = AddListToList(OriginalList(), SecondList())
+ For i = 0 To MaxIndex
+ SourceListbox = AddSingleItemToListbox(SourceListbox, SecondList(i))
+ Next i
+ Call FormSetMoveRights()
+End Sub
+
+
+Sub RemoveListItems(SourceListbox as Object, TargetListbox as Object, RemoveList() as String)
+Dim i as Integer
+Dim s as Integer
+Dim MaxIndex as Integer
+Dim CopyList()
+ MaxIndex = Ubound(RemoveList())
+ For i = 0 To MaxIndex
+ RemoveListboxItemByName(SourceListbox, RemoveList(i))
+ RemoveListboxItemByName(TargetListbox, RemoveList(i))
+ Next i
+ CopyList() = OriginalList()
+ s = 0
+ MaxIndex = Ubound(CopyList())
+ For i = 0 To MaxIndex
+ If IndexInArray(CopyList(i),RemoveList())= -1 Then
+ OriginalList(s) = CopyList(i)
+ s = s + 1
+ End If
+ Next i
+ ReDim Preserve OriginalList(s-1)
+ Call FormSetMoveRights()
+End Sub
+
+
+&apos; Note Boolean Parameter
+Sub InitializeListboxProcedures(oModel as Object, SourceListbox as Object, TargetListbox as Object)
+Dim EmptyList()
+ Set oDialogModel = oModel
+ OriginalList()= SourceListbox.StringItemList()
+ TargetListbox.StringItemList() = EmptyList()
+End Sub
+
+
+Sub CopyListboxItems(SourceListbox as Object, TargetListbox As Object)
+Dim NullArray()
+ TargetListbox.StringItemList() = OriginalList()
+ SourceListbox.StringItemList() = NullArray()
+End Sub
+
+
+Sub FormMoveSelected()
+ Call MoveSelectedListBox(oDialogModel.lstFields, oDialogModel.lstSelFields)
+ Call FormSetMoveRights()
+ oDialogModel.lstSelFields.Tag = True
+End Sub
+
+
+Sub FormMoveAll()
+ Call CopyListboxItems(oDialogModel.lstFields, oDialogModel.lstSelFields)
+ Call FormSetMoveRights()
+ oDialogModel.lstSelFields.Tag = True
+End Sub
+
+
+Sub FormRemoveSelected()
+ Call MoveOrderedSelectedListbox(oDialogModel.lstFields, oDialogModel.lstSelFields, False)
+ Call FormSetMoveRights()
+ oDialogModel.lstSelFields.Tag = True
+End Sub
+
+
+Sub FormRemoveAll()
+ Call MoveOrderedSelectedListbox(oDialogModel.lstFields, oDialogModel.lstSelFields, True)
+ Call FormSetMoveRights()
+ oDialogModel.lstSelFields.Tag = 1
+End Sub
+
+
+Sub MoveSelectedListBox(SourceListbox as Object, TargetListbox as Object)
+Dim MaxCurTarget as Integer
+Dim MaxSourceSelected as Integer
+Dim n as Integer
+Dim m as Integer
+Dim CurIndex
+Dim iOldTargetSelect as Integer
+Dim iOldSourceSelect as Integer
+ MaxCurTarget = Ubound(TargetListbox.StringItemList())
+ MaxSourceSelected = Ubound(SourceListbox.SelectedItems())
+ Dim TargetList(MaxCurTarget+MaxSourceSelected+1)
+ If MaxSourceSelected &gt; -1 Then
+ iOldSourceSelect = SourceListbox.SelectedItems(0)
+ If Ubound(TargetListbox.SelectedItems()) &gt; -1 Then
+ iOldTargetSelect = TargetListbox.SelectedItems(0)
+ Else
+ iOldTargetSelect = -1
+ End If
+ For n = 0 To MaxCurTarget
+ TargetList(n) = TargetListbox.StringItemList(n)
+ Next n
+ For m = 0 To MaxSourceSelected
+ CurIndex = SourceListbox.SelectedItems(m)
+ TargetList(n) = SourceListbox.StringItemList(CurIndex)
+ n = n + 1
+ Next m
+ TargetListBox.StringItemList() = TargetList()
+ SourceListbox.StringItemList() = RemoveSelected (SourceListbox)
+ SetNewSelection(SourceListbox, iOldSourceSelect)
+ SetNewSelection(TargetListbox, iOldTargetSelect)
+ End If
+End Sub
+
+
+
+Sub MoveOrderedSelectedListbox(lstSource as Object, lstTarget as Object, bMoveAll as Boolean)
+Dim NullArray()
+Dim MaxSelected as Integer
+Dim MaxSourceIndex as Integer
+Dim MaxOriginalIndex as Integer
+Dim MaxNewIndex as Integer
+Dim n as Integer
+Dim m as Integer
+Dim CurIndex as Integer
+Dim SearchString as String
+Dim SourceList() as String
+Dim iOldTargetSelect as Integer
+Dim iOldSourceSelect as Integer
+ If bMoveAll Then
+ lstSource.StringItemList() = OriginalList()
+ lstTarget.StringItemList() = NullArray()
+ Else
+ MaxOriginalIndex = Ubound(OriginalList())
+ MaxSelected = Ubound(lstTarget.SelectedItems())
+ iOldTargetSelect = lstTarget.SelectedItems(0)
+ If Ubound(lstSource.SelectedItems()) &gt; -1 Then
+ iOldSourceSelect = lstSource.SelectedItems(0)
+ End If
+ Dim SelList(MaxSelected)
+ For n = 0 To MaxSelected
+ CurIndex = lstTarget.SelectedItems(n)
+ SelList(n) = lstTarget.StringItemList(CurIndex)
+ Next n
+ SourceList() = lstSource.StringItemList()
+ MaxSourceIndex = Ubound(lstSource.StringItemList())
+ MaxNewIndex = MaxSelected + MaxSourceIndex + 1
+ Dim NewSourceList(MaxNewIndex)
+ m = 0
+ For n = 0 To MaxOriginalIndex
+ SearchString = OriginalList(n)
+ If IndexInArray(SearchString, SelList()) &lt;&gt; -1 Then
+ NewSourceList(m) = SearchString
+ m = m + 1
+ ElseIf IndexInArray(SearchString, SourceList()) &lt;&gt; -1 Then
+ NewSourceList(m) = SearchString
+ m = m + 1
+ End If
+ Next n
+ lstSource.StringItemList() = NewSourceList()
+ lstTarget.StringItemList() = RemoveSelected(lstTarget)
+ End If
+ SetNewSelection(lstSource, iOldSourceSelect)
+ SetNewSelection(lstTarget, iOldTargetSelect)
+
+End Sub
+
+
+Function RemoveSelected(oListbox as Object)
+Dim MaxIndex as Integer
+Dim MaxSelected as Integer
+Dim n as Integer
+Dim m as Integer
+Dim CurIndex as Integer
+Dim CurItem as String
+Dim ResultArray()
+ MaxIndex = Ubound(oListbox.StringItemList())
+ MaxSelected = Ubound(oListbox.SelectedItems())
+ Dim LocItemList(MaxIndex)
+ LocItemList() = oListbox.StringItemList()
+ If MaxSelected &gt; -1 Then
+ For n = 0 To MaxSelected
+ CurIndex = oListbox.SelectedItems(n)
+ LocItemList(CurIndex) = &quot;&quot;
+ Next n
+ If MaxIndex &gt; 0 Then
+ ReDim ResultArray(MaxIndex - MaxSelected - 1)
+ m = 0
+ For n = 0 To MaxIndex
+ CurItem = LocItemList(n)
+ If CurItem &lt;&gt; &quot;&quot; Then
+ ResultArray(m) = CurItem
+ m = m + 1
+ End If
+ Next n
+ End If
+ RemoveSelected = ResultArray()
+ Else
+ RemoveSelected = oListbox.StringItemList()
+ End If
+End Function
+
+
+Sub SetNewSelection(oListBox as Object, iLastSelection as Integer)
+Dim MaxIndex as Integer
+Dim SelIndex as Integer
+Dim SelList(0) as Integer
+ MaxIndex = Ubound(oListBox.StringItemList())
+ If MaxIndex &gt; -1 AND iLastSelection &gt; -1 Then
+ If iLastSelection &gt; MaxIndex Then
+ Selindex = MaxIndex
+ Else
+ SelIndex = iLastSelection
+ End If
+ Sellist(0) = SelIndex
+ oListBox.SelectedItems() = SelList()
+ End If
+End Sub
+
+
+Sub ToggleListboxControls(oDialogModel as Object, bDoEnable as Boolean)
+ With oDialogModel
+ .lblFields.Enabled = bDoEnable
+ .lblSelFields.Enabled = bDoEnable
+&apos; .lstTables.Enabled = bDoEnable
+ .lstFields.Enabled = bDoEnable
+ .lstSelFields.Enabled = bDoEnable
+ .cmdRemoveAll.Enabled = bDoEnable
+ .cmdRemoveSelected.Enabled = bDoEnable
+ .cmdMoveAll.Enabled = bDoEnable
+ .cmdMoveSelected.Enabled = bDoEnable
+ End With
+ If bDoEnable Then
+ FormSetMoveRights()
+ End If
+End Sub
+
+
+&apos; Enable or disable the buttons used for moving the available
+&apos; fields between the two list boxes.
+Sub FormSetMoveRights()
+Dim bIsFieldSelected as Boolean
+Dim bSelectSelected as Boolean
+Dim FieldCount as Integer
+Dim SelectCount as Integer
+ bIsFieldSelected = Ubound(oDialogModel.lstFields.SelectedItems()) &lt;&gt; -1
+ FieldCount = Ubound(oDialogModel.lstFields.StringItemList()) + 1
+ bSelectSelected = Ubound(oDialogModel.lstSelFields.SelectedItems()) &gt; -1
+ SelectCount = Ubound(oDialogModel.lstSelFields.StringItemList()) + 1
+ oDialogModel.cmdRemoveAll.Enabled = SelectCount&gt;=1
+ oDialogModel.cmdRemoveSelected.Enabled = bSelectSelected
+ oDialogModel.cmdMoveAll.Enabled = FieldCount &gt;=1
+ oDialogModel.cmdMoveSelected.Enabled = bIsFieldSelected
+ oDialogModel.cmdGoOn.Enabled = SelectCount&gt;=1
+ &apos; This flag is set to &apos;1&apos; when the lstSelFields has been modified
+End Sub
+
+
+Function AddSingleItemToListbox(ByVal oListbox as Object, ListItem as String, Optional iSelIndex) as Object
+Dim MaxIndex as Integer
+Dim i as Integer
+
+ MaxIndex = Ubound(oListbox.StringItemList())
+Dim LocList(MaxIndex + 1)
+&apos; Todo: This goes faster with the Redim LocList(MaxIndex + 1) Preserve function
+ For i = 0 To MaxIndex
+ LocList(i) = oListbox.StringItemList(i)
+ Next i
+ LocList(MaxIndex + 1) = ListItem
+ oListbox.StringItemList() = LocList()
+ If Not IsMissing(iSelIndex) Then
+ SelectListboxItem(oListbox, iSelIndex)
+ End If
+ AddSingleItemToListbox() = oListbox
+End Function
+
+
+Sub EmptyListbox(oListbox as Object)
+Dim NullList() as String
+ oListbox.StringItemList() = NullList()
+End Sub
+
+
+Sub SelectListboxItem(oListbox as Object, iSelIndex as Integer)
+Dim LocSelList(0) as Integer
+ If iSelIndex &lt;&gt; -1 Then
+ LocSelList(0) = iSelIndex
+ oListbox.SelectedItems() = LocSelList()
+ End If
+End Sub
+
+
+Function GetSelectedListboxItems(oListbox as Object)
+Dim SelList(Ubound(oListBox.SelectedItems())) as String
+Dim i as Integer
+Dim CurIndex as Integer
+ For i = 0 To Ubound(oListbox.SelectedItems())
+ CurIndex = oListbox.SelectedItems(i)
+ SelList(i) = oListbox.StringItemList(CurIndex)
+ Next i
+ GetSelectedListboxItems() = SelList()
+End Function
+
+
+&apos; Note: When using this Sub it must be ensured that the
+&apos; &apos;RemoveItem&apos; appears only once in the Listbox
+Sub RemoveListboxItemByName(oListbox as Object, RemoveItem as String)
+Dim OldList() as String
+Dim NullList() as String
+Dim i as Integer
+Dim a as Integer
+Dim MaxIndex as Integer
+ OldList = oListbox.StringItemList()
+ MaxIndex = Ubound(OldList())
+ If IndexInArray(RemoveItem, OldList()) &lt;&gt; -1 Then
+ If MaxIndex &gt; 0 Then
+ a = 0
+ Dim NewList(MaxIndex -1)
+ For i = 0 To MaxIndex
+ If RemoveItem &lt;&gt; OldList(i) Then
+ NewList(a) = OldList(i)
+ a = a + 1
+ End If
+ Next i
+ oListbox.StringItemList() = NewList()
+ Else
+ oListBox.StringItemList() = NullList()
+ End If
+ End If
+End Sub
+
+
+Function GetItemPos(oListBox as Object, sItem as String)
+Dim ItemList()
+Dim MaxIndex as Integer
+Dim i as Integer
+ ItemList() = oListBox.StringItemList()
+ MaxIndex = Ubound(ItemList())
+ For i = 0 To MaxIndex
+ If sItem = ItemList(i) Then
+ GetItemPos() = i
+ Exit Function
+ End If
+ Next i
+ GetItemPos() = -1
+End Function
+</script:module>
diff --git a/wizards/source/tools/Misc.xba b/wizards/source/tools/Misc.xba
new file mode 100644
index 000000000..9aa6d2e2f
--- /dev/null
+++ b/wizards/source/tools/Misc.xba
@@ -0,0 +1,834 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Misc" script:language="StarBasic">REM ***** BASIC *****
+
+Const SBSHARE = 0
+Const SBUSER = 1
+Dim Taskindex as Integer
+Dim oResSrv as Object
+
+Sub Main()
+Dim PropList(3,1)&apos; as String
+ PropList(0,0) = &quot;URL&quot;
+ PropList(0,1) = &quot;sdbc:odbc:Erica_Test_Unicode&quot;
+ PropList(1,0) = &quot;User&quot;
+ PropList(1,1) = &quot;extra&quot;
+ PropList(2,0) = &quot;Password&quot;
+ PropList(2,1) = &quot;extra&quot;
+ PropList(3,0) = &quot;IsPasswordRequired&quot;
+ PropList(3,1) = True
+End Sub
+
+
+Function RegisterNewDataSource(DSName as String, PropertyList(), Optional DriverProperties() as New com.sun.star.beans.PropertyValue)
+Dim oDataSource as Object
+Dim oDBContext as Object
+Dim oPropInfo as Object
+Dim i as Integer
+ oDBContext = createUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+ oDataSource = createUnoService(&quot;com.sun.star.sdb.DataSource&quot;)
+ For i = 0 To Ubound(PropertyList(), 1)
+ sPropName = PropertyList(i,0)
+ sPropValue = PropertyList(i,1)
+ oDataSource.SetPropertyValue(sPropName,sPropValue)
+ Next i
+ If Not IsMissing(DriverProperties()) Then
+ oDataSource.Info() = DriverProperties()
+ End If
+ oDBContext.RegisterObject(DSName, oDataSource)
+ RegisterNewDataSource () = oDataSource
+End Function
+
+
+&apos; Connects to a registered Database
+Function ConnectToDatabase(DSName as String, UserID as String, Password as String, Optional Propertylist(), Optional DriverProperties() as New com.sun.star.beans.PropertyValue)
+Dim oDBContext as Object
+Dim oDBSource as Object
+&apos; On Local Error Goto NOCONNECTION
+ oDBContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
+ If oDBContext.HasbyName(DSName) Then
+ oDBSource = oDBContext.GetByName(DSName)
+ ConnectToDatabase = oDBSource.GetConnection(UserID, Password)
+ Else
+ If Not IsMissing(Propertylist()) Then
+ RegisterNewDataSource(DSName, PropertyList(), DriverProperties())
+ oDBSource = oDBContext.GetByName(DSName)
+ ConnectToDatabase = oDBSource.GetConnection(UserID, Password)
+ Else
+ Msgbox(&quot;DataSource &quot; &amp; DSName &amp; &quot; is not registered&quot; , 16, GetProductname())
+ ConnectToDatabase() = NULL
+ End If
+ End If
+NOCONNECTION:
+ If Err &lt;&gt; 0 Then
+ Msgbox(Error$, 16, GetProductName())
+ Resume LEAVESUB
+ LEAVESUB:
+ End If
+End Function
+
+
+Function GetStarOfficeLocale() as New com.sun.star.lang.Locale
+Dim aLocLocale As New com.sun.star.lang.Locale
+Dim sLocale as String
+Dim sLocaleList(1)
+Dim oMasterKey
+ oMasterKey = GetRegistryKeyContent(&quot;org.openoffice.Setup/L10N/&quot;)
+ sLocale = oMasterKey.getByName(&quot;ooLocale&quot;)
+ sLocaleList() = ArrayoutofString(sLocale, &quot;-&quot;)
+ aLocLocale.Language = sLocaleList(0)
+ If Ubound(sLocaleList()) &gt; 0 Then
+ aLocLocale.Country = sLocaleList(1)
+ End If
+ If Ubound(sLocaleList()) &gt; 1 Then
+ aLocLocale.Variant = sLocaleList(2)
+ End If
+ GetStarOfficeLocale() = aLocLocale
+End Function
+
+
+Function GetRegistryKeyContent(sKeyName as string, Optional bforUpdate as Boolean)
+Dim oConfigProvider as Object
+Dim aNodePath(0) as new com.sun.star.beans.PropertyValue
+ oConfigProvider = createUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
+ aNodePath(0).Name = &quot;nodepath&quot;
+ aNodePath(0).Value = sKeyName
+ If IsMissing(bForUpdate) Then bForUpdate = False
+ If bForUpdate Then
+ GetRegistryKeyContent() = oConfigProvider.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationUpdateAccess&quot;, aNodePath())
+ Else
+ GetRegistryKeyContent() = oConfigProvider.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationAccess&quot;, aNodePath())
+ End If
+End Function
+
+
+Function GetProductname() as String
+Dim oProdNameAccess as Object
+Dim sVersion as String
+Dim sProdName as String
+ oProdNameAccess = GetRegistryKeyContent(&quot;org.openoffice.Setup/Product&quot;)
+ sProdName = oProdNameAccess.getByName(&quot;ooName&quot;)
+ sVersion = oProdNameAccess.getByName(&quot;ooSetupVersion&quot;)
+ GetProductName = sProdName &amp; sVersion
+End Function
+
+
+&apos; Opens a Document, checks beforehand, whether it has to be loaded
+&apos; or whether it is already on the desktop.
+&apos; If the parameter bDisposable is set to False then the returned document
+&apos; should not be disposed afterwards, because it is already opened.
+Function OpenDocument(DocPath as String, Args(), Optional bDisposable as Boolean)
+Dim oComponents as Object
+Dim oComponent as Object
+ &apos; Search if one of the active Components is the one that you search for
+ oComponents = StarDesktop.Components.CreateEnumeration
+ While oComponents.HasmoreElements
+ oComponent = oComponents.NextElement
+ If hasUnoInterfaces(oComponent,&quot;com.sun.star.frame.XModel&quot;) then
+ If UCase(oComponent.URL) = UCase(DocPath) then
+ OpenDocument() = oComponent
+ If Not IsMissing(bDisposable) Then
+ bDisposable = False
+ End If
+ Exit Function
+ End If
+ End If
+ Wend
+ If Not IsMissing(bDisposable) Then
+ bDisposable = True
+ End If
+ OpenDocument() = StarDesktop.LoadComponentFromURL(DocPath,&quot;_default&quot;,0,Args())
+End Function
+
+
+Function TaskonDesktop(DocPath as String) as Boolean
+Dim oComponents as Object
+Dim oComponent as Object
+ &apos; Search if one of the active Components is the one that you search for
+ oComponents = StarDesktop.Components.CreateEnumeration
+ While oComponents.HasmoreElements
+ oComponent = oComponents.NextElement
+ If hasUnoInterfaces(oComponent,&quot;com.sun.star.frame.XModel&quot;) then
+ If UCase(oComponent.URL) = UCase(DocPath) then
+ TaskonDesktop = True
+ Exit Function
+ End If
+ End If
+ Wend
+ TaskonDesktop = False
+End Function
+
+
+&apos; Retrieves a FileName out of a StarOffice-Document
+Function RetrieveFileName(LocDoc as Object)
+Dim LocURL as String
+Dim LocURLArray() as String
+Dim MaxArrIndex as integer
+
+ LocURL = LocDoc.Url
+ LocURLArray() = ArrayoutofString(LocURL,&quot;/&quot;,MaxArrIndex)
+ RetrieveFileName = LocURLArray(MaxArrIndex)
+End Function
+
+
+&apos; Gets a special configured PathSetting
+Function GetPathSettings(sPathType as String, Optional bshowall as Boolean, Optional ListIndex as integer) as String
+Dim oSettings, oPathSettings as Object
+Dim sPath as String
+Dim PathList() as String
+Dim MaxIndex as Integer
+Dim oPS as Object
+
+ oPS = createUnoService(&quot;com.sun.star.util.PathSettings&quot;)
+
+ If Not IsMissing(bShowall) Then
+ If bShowAll Then
+ ShowPropertyValues(oPS)
+ Exit Function
+ End If
+ End If
+ sPath = oPS.getPropertyValue(sPathType)
+ If Not IsMissing(ListIndex) Then
+ &apos; Share and User-Directory
+ If Instr(1,sPath,&quot;;&quot;) &lt;&gt; 0 Then
+ PathList = ArrayoutofString(sPath,&quot;;&quot;, MaxIndex)
+ If ListIndex &lt;= MaxIndex Then
+ sPath = PathList(ListIndex)
+ Else
+ Msgbox(&quot;String Cannot be analyzed!&quot; &amp; sPath , 16, GetProductName())
+ End If
+ End If
+ End If
+ If Instr(1, sPath, &quot;;&quot;) = 0 Then
+ GetPathSettings = ConvertToUrl(sPath)
+ Else
+ GetPathSettings = sPath
+ End If
+
+End Function
+
+
+
+&apos; Gets the fully qualified path to a subdirectory of the
+&apos; Template Directory, e. g. with the parameter &quot;wizard/bitmap&quot;
+&apos; The parameter must be passed in Url notation
+&apos; The return-Value is in Url notation
+Function GetOfficeSubPath(sOfficePath as String, ByVal sSubDir as String)
+Dim sOfficeString as String
+Dim sOfficeList() as String
+Dim sOfficeDir as String
+Dim sBigDir as String
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim oUcb as Object
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ sOfficeString = GetPathSettings(sOfficePath)
+ If Right(sSubDir,1) &lt;&gt; &quot;/&quot; Then
+ sSubDir = sSubDir &amp; &quot;/&quot;
+ End If
+ sOfficeList() = ArrayoutofString(sOfficeString,&quot;;&quot;, MaxIndex)
+ For i = 0 To MaxIndex
+ sOfficeDir = ConvertToUrl(sOfficeList(i))
+ If Right(sOfficeDir,1) &lt;&gt; &quot;/&quot; Then
+ sOfficeDir = sOfficeDir &amp; &quot;/&quot;
+ End If
+ sBigDir = sOfficeDir &amp; sSubDir
+ If oUcb.Exists(sBigDir) Then
+ GetOfficeSubPath() = sBigDir
+ Exit Function
+ End If
+ Next i
+ ShowNoOfficePathError()
+ GetOfficeSubPath = &quot;&quot;
+End Function
+
+
+Sub ShowNoOfficePathError()
+Dim ProductName as String
+Dim sError as String
+Dim bResObjectexists as Boolean
+Dim oLocResSrv as Object
+ bResObjectexists = not IsNull(oResSrv)
+ If bResObjectexists Then
+ oLocResSrv = oResSrv
+ End If
+ If InitResources(&quot;Tools&quot;) Then
+ ProductName = GetProductName()
+ sError = GetResText(&quot;RID_COMMON_6&quot;)
+ sError = ReplaceString(sError, ProductName, &quot;%PRODUCTNAME&quot;)
+ sError = ReplaceString(sError, chr(13), &quot;&lt;BR&gt;&quot;)
+ MsgBox(sError, 16, ProductName)
+ End If
+ If bResObjectexists Then
+ oResSrv = oLocResSrv
+ End If
+
+End Sub
+
+
+Function InitResources(Description) as boolean
+Dim xResource as Object
+Dim sOfficeDir as String
+Dim aArgs(5) as Any
+ On Error Goto ErrorOccurred
+ sOfficeDir = &quot;$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/wizards/&quot;
+ sOfficeDir = GetDefaultContext.getByName(&quot;/singletons/com.sun.star.util.theMacroExpander&quot;).ExpandMacros(sOfficeDir)
+ aArgs(0) = sOfficeDir
+ aArgs(1) = true
+ aArgs(2) = GetStarOfficeLocale()
+ aArgs(3) = &quot;resources&quot;
+ aArgs(4) = &quot;&quot;
+ aArgs(5) = NULL
+ oResSrv = getProcessServiceManager().createInstanceWithArguments( &quot;com.sun.star.resource.StringResourceWithLocation&quot;, aArgs() )
+ If (IsNull(oResSrv)) then
+ InitResources = FALSE
+ MsgBox(&quot;could not initialize StringResourceWithLocation&quot;)
+ Else
+ InitResources = TRUE
+ End If
+ Exit Function
+ErrorOccurred:
+ Dim nSolarVer
+ InitResources = FALSE
+ nSolarVer = GetSolarVersion()
+ MsgBox(&quot;Resource file missing&quot;, 16, GetProductName())
+ Resume CLERROR
+ CLERROR:
+End Function
+
+
+Function GetResText( sID as String ) As string
+Dim sString as String
+ On Error Goto ErrorOccurred
+ If Not IsNull(oResSrv) Then
+ sString = oResSrv.resolveString(sID)
+ GetResText = ReplaceString(sString, GetProductname(), &quot;%PRODUCTNAME&quot;)
+ Else
+ GetResText = &quot;&quot;
+ End If
+ Exit Function
+ErrorOccurred:
+ GetResText = &quot;&quot;
+ MsgBox(&quot;Resource with ID =&quot; + sID + &quot; not found!&quot;, 16, GetProductName())
+ Resume CLERROR
+ CLERROR:
+End Function
+
+
+Function CutPathView(sDocUrl as String, Optional PathLen as Integer)
+Dim sViewPath as String
+Dim FileName as String
+Dim iFileLen as Integer
+ sViewPath = ConvertfromURL(sDocURL)
+ iViewPathLen = Len(sViewPath)
+ If iViewPathLen &gt; 60 Then
+ FileName = FileNameoutofPath(sViewPath, &quot;/&quot;)
+ iFileLen = Len(FileName)
+ If iFileLen &lt; 44 Then
+ sViewPath = Left(sViewPath,57-iFileLen-10) &amp; &quot;...&quot; &amp; Right(sViewPath,iFileLen + 10)
+ Else
+ sViewPath = Left(sViewPath,27) &amp; &quot; ... &quot; &amp; Right(sViewPath,28)
+ End If
+ End If
+ CutPathView = sViewPath
+End Function
+
+
+&apos; Deletes the content of all cells that are softformatted according
+&apos; to the &apos;InputStyleName&apos;
+Sub DeleteInputCells(oSheet as Object, InputStyleName as String)
+Dim oRanges as Object
+Dim oRange as Object
+ oRanges = oSheet.CellFormatRanges.createEnumeration
+ While oRanges.hasMoreElements
+ oRange = oRanges.NextElement
+ If Instr(1,oRange.CellStyle, InputStyleName) &lt;&gt; 0 Then
+ Call ReplaceRangeValues(oRange, &quot;&quot;)
+ End If
+ Wend
+End Sub
+
+
+&apos; Inserts a certain string to all cells of a range that is passed
+&apos; either as an object or as the RangeName
+Sub ChangeValueofRange(oSheet as Object, Range, ReplaceValue, Optional StyleName as String)
+Dim oCellRange as Object
+ If Vartype(Range) = 8 Then
+ &apos; Get the Range out of the Rangename
+ oCellRange = oSheet.GetCellRangeByName(Range)
+ Else
+ &apos; The range is passed as an object
+ Set oCellRange = Range
+ End If
+ If IsMissing(StyleName) Then
+ ReplaceRangeValues(oCellRange, ReplaceValue)
+ Else
+ If Instr(1,oCellRange.CellStyle,StyleName) Then
+ ReplaceRangeValues(oCellRange, ReplaceValue)
+ End If
+ End If
+End Sub
+
+
+Sub ReplaceRangeValues(oRange as Object, ReplaceValue)
+Dim oRangeAddress as Object
+Dim ColCount as Integer
+Dim RowCount as Integer
+Dim i as Integer
+ oRangeAddress = oRange.RangeAddress
+ ColCount = oRangeAddress.EndColumn - oRangeAddress.StartColumn
+ RowCount = oRangeAddress.EndRow - oRangeAddress.StartRow
+ Dim FillArray(RowCount) as Variant
+ Dim sLine(ColCount) as Variant
+ For i = 0 To ColCount
+ sLine(i) = ReplaceValue
+ Next i
+ For i = 0 To RowCount
+ FillArray(i) = sLine()
+ Next i
+ oRange.DataArray = FillArray()
+End Sub
+
+
+&apos; Returns the Value of the first cell of a Range
+Function GetValueofCellbyName(oSheet as Object, sCellName as String)
+Dim oCell as Object
+ oCell = GetCellByName(oSheet, sCellName)
+ GetValueofCellbyName = oCell.Value
+End Function
+
+
+Function DuplicateRow(oSheet as Object, RangeName as String)
+Dim oRange as Object
+Dim oCell as Object
+Dim oCellAddress as New com.sun.star.table.CellAddress
+Dim oRangeAddress as New com.sun.star.table.CellRangeAddress
+ oRange = oSheet.GetCellRangeByName(RangeName)
+ oRangeAddress = oRange.RangeAddress
+ oCell = oSheet.GetCellByPosition(oRangeAddress.StartColumn,oRangeAddress.StartRow)
+ oCellAddress = oCell.CellAddress
+ oSheet.Rows.InsertByIndex(oCellAddress.Row,1)
+ oRangeAddress = oRange.RangeAddress
+ oSheet.CopyRange(oCellAddress, oRangeAddress)
+ DuplicateRow = oRangeAddress.StartRow-1
+End Function
+
+
+&apos; Returns the String of the first cell of a Range
+Function GetStringofCellbyName(oSheet as Object, sCellName as String)
+Dim oCell as Object
+ oCell = GetCellByName(oSheet, sCellName)
+ GetStringofCellbyName = oCell.String
+End Function
+
+
+&apos; Returns a named Cell
+Function GetCellByName(oSheet as Object, sCellName as String) as Object
+Dim oCellRange as Object
+Dim oCellAddress as Object
+ oCellRange = oSheet.GetCellRangeByName(sCellName)
+ oCellAddress = oCellRange.RangeAddress
+ GetCellByName = oSheet.GetCellByPosition(oCellAddress.StartColumn,oCellAddress.StartRow)
+End Function
+
+
+&apos; Changes the numeric Value of a cell by transmitting the String of the numeric Value
+Sub ChangeCellValue(oCell as Object, ValueString as String)
+Dim CellValue
+ oCell.Formula = &quot;=Value(&quot; &amp; &quot;&quot;&quot;&quot; &amp; ValueString &amp; &quot;&quot;&quot;&quot; &amp; &quot;)&quot;
+ CellValue = oCell.Value
+ oCell.Formula = &quot;&quot;
+ oCell.Value = CellValue
+End Sub
+
+
+Function GetDocumentType(oDocument)
+ On Local Error GoTo NODOCUMENTTYPE
+&apos; ShowSupportedServiceNames(oDocument)
+ If oDocument.SupportsService(&quot;com.sun.star.sheet.SpreadsheetDocument&quot;) Then
+ GetDocumentType() = &quot;scalc&quot;
+ ElseIf oDocument.SupportsService(&quot;com.sun.star.text.TextDocument&quot;) Then
+ GetDocumentType() = &quot;swriter&quot;
+ ElseIf oDocument.SupportsService(&quot;com.sun.star.drawing.DrawingDocument&quot;) Then
+ GetDocumentType() = &quot;sdraw&quot;
+ ElseIf oDocument.SupportsService(&quot;com.sun.star.presentation.PresentationDocument&quot;) Then
+ GetDocumentType() = &quot;simpress&quot;
+ ElseIf oDocument.SupportsService(&quot;com.sun.star.formula.FormulaProperties&quot;) Then
+ GetDocumentType() = &quot;smath&quot;
+ End If
+ NODOCUMENTTYPE:
+ If Err &lt;&gt; 0 Then
+ GetDocumentType = &quot;&quot;
+ Resume GOON
+ GOON:
+ End If
+End Function
+
+
+Function GetNumberFormatType(oDocFormats, oFormatObject as Object) as Integer
+Dim ThisFormatKey as Long
+Dim oObjectFormat as Object
+ On Local Error Goto NOFORMAT
+ ThisFormatKey = oFormatObject.NumberFormat
+ oObjectFormat = oDocFormats.GetByKey(ThisFormatKey)
+ GetNumberFormatType = oObjectFormat.Type
+ NOFORMAT:
+ If Err &lt;&gt; 0 Then
+ Msgbox(&quot;Numberformat of Object is not available!&quot;, 16, GetProductName())
+ GetNumberFormatType = 0
+ GOTO NOERROR
+ End If
+ NOERROR:
+ On Local Error Goto 0
+End Function
+
+
+Sub ProtectSheets(Optional oSheets as Object)
+Dim i as Integer
+Dim oDocSheets as Object
+ If IsMissing(oSheets) Then
+ oDocSheets = StarDesktop.CurrentFrame.Controller.Model.Sheets
+ Else
+ Set oDocSheets = oSheets
+ End If
+
+ For i = 0 To oDocSheets.Count-1
+ oDocSheets(i).Protect(&quot;&quot;)
+ Next i
+End Sub
+
+
+Sub UnprotectSheets(Optional oSheets as Object)
+Dim i as Integer
+Dim oDocSheets as Object
+ If IsMissing(oSheets) Then
+ oDocSheets = StarDesktop.CurrentFrame.Controller.Model.Sheets
+ Else
+ Set oDocSheets = oSheets
+ End If
+
+ For i = 0 To oDocSheets.Count-1
+ oDocSheets(i).Unprotect(&quot;&quot;)
+ Next i
+End Sub
+
+
+Function GetRowIndex(oSheet as Object, RowName as String)
+Dim oRange as Object
+ oRange = oSheet.GetCellRangeByName(RowName)
+ GetRowIndex = oRange.RangeAddress.StartRow
+End Function
+
+
+Function GetColumnIndex(oSheet as Object, ColName as String)
+Dim oRange as Object
+ oRange = oSheet.GetCellRangeByName(ColName)
+ GetColumnIndex = oRange.RangeAddress.StartColumn
+End Function
+
+
+Function CopySheetbyName(oSheets as Object, OldName as String, NewName as String, DestPos as Integer) as Object
+Dim oSheet as Object
+Dim Count as Integer
+Dim BasicSheetName as String
+
+ BasicSheetName = NewName
+ &apos; Copy the last table. Assumption: The last table is the template
+ On Local Error Goto RENAMESHEET
+ oSheets.CopybyName(OldName, NewName, DestPos)
+
+RENAMESHEET:
+ oSheet = oSheets(DestPos)
+ If Err &lt;&gt; 0 Then
+ &apos; Test if renaming failed
+ Count = 2
+ Do While oSheet.Name &lt;&gt; NewName
+ NewName = BasicSheetName &amp; &quot;_&quot; &amp; Count
+ oSheet.Name = NewName
+ Count = Count + 1
+ Loop
+ Resume CL_ERROR
+CL_ERROR:
+ End If
+ CopySheetbyName = oSheet
+End Function
+
+
+&apos; Dis-or enables a Window and adjusts the mousepointer accordingly
+Sub ToggleWindow(bDoEnable as Boolean)
+Dim oWindow as Object
+ oWindow = StarDesktop.CurrentFrame.ComponentWindow
+ oWindow.Enable = bDoEnable
+End Sub
+
+
+Function CheckNewSheetname(oSheets as Object, Sheetname as String, Optional oLocale) as String
+Dim nStartFlags as Long
+Dim nContFlags as Long
+Dim oCharService as Object
+Dim iSheetNameLength as Integer
+Dim iResultPos as Integer
+Dim WrongChar as String
+Dim oResult as Object
+ nStartFlags = com.sun.star.i18n.KParseTokens.ANY_LETTER_OR_NUMBER + com.sun.star.i18n.KParseTokens.ASC_UNDERSCORE
+ nContFlags = nStartFlags
+ oCharService = CreateUnoService(&quot;com.sun.star.i18n.CharacterClassification&quot;)
+ iSheetNameLength = Len(SheetName)
+ If IsMissing(oLocale) Then
+ oLocale = ThisComponent.CharLocale
+ End If
+ Do
+ oResult =oCharService.parsePredefinedToken(com.sun.star.i18n.KParseType.IDENTNAME, SheetName, 0, oLocale, nStartFlags, &quot;&quot;, nContFlags, &quot; &quot;)
+ iResultPos = oResult.EndPos
+ If iResultPos &lt; iSheetNameLength Then
+ WrongChar = Mid(SheetName, iResultPos+1,1)
+ SheetName = ReplaceString(SheetName,&quot;_&quot;, WrongChar)
+ End If
+ Loop Until iResultPos = iSheetNameLength
+ CheckNewSheetname = SheetName
+End Function
+
+
+Sub AddNewSheetName(oSheets as Object, ByVal SheetName as String)
+Dim Count as Integer
+Dim bSheetIsThere as Boolean
+Dim iSheetNameLength as Integer
+ iSheetNameLength = Len(SheetName)
+ Count = 2
+ Do
+ bSheetIsThere = oSheets.HasByName(SheetName)
+ If bSheetIsThere Then
+ SheetName = Right(SheetName,iSheetNameLength) &amp; &quot;_&quot; &amp; Count
+ Count = Count + 1
+ End If
+ Loop Until Not bSheetIsThere
+ AddNewSheetname = SheetName
+End Sub
+
+
+Function GetSheetIndex(oSheets, sName) as Integer
+Dim i as Integer
+ For i = 0 To oSheets.Count-1
+ If oSheets(i).Name = sName Then
+ GetSheetIndex = i
+ exit Function
+ End If
+ Next i
+ GetSheetIndex = -1
+End Function
+
+
+Function GetLastUsedRow(oSheet as Object) as Long
+Dim oCell As Object
+Dim oCursor As Object
+Dim aAddress As Variant
+ oCell = oSheet.GetCellbyPosition(0, 0)
+ oCursor = oSheet.createCursorByRange(oCell)
+ oCursor.GotoEndOfUsedArea(True)
+ aAddress = oCursor.RangeAddress
+ GetLastUsedRow = aAddress.EndRow
+End Function
+
+
+&apos; Note To set a one lined frame you have to set the inner width to 0
+&apos; In the API all Units that refer to pt-Heights are &quot;1/100mm&quot;
+&apos; The convert factor from 1pt to 1/100 mm is approximately 35
+Function ModifyBorderLineWidth(ByVal oStyleBorder, iInnerLineWidth as Integer, iOuterLineWidth as Integer)
+Dim aBorder as New com.sun.star.table.BorderLine
+ aBorder = oStyleBorder
+ aBorder.InnerLineWidth = iInnerLineWidth
+ aBorder.OuterLineWidth = iOuterLineWidth
+ ModifyBorderLineWidth = aBorder
+End Function
+
+
+Sub AttachBasicMacroToEvent(oDocument as Object, EventName as String, SubPath as String)
+Dim PropValue(1) as new com.sun.star.beans.PropertyValue
+ PropValue(0).Name = &quot;EventType&quot;
+ PropValue(0).Value = &quot;StarBasic&quot;
+ PropValue(1).Name = &quot;Script&quot;
+ PropValue(1).Value = &quot;macro:///&quot; &amp; SubPath
+ oDocument.Events.ReplaceByName(EventName, PropValue())
+End Sub
+
+
+
+Function ModifyPropertyValue(oContent() as New com.sun.star.beans.PropertyValue, TargetProperties() as New com.sun.star.beans.PropertyValue)
+Dim MaxIndex as Integer
+Dim i as Integer
+Dim a as Integer
+ MaxIndex = Ubound(oContent())
+ bDoReplace = False
+ For i = 0 To MaxIndex
+ a = GetPropertyValueIndex(oContent(i).Name, TargetProperties())
+ If a &lt;&gt; -1 Then
+ If Vartype(TargetProperties(a).Value) &lt;&gt; 9 Then
+ If TargetProperties(a).Value &lt;&gt; oContent(i).Value Then
+ oContent(i).Value = TargetProperties(a).Value
+ bDoReplace = True
+ End If
+ Else
+ If Not EqualUnoObjects(TargetProperties(a).Value, oContent(i).Value) Then
+ oContent(i).Value = TargetProperties(a).Value
+ bDoReplace = True
+ End If
+ End If
+ End If
+ Next i
+ ModifyPropertyValue() = bDoReplace
+End Function
+
+
+Function GetPropertyValueIndex(SearchName as String, TargetProperties() as New com.sun.star.beans.PropertyValue ) as Integer
+Dim i as Integer
+ For i = 0 To Ubound(TargetProperties())
+ If Searchname = TargetProperties(i).Name Then
+ GetPropertyValueIndex = i
+ Exit Function
+ End If
+ Next i
+ GetPropertyValueIndex() = -1
+End Function
+
+
+Sub DispatchSlot(SlotID as Integer)
+Dim oArg() as new com.sun.star.beans.PropertyValue
+Dim oUrl as new com.sun.star.util.URL
+Dim oTrans as Object
+Dim oDisp as Object
+ oTrans = createUNOService(&quot;com.sun.star.util.URLTransformer&quot;)
+ oUrl.Complete = &quot;slot:&quot; &amp; CStr(SlotID)
+ oTrans.parsestrict(oUrl)
+ oDisp = StarDesktop.ActiveFrame.queryDispatch(oUrl, &quot;_self&quot;, 0)
+ oDisp.dispatch(oUrl, oArg())
+End Sub
+
+
+&apos;returns the type of the office application
+&apos;FatOffice = 0, WebTop = 1
+&apos;This routine has to be changed if the Product Name is being changed!
+Function IsFatOffice() As Boolean
+ If sProductname = &quot;&quot; Then
+ sProductname = GetProductname()
+ End If
+ IsFatOffice = TRUE
+ &apos;The following line has to include the current productname
+ If Instr(1,sProductname,&quot;WebTop&quot;,1) &lt;&gt; 0 Then
+ IsFatOffice = FALSE
+ End If
+End Function
+
+
+Sub ToggleDesignMode(oDocument as Object)
+Dim aSwitchMode as new com.sun.star.util.URL
+ aSwitchMode.Complete = &quot;.uno:SwitchControlDesignMode&quot;
+ aTransformer = createUnoService(&quot;com.sun.star.util.URLTransformer&quot;)
+ aTransformer.parseStrict(aSwitchMode)
+ oFrame = oDocument.currentController.Frame
+ oDispatch = oFrame.queryDispatch(aSwitchMode, oFrame.Name, 63)
+ Dim aEmptyArgs() as New com.sun.star.bean.PropertyValue
+ oDispatch.dispatch(aSwitchMode, aEmptyArgs())
+ Erase aSwitchMode
+End Sub
+
+
+Function isHighContrast(oPeer as Object)
+ Dim UIColor as Long
+ Dim myRed as Integer
+ Dim myGreen as Integer
+ Dim myBlue as Integer
+ Dim myLuminance as Double
+
+ UIColor = oPeer.getProperty( &quot;DisplayBackgroundColor&quot; )
+ myRed = Red (UIColor)
+ myGreen = Green (UIColor)
+ myBlue = Blue (UIColor)
+ myLuminance = (( myBlue*28 + myGreen*151 + myRed*77 ) / 256 )
+ isHighContrast = false
+ If myLuminance &lt;= 25 Then isHighContrast = true
+End Function
+
+
+Function CreateNewDocument(sType as String, Optional sAddMsg as String) as Object
+Dim NoArgs() as new com.sun.star.beans.PropertyValue
+Dim oDocument as Object
+Dim sUrl as String
+Dim ErrMsg as String
+ On Local Error Goto NOMODULEINSTALLED
+ sUrl = &quot;private:factory/&quot; &amp; sType
+ oDocument = StarDesktop.LoadComponentFromURL(sUrl,&quot;_default&quot;,0, NoArgs())
+NOMODULEINSTALLED:
+ If (Err &lt;&gt; 0) OR IsNull(oDocument) Then
+ If InitResources(&quot;&quot;) Then
+ Select Case sType
+ Case &quot;swriter&quot;
+ ErrMsg = GetResText(&quot;RID_COMMON_1&quot;)
+ Case &quot;scalc&quot;
+ ErrMsg = GetResText(&quot;RID_COMMON_2&quot;)
+ Case &quot;simpress&quot;
+ ErrMsg = GetResText(&quot;RID_COMMON_3&quot;)
+ Case &quot;sdraw&quot;
+ ErrMsg = GetResText(&quot;RID_COMMON_4&quot;)
+ Case &quot;smath&quot;
+ ErrMsg = GetResText(&quot;RID_COMMON_5&quot;)
+ Case Else
+ ErrMsg = &quot;Invalid Document Type!&quot;
+ End Select
+ ErrMsg = ReplaceString(ErrMsg, chr(13), &quot;&lt;BR&gt;&quot;)
+ If Not IsMissing(sAddMsg) Then
+ ErrMsg = ErrMsg &amp; chr(13) &amp; sAddMsg
+ End If
+ Msgbox(ErrMsg, 48, GetProductName())
+ End If
+ If Err &lt;&gt; 0 Then
+ Resume GOON
+ End If
+ End If
+GOON:
+ CreateNewDocument = oDocument
+End Function
+
+
+&apos; This Sub has been used in order to ensure that after disposing a document
+&apos; from the backing window it is returned to the backing window, so the
+&apos; office won&apos;t be closed
+Sub DisposeDocument(oDocument as Object)
+Dim dispatcher as Object
+Dim parser as Object
+Dim disp as Object
+Dim url as new com.sun.star.util.URL
+Dim NoArgs() as New com.sun.star.beans.PropertyValue
+Dim oFrame as Object
+ If Not IsNull(oDocument) Then
+ oDocument.setModified(false)
+ parser = createUnoService(&quot;com.sun.star.util.URLTransformer&quot;)
+ url.Complete = &quot;.uno:CloseDoc&quot;
+ parser.parseStrict(url)
+ oFrame = oDocument.CurrentController.Frame
+ disp = oFrame.queryDispatch(url,&quot;_self&quot;, com.sun.star.util.SearchFlags.NORM_WORD_ONLY)
+ disp.dispatch(url, NoArgs())
+ End If
+End Sub
+
+&apos;Function to calculate if the year is a leap year
+Function CalIsLeapYear(ByVal iYear as Integer) as Boolean
+ CalIsLeapYear = ((iYear Mod 4 = 0) And ((iYear Mod 100 &lt;&gt; 0) Or (iYear Mod 400 = 0)))
+End Function
+</script:module>
diff --git a/wizards/source/tools/ModuleControls.xba b/wizards/source/tools/ModuleControls.xba
new file mode 100644
index 000000000..059956cb1
--- /dev/null
+++ b/wizards/source/tools/ModuleControls.xba
@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ModuleControls" script:language="StarBasic">Option Explicit
+
+Public DlgOverwrite as Object
+Public Const SBOVERWRITEUNDEFINED as Integer = 0
+Public Const SBOVERWRITECANCEL as Integer = 2
+Public Const SBOVERWRITEQUERY as Integer = 7
+Public Const SBOVERWRITEALWAYS as Integer = 6
+Public Const SBOVERWRITENEVER as Integer = 8
+Public iGeneralOverwrite as Integer
+
+
+
+&apos; Accepts the name of a control and returns the respective control model as object
+&apos; The Container can either be a whole document or a specific sheet of a Calc-Document
+&apos; &apos;CName&apos; is the name of the Control
+Function getControlModel(oContainer as Object, CName as String)
+Dim aForm, oForms as Object
+Dim i as Integer
+ oForms = oContainer.Drawpage.GetForms
+ For i = 0 To oForms.Count-1
+ aForm = oForms.GetbyIndex(i)
+ If aForm.HasByName(CName) Then
+ GetControlModel = aForm.GetbyName(CName)
+ Exit Function
+ End If
+ Next i
+ Msgbox(&quot;No Control with the name &apos;&quot; &amp; CName &amp; &quot;&apos; found&quot; , 16, GetProductName())
+End Function
+
+
+
+&apos; Gets the Shape of a Control( e. g. to reset the size or Position of the control
+&apos; Parameters:
+&apos; The &apos;oContainer&apos; is the Document or a specific sheet of a Calc - Document
+&apos; &apos;CName&apos; is the Name of the Control
+Function GetControlShape(oContainer as Object,CName as String)
+Dim i as integer
+Dim aShape as Object
+ For i = 0 to oContainer.DrawPage.Count-1
+ aShape = oContainer.DrawPage(i)
+ If HasUnoInterfaces(aShape, &quot;com.sun.star.drawing.XControlShape&quot;) then
+ If ashape.Control.Name = CName then
+ GetControlShape = aShape
+ exit Function
+ End If
+ End If
+ Next
+End Function
+
+
+&apos; Returns the View of a Control
+&apos; Parameters:
+&apos; The &apos;oContainer&apos; is the Document or a specific sheet of a Calc - Document
+&apos; The &apos;oController&apos; is always directly attached to the Document
+&apos; &apos;CName&apos; is the Name of the Control
+Function getControlView(oContainer , oController as Object, CName as String) as Object
+Dim aForm, oForms, oControlModel as Object
+Dim i as Integer
+ oForms = oContainer.DrawPage.Forms
+ For i = 0 To oForms.Count-1
+ aForm = oforms.GetbyIndex(i)
+ If aForm.HasByName(CName) Then
+ oControlModel = aForm.GetbyName(CName)
+ GetControlView = oController.GetControl(oControlModel)
+ Exit Function
+ End If
+ Next i
+ Msgbox(&quot;No Control with the name &apos;&quot; &amp; CName &amp; &quot;&apos; found&quot; , 16, GetProductName())
+End Function
+
+
+
+&apos; Parameters:
+&apos; The &apos;oContainer&apos; is the Document or a specific sheet of a Calc - Document
+&apos; &apos;CName&apos; is the Name of the Control
+Function DisposeControl(oContainer as Object, CName as String) as Boolean
+Dim aControl as Object
+
+ aControl = GetControlModel(oContainer,CName)
+ If not IsNull(aControl) Then
+ aControl.Dispose()
+ DisposeControl = True
+ Else
+ DisposeControl = False
+ End If
+End Function
+
+
+&apos; Returns a sequence of a group of controls like option buttons or checkboxes
+&apos; The &apos;oContainer&apos; is the Document or a specific sheet of a Calc - Document
+&apos; &apos;sGroupName&apos; is the Name of the Controlgroup
+Function GetControlGroupModel(oContainer as Object, sGroupName as String )
+Dim aForm, oForms As Object
+Dim aControlModel() As Object
+Dim i as integer
+
+ oForms = oContainer.DrawPage.Forms
+ For i = 0 To oForms.Count-1
+ aForm = oForms(i)
+ If aForm.HasbyName(sGroupName) Then
+ aForm.GetGroupbyName(sGroupName,aControlModel)
+ GetControlGroupModel = aControlModel
+ Exit Function
+ End If
+ Next i
+ Msgbox(&quot;No Controlgroup with the name &apos;&quot; &amp; sGroupName &amp; &quot;&apos; found&quot; , 16, GetProductName())
+End Function
+
+
+&apos; Returns the Referencevalue of a group of e.g. option buttons or check boxes
+&apos; &apos;oControlGroup&apos; is a sequence of the Control objects
+Function GetRefValue(oControlGroup() as Object)
+Dim i as Integer
+ For i = 0 To Ubound(oControlGroup())
+&apos; oControlGroup(i).DefaultState = oControlGroup(i).State
+ If oControlGroup(i).State Then
+ GetRefValue = oControlGroup(i).RefValue
+ exit Function
+ End If
+ Next
+ GetRefValue() = -1
+End Function
+
+
+Function GetRefValueOfControlGroup(oContainer as Object, GroupName as String)
+Dim oOptGroup() as Object
+Dim iRef as Integer
+ oOptGroup() = GetControlGroupModel(oContainer, GroupName)
+ iRef = GetRefValue(oOptGroup())
+ GetRefValueofControlGroup = iRef
+End Function
+
+
+Function GetOptionGroupValue(oContainer as Object, OptGroupName as String) as Boolean
+Dim oRulesOptions() as Object
+ oRulesOptions() = GetControlGroupModel(oContainer, OptGroupName)
+ GetOptionGroupValue = oRulesOptions(0).State
+End Function
+
+
+
+Function WriteOptValueToCell(oSheet as Object, OptGroupName as String, iCol as Integer, iRow as Integer) as Boolean
+Dim bOptValue as Boolean
+Dim oCell as Object
+ bOptValue = GetOptionGroupValue(oSheet, OptGroupName)
+ oCell = oSheet.GetCellByPosition(iCol, iRow)
+ oCell.SetValue(ABS(CInt(bOptValue)))
+ WriteOptValueToCell() = bOptValue
+End Function
+
+
+Function LoadDialog(Libname as String, DialogName as String, Optional oLibContainer)
+Dim oLib as Object
+Dim oLibDialog as Object
+Dim oRuntimeDialog as Object
+ If IsMissing(oLibContainer ) then
+ oLibContainer = DialogLibraries
+ End If
+ oLibContainer.LoadLibrary(LibName)
+ oLib = oLibContainer.GetByName(Libname)
+ oLibDialog = oLib.GetByName(DialogName)
+ oRuntimeDialog = CreateUnoDialog(oLibDialog)
+ LoadDialog() = oRuntimeDialog
+End Function
+
+
+Sub GetFolderName(oRefModel as Object)
+Dim oFolderDialog as Object
+Dim iAccept as Integer
+Dim sPath as String
+Dim InitPath as String
+Dim RefControlName as String
+Dim oUcb as object
+ &apos;Note: The following services have to be called in the following order
+ &apos; because otherwise Basic does not remove the FileDialog Service
+ oFolderDialog = CreateUnoService(&quot;com.sun.star.ui.dialogs.FolderPicker&quot;)
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ InitPath = ConvertToUrl(oRefModel.Text)
+ If InitPath = &quot;&quot; Then
+ InitPath = GetPathSettings(&quot;Work&quot;)
+ End If
+ If oUcb.Exists(InitPath) Then
+ oFolderDialog.SetDisplayDirectory(InitPath)
+ End If
+ iAccept = oFolderDialog.Execute()
+ If iAccept = 1 Then
+ sPath = oFolderDialog.GetDirectory()
+ If oUcb.Exists(sPath) Then
+ oRefModel.Text = ConvertFromUrl(sPath)
+ End If
+ End If
+End Sub
+
+
+Sub GetFileName(oRefModel as Object, Filternames())
+Dim oFileDialog as Object
+Dim iAccept as Integer
+Dim sPath as String
+Dim InitPath as String
+Dim RefControlName as String
+Dim oUcb as object
+&apos;Dim ListAny(0)
+ &apos;Note: The following services have to be called in the following order
+ &apos; because otherwise Basic does not remove the FileDialog Service
+ oFileDialog = CreateUnoService(&quot;com.sun.star.ui.dialogs.FilePicker&quot;)
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ &apos;ListAny(0) = com.sun.star.ui.dialogs.TemplateDescription.FILEOPEN_SIMPLE
+ &apos;oFileDialog.initialize(ListAny())
+ AddFiltersToDialog(FilterNames(), oFileDialog)
+ InitPath = ConvertToUrl(oRefModel.Text)
+ If InitPath = &quot;&quot; Then
+ InitPath = GetPathSettings(&quot;Work&quot;)
+ End If
+ If oUcb.Exists(InitPath) Then
+ oFileDialog.SetDisplayDirectory(InitPath)
+ End If
+ iAccept = oFileDialog.Execute()
+ If iAccept = 1 Then
+ sPath = oFileDialog.Files(0)
+ If oUcb.Exists(sPath) Then
+ oRefModel.Text = ConvertFromUrl(sPath)
+ End If
+ End If
+ oFileDialog.Dispose()
+End Sub
+
+
+Function StoreDocument(oDocument as Object, FilterNames() as String, DefaultName as String, DisplayDirectory as String, Optional iAddProcedure as Integer) as String
+Dim NoArgs() as New com.sun.star.beans.PropertyValue
+Dim oStoreProperties(0) as New com.sun.star.beans.PropertyValue
+Dim oStoreDialog as Object
+Dim iAccept as Integer
+Dim sPath as String
+Dim ListAny(0) as Long
+Dim UIFilterName as String
+Dim FilterName as String
+Dim FilterIndex as Integer
+ ListAny(0) = com.sun.star.ui.dialogs.TemplateDescription.FILESAVE_AUTOEXTENSION_PASSWORD
+ oStoreDialog = CreateUnoService(&quot;com.sun.star.ui.dialogs.FilePicker&quot;)
+ oStoreDialog.Initialize(ListAny())
+ AddFiltersToDialog(FilterNames(), oStoreDialog)
+ oStoreDialog.SetDisplayDirectory(DisplayDirectory)
+ oStoreDialog.SetDefaultName(DefaultName)
+ oStoreDialog.setValue(com.sun.star.ui.dialogs.ExtendedFilePickerElementIds.CHECKBOX_AUTOEXTENSION,0, true)
+
+ iAccept = oStoreDialog.Execute()
+ If iAccept = 1 Then
+ sPath = oStoreDialog.Files(0)
+ UIFilterName = oStoreDialog.GetCurrentFilter()
+ FilterIndex = IndexInArray(UIFilterName, FilterNames())
+ FilterName = FilterNames(FilterIndex,2)
+ If Not IsMissing(iAddProcedure) Then
+ Select Case iAddProcedure
+ Case 1
+ CommitLastDocumentChanges(sPath)
+ End Select
+ End If
+ On Local Error Goto NOSAVING
+ If FilterName = &quot;&quot; Then
+ &apos; Todo: Catch the case that a document that has to be overwritten is writeprotected (e.g. it is open)
+ oDocument.StoreAsUrl(sPath, NoArgs())
+ Else
+ oStoreProperties(0).Name = &quot;FilterName&quot;
+ oStoreProperties(0).Value = FilterName
+ oDocument.StoreAsUrl(sPath, oStoreProperties())
+ End If
+ End If
+ oStoreDialog.dispose()
+ StoreDocument() = sPath
+ Exit Function
+NOSAVING:
+ If Err &lt;&gt; 0 Then
+&apos; Msgbox(&quot;Document cannot be saved under &apos;&quot; &amp; ConvertFromUrl(sPath) &amp; &quot;&apos;&quot;, 48, GetProductName())
+ sPath = &quot;&quot;
+ oStoreDialog.dispose()
+ Resume NOERROR
+ NOERROR:
+ End If
+End Function
+
+
+Sub AddFiltersToDialog(FilterNames() as String, oDialog as Object)
+Dim i as Integer
+Dim MaxIndex as Integer
+Dim ViewFiltername as String
+Dim oProdNameAccess as Object
+Dim sProdName as String
+ oProdNameAccess = GetRegistryKeyContent(&quot;org.openoffice.Setup/Product&quot;)
+ sProdName = oProdNameAccess.getByName(&quot;ooName&quot;)
+ MaxIndex = Ubound(FilterNames(), 1)
+ For i = 0 To MaxIndex
+ Filternames(i,0) = ReplaceString(Filternames(i,0), sProdName,&quot;%productname%&quot;)
+ oDialog.AppendFilter(FilterNames(i,0), FilterNames(i,1))
+ Next i
+ oDialog.SetCurrentFilter(FilterNames(0,0))
+End Sub
+
+
+Sub SwitchMousePointer(oWindowPeer as Object, bDoEnable as Boolean)
+Dim oWindowPointer as Object
+ oWindowPointer = CreateUnoService(&quot;com.sun.star.awt.Pointer&quot;)
+ If bDoEnable Then
+ oWindowPointer.SetType(com.sun.star.awt.SystemPointer.ARROW)
+ Else
+ oWindowPointer.SetType(com.sun.star.awt.SystemPointer.WAIT)
+ End If
+ oWindowPeer.SetPointer(oWindowPointer)
+End Sub
+
+
+Sub ShowOverwriteAllDialog(FilePath as String, sTitle as String)
+Dim QueryString as String
+Dim LocRetValue as Integer
+Dim lblYes as String
+Dim lblNo as String
+Dim lblYesToAll as String
+Dim lblCancel as String
+Dim OverwriteModel as Object
+ If InitResources(GetProductName()) Then
+ QueryString = GetResText(&quot;RID_COMMON_7&quot;)
+ QueryString = ReplaceString(QueryString, ConvertFromUrl(FilePath), &quot;&lt;PATH&gt;&quot;)
+ If Len(QueryString) &gt; 190 Then
+ QueryString = DeleteStr(QueryString, &quot;.&lt;BR&gt;&quot;)
+ End If
+ QueryString = ReplaceString(QueryString, chr(13), &quot;&lt;BR&gt;&quot;)
+ lblYes = GetResText(&quot;RID_COMMON_8&quot;)
+ lblYesToAll = GetResText(&quot;RID_COMMON_9&quot;)
+ lblNo = GetResText(&quot;RID_COMMON_10&quot;)
+ lblCancel = GetResText(&quot;RID_COMMON_11&quot;)
+ DlgOverwrite = LoadDialog(&quot;Tools&quot;, &quot;DlgOverwriteAll&quot;)
+ DlgOverwrite.Title = sTitle
+ OverwriteModel = DlgOverwrite.Model
+ OverwriteModel.cmdYes.Label = lblYes
+ OverwriteModel.cmdYesToAll.Label = lblYesToAll
+ OverwriteModel.cmdNo.Label = lblNo
+ OverwriteModel.cmdCancel.Label = lblCancel
+ OverwriteModel.lblQueryforSave.Label = QueryString
+ OverwriteModel.cmdNo.DefaultButton = True
+ DlgOverwrite.GetControl(&quot;cmdNo&quot;).SetFocus()
+ iGeneralOverwrite = 999
+ LocRetValue = DlgOverwrite.execute()
+ If iGeneralOverwrite = 999 Then
+ iGeneralOverwrite = SBOVERWRITECANCEL
+ End If
+ DlgOverwrite.dispose()
+ Else
+ iGeneralOverwrite = SBOVERWRITECANCEL
+ End If
+End Sub
+
+
+Sub SetOVERWRITEToQuery()
+ iGeneralOverwrite = SBOVERWRITEQUERY
+ DlgOverwrite.EndExecute()
+End Sub
+
+
+Sub SetOVERWRITEToAlways()
+ iGeneralOverwrite = SBOVERWRITEALWAYS
+ DlgOverwrite.EndExecute()
+End Sub
+
+
+Sub SetOVERWRITEToNever()
+ iGeneralOverwrite = SBOVERWRITENEVER
+ DlgOverwrite.EndExecute()
+End Sub
+</script:module>
diff --git a/wizards/source/tools/Strings.xba b/wizards/source/tools/Strings.xba
new file mode 100644
index 000000000..bb1593a20
--- /dev/null
+++ b/wizards/source/tools/Strings.xba
@@ -0,0 +1,469 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Strings" script:language="StarBasic">Option Explicit
+Public sProductname as String
+
+
+&apos; Deletes out of a String &apos;BigString&apos; all possible PartStrings, that are summed up
+&apos; in the Array &apos;ElimArray&apos;
+Function ElimChar(ByVal BigString as String, ElimArray() as String)
+Dim i% ,n%
+ For i = 0 to Ubound(ElimArray)
+ BigString = DeleteStr(BigString,ElimArray(i))
+ Next
+ ElimChar = BigString
+End Function
+
+
+&apos; Deletes out of a String &apos;BigString&apos; a possible Partstring &apos;CompString&apos;
+Function DeleteStr(ByVal BigString,CompString as String) as String
+Dim i%, CompLen%, BigLen%
+ CompLen = Len(CompString)
+ i = 1
+ While i &lt;&gt; 0
+ i = Instr(i, BigString,CompString)
+ If i &lt;&gt; 0 then
+ BigLen = Len(BigString)
+ BigString = Mid(BigString,1,i-1) + Mid(BigString,i+CompLen,BigLen-i+1-CompLen)
+ End If
+ Wend
+ DeleteStr = BigString
+End Function
+
+
+&apos; Finds a PartString, that is framed by the Strings &apos;Prestring&apos; and &apos;PostString&apos;
+Function FindPartString(BigString, PreString, PostString as String, SearchPos as Integer) as String
+Dim StartPos%, EndPos%
+Dim BigLen%, PreLen%, PostLen%
+ StartPos = Instr(SearchPos,BigString,PreString)
+ If StartPos &lt;&gt; 0 Then
+ PreLen = Len(PreString)
+ EndPos = Instr(StartPos + PreLen,BigString,PostString)
+ If EndPos &lt;&gt; 0 Then
+ BigLen = Len(BigString)
+ PostLen = Len(PostString)
+ FindPartString = Mid(BigString,StartPos + PreLen, EndPos - (StartPos + PreLen))
+ SearchPos = EndPos + PostLen
+ Else
+ Msgbox(&quot;No final tag for &apos;&quot; &amp; PreString &amp; &quot;&apos; existing&quot;, 16, GetProductName())
+ FindPartString = &quot;&quot;
+ End If
+ Else
+ FindPartString = &quot;&quot;
+ End If
+End Function
+
+
+&apos; Note iCompare = 0 (Binary comparison)
+&apos; iCompare = 1 (Text comparison)
+Function PartStringInArray(BigArray(), SearchString as String, iCompare as Integer) as Integer
+Dim MaxIndex as Integer
+Dim i as Integer
+ MaxIndex = Ubound(BigArray())
+ For i = 0 To MaxIndex
+ If Instr(1, BigArray(i), SearchString, iCompare) &lt;&gt; 0 Then
+ PartStringInArray() = i
+ Exit Function
+ End If
+ Next i
+ PartStringInArray() = -1
+End Function
+
+
+&apos; Deletes the String &apos;SmallString&apos; out of the String &apos;BigString&apos;
+&apos; in case SmallString&apos;s Position in BigString is right at the end
+Function RTrimStr(ByVal BigString, SmallString as String) as String
+Dim SmallLen as Integer
+Dim BigLen as Integer
+ SmallLen = Len(SmallString)
+ BigLen = Len(BigString)
+ If Instr(1,BigString, SmallString) &lt;&gt; 0 Then
+ If Mid(BigString,BigLen + 1 - SmallLen, SmallLen) = SmallString Then
+ RTrimStr = Mid(BigString,1,BigLen - SmallLen)
+ Else
+ RTrimStr = BigString
+ End If
+ Else
+ RTrimStr = BigString
+ End If
+End Function
+
+
+&apos; Deletes the Char &apos;CompChar&apos; out of the String &apos;BigString&apos;
+&apos; in case CompChar&apos;s Position in BigString is right at the beginning
+Function LTRimChar(ByVal BigString as String,CompChar as String) as String
+Dim BigLen as integer
+ BigLen = Len(BigString)
+ If BigLen &gt; 1 Then
+ If Left(BigString,1) = CompChar then
+ BigString = Mid(BigString,2,BigLen-1)
+ End If
+ ElseIf BigLen = 1 Then
+ BigString = &quot;&quot;
+ End If
+ LTrimChar = BigString
+End Function
+
+
+&apos; Retrieves an Array out of a String.
+&apos; The fields of the Array are separated by the parameter &apos;Separator&apos;, that is contained
+&apos; in the Array
+&apos; The Array MaxIndex delivers the highest Index of this Array
+Function ArrayOutOfString(BigString, Separator as String, Optional MaxIndex as Integer)
+Dim LocList() as String
+ LocList=Split(BigString,Separator)
+
+ If not isMissing(MaxIndex) then maxIndex=ubound(LocList())
+
+ ArrayOutOfString=LocList
+End Function
+
+
+&apos; Deletes all fieldvalues in one-dimensional Array
+Sub ClearArray(BigArray)
+Dim i as integer
+ For i = Lbound(BigArray()) to Ubound(BigArray())
+ BigArray(i) = &quot;&quot;
+ Next
+End Sub
+
+
+&apos; Deletes all fieldvalues in a multidimensional Array
+Sub ClearMultiDimArray(BigArray,DimCount as integer)
+Dim n%, m%
+ For n = Lbound(BigArray(),1) to Ubound(BigArray(),1)
+ For m = 0 to Dimcount - 1
+ BigArray(n,m) = &quot;&quot;
+ Next m
+ Next n
+End Sub
+
+
+&apos; Checks if a Field (LocField) is already defined in an Array
+&apos; Returns &apos;True&apos; or &apos;False&apos;
+Function FieldInArray(LocArray(), MaxIndex as integer, LocField as String) As Boolean
+Dim i as integer
+ For i = Lbound(LocArray()) to MaxIndex
+ If UCase(LocArray(i)) = UCase(LocField) Then
+ FieldInArray = True
+ Exit Function
+ End if
+ Next
+ FieldInArray = False
+End Function
+
+
+&apos; Checks if a Field (LocField) is already defined in an Array
+&apos; Returns &apos;True&apos; or &apos;False&apos;
+Function FieldInList(LocField, BigList()) As Boolean
+Dim i as integer
+ For i = Lbound(BigList()) to Ubound(BigList())
+ If LocField = BigList(i) Then
+ FieldInList = True
+ Exit Function
+ End if
+ Next
+ FieldInList = False
+End Function
+
+
+&apos; Retrieves the Index of the delivered String &apos;SearchString&apos; in
+&apos; the Array LocList()&apos;
+Function IndexInArray(SearchString as String, LocList()) as Integer
+Dim i as integer
+ For i = Lbound(LocList(),1) to Ubound(LocList(),1)
+ If UCase(LocList(i,0)) = UCase(SearchString) Then
+ IndexInArray = i
+ Exit Function
+ End if
+ Next
+ IndexInArray = -1
+End Function
+
+
+Sub MultiArrayInListbox(oDialog as Object, ListboxName as String, ValList(), iDim as Integer)
+Dim oListbox as Object
+Dim i as integer
+Dim a as Integer
+ a = 0
+ oListbox = oDialog.GetControl(ListboxName)
+ oListbox.RemoveItems(0, oListbox.GetItemCount)
+ For i = 0 to Ubound(ValList(), 1)
+ If ValList(i) &lt;&gt; &quot;&quot; Then
+ oListbox.AddItem(ValList(i, iDim-1), a)
+ a = a + 1
+ End If
+ Next
+End Sub
+
+
+&apos; Searches for a String in a two-dimensional Array by querying all Searchindexes of the second dimension
+&apos; and delivers the specific String of the ReturnIndex in the second dimension of the Searchlist()
+Function StringInMultiArray(SearchList(), SearchString as String, SearchIndex as Integer, ReturnIndex as Integer, Optional MaxIndex as Integer) as String
+Dim i as integer
+Dim CurFieldString as String
+ If IsMissing(MaxIndex) Then
+ MaxIndex = Ubound(SearchList(),1)
+ End If
+ For i = Lbound(SearchList()) to MaxIndex
+ CurFieldString = SearchList(i,SearchIndex)
+ If UCase(CurFieldString) = UCase(SearchString) Then
+ StringInMultiArray() = SearchList(i,ReturnIndex)
+ Exit Function
+ End if
+ Next
+ StringInMultiArray() = &quot;&quot;
+End Function
+
+
+&apos; Searches for a Value in multidimensial Array by querying all Searchindices of the passed dimension
+&apos; and delivers the Index where it is found.
+Function GetIndexInMultiArray(SearchList(), SearchValue, SearchIndex as Integer) as Integer
+Dim i as integer
+Dim MaxIndex as Integer
+Dim CurFieldValue
+ MaxIndex = Ubound(SearchList(),1)
+ For i = Lbound(SearchList()) to MaxIndex
+ CurFieldValue = SearchList(i,SearchIndex)
+ If CurFieldValue = SearchValue Then
+ GetIndexInMultiArray() = i
+ Exit Function
+ End if
+ Next
+ GetIndexInMultiArray() = -1
+End Function
+
+
+&apos; Searches for a Value in multidimensial Array by querying all Searchindices of the passed dimension
+&apos; and delivers the Index where the Searchvalue is found as a part string
+Function GetIndexForPartStringinMultiArray(SearchList(), SearchValue, SearchIndex as Integer) as Integer
+Dim i as integer
+Dim MaxIndex as Integer
+Dim CurFieldValue
+ MaxIndex = Ubound(SearchList(),1)
+ For i = Lbound(SearchList()) to MaxIndex
+ CurFieldValue = SearchList(i,SearchIndex)
+ If Instr(CurFieldValue, SearchValue) &gt; 0 Then
+ GetIndexForPartStringinMultiArray() = i
+ Exit Function
+ End if
+ Next
+ GetIndexForPartStringinMultiArray = -1
+End Function
+
+
+Function ArrayfromMultiArray(MultiArray as String, iDim as Integer)
+Dim MaxIndex as Integer
+Dim i as Integer
+ MaxIndex = Ubound(MultiArray())
+ Dim ResultArray(MaxIndex) as String
+ For i = 0 To MaxIndex
+ ResultArray(i) = MultiArray(i,iDim)
+ Next i
+ ArrayfromMultiArray() = ResultArray()
+End Function
+
+
+&apos; Replaces the string &quot;OldReplace&quot; through the String &quot;NewReplace&quot; in the String
+&apos; &apos;BigString&apos;
+Function ReplaceString(ByVal Bigstring, NewReplace, OldReplace as String) as String
+ ReplaceString=join(split(BigString,OldReplace),NewReplace)
+End Function
+
+
+&apos; Retrieves the second value for a next to &apos;SearchString&apos; in
+&apos; a two-dimensional string-Array
+Function FindSecondValue(SearchString as String, TwoDimList() as String ) as String
+Dim i as Integer
+ For i = 0 To Ubound(TwoDimList,1)
+ If UCase(SearchString) = UCase(TwoDimList(i,0)) Then
+ FindSecondValue = TwoDimList(i,1)
+ Exit For
+ End If
+ Next
+End Function
+
+
+&apos; raises a base to a certain power
+Function Power(Basis as Double, Exponent as Double) as Double
+ Power = Exp(Exponent*Log(Basis))
+End Function
+
+
+&apos; rounds a Real to a given Number of Decimals
+Function Round(BaseValue as Double, Decimals as Integer) as Double
+Dim Multiplicator as Long
+Dim DblValue#, RoundValue#
+ Multiplicator = Power(10,Decimals)
+ RoundValue = Int(BaseValue * Multiplicator)
+ Round = RoundValue/Multiplicator
+End Function
+
+
+&apos;Retrieves the mere filename out of a whole path
+Function FileNameoutofPath(ByVal Path as String, Optional Separator as String) as String
+Dim i as Integer
+Dim SepList() as String
+ If IsMissing(Separator) Then
+ Path = ConvertFromUrl(Path)
+ Separator = GetPathSeparator()
+ End If
+ SepList() = ArrayoutofString(Path, Separator,i)
+ FileNameoutofPath = SepList(i)
+End Function
+
+
+Function GetFileNameExtension(ByVal FileName as String)
+Dim MaxIndex as Integer
+Dim SepList() as String
+ SepList() = ArrayoutofString(FileName,&quot;.&quot;, MaxIndex)
+ GetFileNameExtension = SepList(MaxIndex)
+End Function
+
+
+Function GetFileNameWithoutExtension(ByVal FileName as String, Optional Separator as String)
+Dim MaxIndex as Integer
+Dim SepList() as String
+ If not IsMissing(Separator) Then
+ FileName = FileNameoutofPath(FileName, Separator)
+ End If
+ SepList() = ArrayoutofString(FileName,&quot;.&quot;, MaxIndex)
+ GetFileNameWithoutExtension = RTrimStr(FileName, &quot;.&quot; &amp; SepList(MaxIndex))
+End Function
+
+
+Function DirectoryNameoutofPath(sPath as String, Separator as String) as String
+Dim LocFileName as String
+ LocFileName = FileNameoutofPath(sPath, Separator)
+ DirectoryNameoutofPath = RTrimStr(sPath, Separator &amp; LocFileName)
+End Function
+
+
+Function CountCharsInString(BigString, LocChar as String, ByVal StartPos as Integer) as Integer
+Dim LocCount%, LocPos%
+ LocCount = 0
+ Do
+ LocPos = Instr(StartPos,BigString,LocChar)
+ If LocPos &lt;&gt; 0 Then
+ LocCount = LocCount + 1
+ StartPos = LocPos+1
+ End If
+ Loop until LocPos = 0
+ CountCharsInString = LocCount
+End Function
+
+
+Function BubbleSortList(ByVal SortList(),optional sort2ndValue as Boolean)
+&apos;This function bubble sorts an array of maximum 2 dimensions.
+&apos;The default sorting order is the first dimension
+&apos;Only if sort2ndValue is True the second dimension is the relevant for the sorting order
+ Dim s as Integer
+ Dim t as Integer
+ Dim i as Integer
+ Dim k as Integer
+ Dim dimensions as Integer
+ Dim sortvalue as Integer
+ Dim DisplayDummy
+ dimensions = 2
+
+On Local Error Goto No2ndDim
+ k = Ubound(SortList(),2)
+ No2ndDim:
+ If Err &lt;&gt; 0 Then dimensions = 1
+
+ i = Ubound(SortList(),1)
+ If ismissing(sort2ndValue) then
+ sortvalue = 0
+ else
+ sortvalue = 1
+ end if
+
+ For s = 1 to i - 1
+ For t = 0 to i-s
+ Select Case dimensions
+ Case 1
+ If SortList(t) &gt; SortList(t+1) Then
+ DisplayDummy = SortList(t)
+ SortList(t) = SortList(t+1)
+ SortList(t+1) = DisplayDummy
+ End If
+ Case 2
+ If SortList(t,sortvalue) &gt; SortList(t+1,sortvalue) Then
+ For k = 0 to UBound(SortList(),2)
+ DisplayDummy = SortList(t,k)
+ SortList(t,k) = SortList(t+1,k)
+ SortList(t+1,k) = DisplayDummy
+ Next k
+ End If
+ End Select
+ Next t
+ Next s
+ BubbleSortList = SortList()
+End Function
+
+
+Function GetValueoutofList(SearchValue, BigList(), iDim as Integer, Optional ValueIndex)
+Dim i as Integer
+Dim MaxIndex as Integer
+ MaxIndex = Ubound(BigList(),1)
+ For i = 0 To MaxIndex
+ If BigList(i,0) = SearchValue Then
+ If Not IsMissing(ValueIndex) Then
+ ValueIndex = i
+ End If
+ GetValueOutOfList() = BigList(i,iDim)
+ End If
+ Next i
+End Function
+
+
+Function AddListtoList(ByVal FirstArray(), ByVal SecondArray(), Optional StartIndex)
+Dim n as Integer
+Dim m as Integer
+Dim MaxIndex as Integer
+ MaxIndex = Ubound(FirstArray()) + Ubound(SecondArray()) + 1
+ If MaxIndex &gt; -1 Then
+ Dim ResultArray(MaxIndex)
+ For m = 0 To Ubound(FirstArray())
+ ResultArray(m) = FirstArray(m)
+ Next m
+ For n = 0 To Ubound(SecondArray())
+ ResultArray(m) = SecondArray(n)
+ m = m + 1
+ Next n
+ AddListToList() = ResultArray()
+ Else
+ Dim NullArray()
+ AddListToList() = NullArray()
+ End If
+End Function
+
+
+Function CheckDouble(DoubleString as String)
+On Local Error Goto WRONGDATATYPE
+ CheckDouble() = CDbl(DoubleString)
+WRONGDATATYPE:
+ If Err &lt;&gt; 0 Then
+ CheckDouble() = 0
+ Resume NoErr:
+ End If
+NOERR:
+End Function
+</script:module>
diff --git a/wizards/source/tools/UCB.xba b/wizards/source/tools/UCB.xba
new file mode 100644
index 000000000..d849a2ea3
--- /dev/null
+++ b/wizards/source/tools/UCB.xba
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="UCB" script:language="StarBasic">&apos;Option explicit
+Public oDocument
+Public oDocInfo as object
+Const SBMAXDIRCOUNT = 10
+Dim CurDirMaxCount as Integer
+Dim sDirArray(SBMAXDIRCOUNT-1) as String
+Dim DirIndex As Integer
+Dim iDirCount as Integer
+Public bInterruptSearch as Boolean
+Public NoArgs()as New com.sun.star.beans.PropertyValue
+
+Sub Main()
+Dim LocsfileContent(0) as String
+ LocsfileContent(0) = &quot;*&quot;
+ ReadDirectories(&quot;file:///space&quot;, LocsfileContent(), True, False, false)
+End Sub
+
+&apos; ReadDirectories( sSourceDir, bRecursive, bCheckRealType, False, sFileContent(), sLocExtension)
+
+Function ReadDirectories(ByVal AnchorDir As String, bRecursive as Boolean, bcheckFileType as Boolean, bGetByTitle as Boolean, Optional sFileContent(), Optional sExtension as String)
+Dim i as integer
+Dim Status as Object
+Dim FileCountinDir as Integer
+Dim RealFileContent as String
+Dim FileName as string
+Dim oUcbObject as Object
+Dim DirContent()
+Dim CurIndex as Integer
+Dim MaxIndex as Integer
+Dim StartUbound as Integer
+Dim FileExtension as String
+ StartUbound = 5
+ MaxIndex = StartUBound
+ CurDirMaxCount = SBMAXDIRCOUNT
+Dim sFileArray(StartUbound,1) as String
+ On Local Error Goto FILESYSTEMPROBLEM:
+ CurIndex = -1
+ &apos; Todo: Is the last separator valid?
+ DirIndex = 0
+ sDirArray(iDirIndex) = AnchorDir
+ iDirCount = 1
+ oDocInfo = CreateUnoService(&quot;com.sun.star.document.DocumentProperties&quot;)
+ oUcbObject = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ If oUcbObject.Exists(AnchorDir) Then
+ Do
+ AnchorDir = sDirArray(DirIndex)
+ On Local Error Resume Next
+ DirContent() = oUcbObject.GetFolderContents(AnchorDir,True)
+ DirIndex = DirIndex + 1
+ On Local Error Goto 0
+ On Local Error Goto FILESYSTEMPROBLEM:
+ If Ubound(DirContent()) &lt;&gt; -1 Then
+ FileCountinDir = Ubound(DirContent())+ 1
+ For i = 0 to FilecountinDir -1
+ If bInterruptSearch = True Then
+ Exit Do
+ End If
+
+ Filename = DirContent(i)
+ If oUcbObject.IsFolder(FileName) Then
+ If brecursive Then
+ AddFoldertoList(FileName, DirIndex)
+ End If
+ Else
+ If bcheckFileType Then
+ RealFileContent = GetRealFileContent(FileName)
+ Else
+ RealFileContent = GetFileNameExtension(FileName)
+ End If
+ If RealFileContent &lt;&gt; &quot;&quot; Then
+ &apos; Retrieve the Index in the Array, where a Filename is positioned
+ If Not IsMissing(sFileContent()) Then
+ If (FieldInArray(sFileContent(), Ubound(sFileContent), RealFileContent)) Then
+ &apos; The extension of the current file passes the filter and is therefore admitted to the
+ &apos; fileList
+ If Not IsMissing(sExtension) Then
+ If sExtension &lt;&gt; &quot;&quot; Then
+ &apos; Consider that some Formats like old StarOffice Templates with the extension &quot;.vor&quot; can only be
+ &apos; precisely identified by their mimetype and their extension
+ FileExtension = GetFileNameExtension(FileName)
+ If FileExtension = sExtension Then
+ AddFileNameToList(sFileArray(), FileName, RealFileContent, bGetByTitle, CurIndex)
+ End If
+ Else
+ AddFileNameToList(sFileArray(), FileName, RealFileContent, bGetByTitle, CurIndex)
+ End If
+ Else
+ AddFileNameToList(sFileArray(), FileName, RealFileContent, bGetByTitle, CurIndex)
+ End If
+ End If
+ Else
+ AddFileNameToList(sFileArray(), FileName, RealFileContent, bGetByTitle, CurIndex)
+ End If
+ If CurIndex = MaxIndex Then
+ MaxIndex = MaxIndex + StartUbound
+ ReDim Preserve sFileArray(MaxIndex,1) as String
+ End If
+ End If
+ End If
+ Next i
+ End If
+ Loop Until DirIndex &gt;= iDirCount
+ If CurIndex &gt; -1 Then
+ ReDim Preserve sFileArray(CurIndex,1) as String
+ Else
+ ReDim sFileArray() as String
+ End If
+ Else
+ Msgbox(&quot;Directory &apos;&quot; &amp; ConvertFromUrl(AnchorDir) &amp; &quot;&apos; does not exist!&quot;, 16, GetProductName())
+ End If
+ ReadDirectories() = sFileArray()
+ Exit Function
+
+ FILESYSTEMPROBLEM:
+ Msgbox(&quot;Sorry, Filesystem Problem&quot;)
+ ReadDirectories() = sFileArray()
+ Resume LEAVEPROC
+ LEAVEPROC:
+End Function
+
+
+Sub AddFoldertoList(sDirURL as String, iDirIndex)
+ iDirCount = iDirCount + 1
+ If iDirCount = CurDirMaxCount Then
+ CurDirMaxCount = CurDirMaxCount + SBMAXDIRCOUNT
+ ReDim Preserve sDirArray(CurDirMaxCount) as String
+ End If
+ sDirArray(iDirCount-1) = sDirURL
+End Sub
+
+
+Sub AddFileNameToList(sFileArray(), FileName as String, FileContent as String, bGetByTitle as Boolean, CurIndex)
+Dim FileCount As Integer
+ CurIndex = CurIndex + 1
+ sFileArray(CurIndex,0) = FileName
+ If bGetByTitle Then
+ sFileArray(CurIndex,1) = RetrieveDocTitle(oDocInfo, FileName)
+ &apos; Add the documenttitles to the Filearray
+ Else
+ sFileArray(CurIndex,1) = FileContent
+ End If
+End Sub
+
+
+Function RetrieveDocTitle(oDocProps as Object, sFileName as String) As String
+Dim sDocTitle as String
+ On Local Error Goto NOFILE
+ oDocProps.loadFromMedium(sFileName, NoArgs())
+ sDocTitle = oDocProps.Title
+ NOFILE:
+ If Err &lt;&gt; 0 Then
+ RetrieveDocTitle = &quot;&quot;
+ RESUME CLR_ERROR
+ End If
+ CLR_ERROR:
+ If sDocTitle = &quot;&quot; Then
+ sDocTitle = GetFileNameWithoutExtension(sFilename, &quot;/&quot;)
+ End If
+ RetrieveDocTitle = sDocTitle
+End Function
+
+
+&apos; Retrieves The Filecontent of a Document by extracting the content
+&apos; from the Header of the document
+Function GetRealFileContent(FileName as String) As String
+ On Local Error Goto NOFILE
+ oTypeDetect = createUnoService(&quot;com.sun.star.document.TypeDetection&quot;)
+ GetRealFileContent = oTypeDetect.queryTypeByURL(FileName)
+ NOFILE:
+ If Err &lt;&gt; 0 Then
+ GetRealFileContent = &quot;&quot;
+ resume CLR_ERROR
+ End If
+ CLR_ERROR:
+End Function
+
+
+Function CopyRecursively(SourceFilePath as String, SourceStemDir as String, TargetStemDir as String)
+Dim TargetDir as String
+Dim TargetFile as String
+
+ TargetFile= ReplaceString(SourceFilePath, TargetStemDir, SourceStemDir)
+ TargetFileName = FileNameoutofPath(TargetFile,&quot;/&quot;)
+ TargetDir = DeleteStr(TargetFile, TargetFileName)
+ CreateFolder(TargetDir)
+ CopyRecursively() = TargetFile
+End Function
+
+
+&apos; Opens a help url referenced by a Help ID that is retrieved from the calling button tag
+Sub ShowHelperDialog(aEvent)
+Dim oSystemNode as Object
+Dim sSystem as String
+Dim oLanguageNode as Object
+Dim sLocale as String
+Dim sLocaleList() as String
+Dim sLanguage as String
+Dim sHelpUrl as String
+Dim sDocType as String
+ HelpID = aEvent.Source.Model.Tag
+ oLocDocument = StarDesktop.ActiveFrame.Controller.Model
+ sDocType = GetDocumentType(oLocDocument)
+ oSystemNode = GetRegistryKeyContent(&quot;org.openoffice.Office.Common/Help&quot;)
+ sSystem = oSystemNode.GetByName(&quot;System&quot;)
+ oLanguageNode = GetRegistryKeyContent(&quot;org.openoffice.Setup/L10N/&quot;)
+ sLocale = oLanguageNode.getByName(&quot;ooLocale&quot;)
+ sLocaleList() = ArrayoutofString(sLocale, &quot;-&quot;)
+ sLanguage = sLocaleList(0)
+ sHelpUrl = &quot;vnd.sun.star.help://&quot; &amp; sDocType &amp; &quot;/&quot; &amp; HelpID &amp; &quot;?Language=&quot; &amp; sLanguage &amp; &quot;&amp;System=&quot; &amp; sSystem
+ StarDesktop.LoadComponentfromUrl(sHelpUrl, &quot;OFFICE_HELP&quot;, 63, NoArgs())
+End Sub
+
+
+Sub SaveDataToFile(FilePath as String, DataList())
+Dim FileChannel as Integer
+Dim i as Integer
+Dim oFile as Object
+Dim oOutputStream as Object
+Dim oStreamString as Object
+Dim oUcb as Object
+Dim sCRLF as String
+
+ sCRLF = CHR(13) &amp; CHR(10)
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ oOutputStream = createUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
+ If oUcb.Exists(FilePath) Then
+ oUcb.Kill(FilePath)
+ End If
+ oFile = oUcb.OpenFileReadWrite(FilePath)
+ oOutputStream.SetOutputStream(oFile.GetOutputStream)
+ For i = 0 To Ubound(DataList())
+ oOutputStream.WriteString(DataList(i) &amp; sCRLF)
+ Next i
+ oOutputStream.CloseOutput()
+End Sub
+
+
+Function LoadDataFromFile(FilePath as String, DataList()) as Boolean
+Dim oInputStream as Object
+Dim i as Integer
+Dim oUcb as Object
+Dim oFile as Object
+Dim MaxIndex as Integer
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ If oUcb.Exists(FilePath) Then
+ MaxIndex = 10
+ oInputStream = createUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
+ oFile = oUcb.OpenFileReadWrite(FilePath)
+ oInputStream.SetInputStream(oFile.GetInputStream)
+ i = -1
+ Redim Preserve DataList(MaxIndex)
+ While Not oInputStream.IsEOF
+ i = i + 1
+ If i &gt; MaxIndex Then
+ MaxIndex = MaxIndex + 10
+ Redim Preserve DataList(MaxIndex)
+ End If
+ DataList(i) = oInputStream.ReadLine
+ Wend
+ If i &gt; -1 And i &lt;&gt; MaxIndex Then
+ Redim Preserve DataList(i)
+ End If
+ LoadDataFromFile() = True
+ oInputStream.CloseInput()
+ Else
+ LoadDataFromFile() = False
+ End If
+End Function
+
+
+Function CreateFolder(sNewFolder) as Boolean
+Dim oUcb as Object
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ On Local Error Goto NOSPACEONDRIVE
+ If Not oUcb.Exists(sNewFolder) Then
+ oUcb.CreateFolder(sNewFolder)
+ End If
+ CreateFolder = True
+NOSPACEONDRIVE:
+ If Err &lt;&gt; 0 Then
+ If InitResources(&quot;&quot;) Then
+ ErrMsg = GetResText(&quot;RID_COMMON_0&quot;)
+ ErrMsg = ReplaceString(ErrMsg, chr(13), &quot;&lt;BR&gt;&quot;)
+ ErrMsg = ReplaceString(ErrMsg, sNewFolder, &quot;%1&quot;)
+ Msgbox(ErrMsg, 48, GetProductName())
+ End If
+ CreateFolder = False
+ Resume GOON
+ End If
+GOON:
+End Function
+</script:module>
diff --git a/wizards/source/tools/dialog.xlb b/wizards/source/tools/dialog.xlb
new file mode 100644
index 000000000..dc8dfbda2
--- /dev/null
+++ b/wizards/source/tools/dialog.xlb
@@ -0,0 +1,5 @@
+<?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="Tools" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="DlgOverwriteAll"/>
+</library:library>
diff --git a/wizards/source/tools/script.xlb b/wizards/source/tools/script.xlb
new file mode 100644
index 000000000..fe4d74d60
--- /dev/null
+++ b/wizards/source/tools/script.xlb
@@ -0,0 +1,10 @@
+<?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="Tools" library:readonly="true" library:passwordprotected="false">
+ <library:element library:name="ModuleControls"/>
+ <library:element library:name="Strings"/>
+ <library:element library:name="Misc"/>
+ <library:element library:name="UCB"/>
+ <library:element library:name="Listbox"/>
+ <library:element library:name="Debug"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/tutorials/Functions.xba b/wizards/source/tutorials/Functions.xba
new file mode 100644
index 000000000..4b422c80b
--- /dev/null
+++ b/wizards/source/tutorials/Functions.xba
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Functions" script:language="StarBasic">REM ***** BASIC *****
+Dim DialogVisible As Boolean
+Dim TutorStep As Integer
+Dim TutorLastStep As Integer
+Dim myDialog As Object
+Dim myTutorial As Object
+Public TutorText() As String
+Dim documentTitle As String
+Dim exampleUse As Object
+Dim properties() As Object
+Dim docTYP As String
+&apos;public myWidth As Long
+Dim myHeight As Long
+Dim oTextField As Object
+Dim stepTitle As String
+Dim oOpenDialogFlag
+Dim imageStatus As String
+
+Sub LoadTutorialDialog(exampleToUse, documentTYP)
+ Init()
+ exampleUse = exampleToUse
+ TutorText() = exampleUse.LoadText()
+ properties() = exampleUse.GetProperties()
+ If properties(3).Value = &quot;True&quot; Then
+ Dim localisation(0) As new com.sun.star.beans.NamedValue
+ localisation(0).Name = &quot;Localisation&quot;
+ localisation(0).Value = properties()
+ myTutorial.execute(localisation())
+ Else
+ TutorStep = 0
+ TutorLastStep = 0
+ docTYP = documentTYP
+ InitAction()
+ ShowInfoMain()
+ DialogVisible = True
+ myDialog = LoadDialog(&quot;Tutorials&quot;,&quot;TutorialsDialog&quot;)
+
+ SetTutorialDocumentPosSize()
+
+ documentProps = ThisComponent.getDocumentProperties()
+ myDialog.Title = &quot;Tutorials - &quot; &amp; documentProps.Title
+ oTextField = myDialog.GetControl(&quot;myTextField&quot;)
+ oTextField.setVisible(False)
+
+ imageStatus = &quot;MIN&quot;
+ setMaxMinImage(imageStatus)
+
+ &apos;myWidth = myDialog.Size.Width
+ myHeight = myDialog.Size.Height
+
+ CheckForStepShowButtonStatus()
+ CheckForStepNextButtonStatus()
+ InitRoadMap()
+ SetVisibleTrue()
+ myDialog.model.myTextField.Label = stepTitle
+ myDialog.model.myText.Label = GetStepText()&apos;TutorText(TutorStep)
+
+
+ Do
+ wait 1000
+ Loop Until DialogVisible = False
+ If( oOpenDialogFlag = True) Then
+ Destroy()
+ TutorialOpen.TutorialOpenMain()
+ Else
+ Destroy()
+ End If
+ End If
+End Sub
+
+Sub setMaxMinImage(param As String)
+ On Local Error Goto NOIMAGE
+ oCommandButton = myDialog.GetControl(&quot;CommandButton&quot;)
+ templatePath = GetPathSettings(&quot;Template&quot;,false, 0)
+ Dim bitmapPath As String
+ iPos = InStr(templatePath,&quot;/&quot;)
+ If(iPos &gt; 0) Then
+ If(param = &quot;MAX&quot;) Then
+ bitmapPath = templatePath &amp; &quot;../wizard/bitmap/maximize.png&quot;
+ ElseIf(param = &quot;MIN&quot;) Then
+ bitmapPath = templatePath &amp; &quot;../wizard/bitmap/minimize.png&quot;
+ End If
+ Else
+ If(param = &quot;MAX&quot;) Then
+ bitmapPath = templatePath &amp; &quot;..\wizard\bitmap\maximize.png&quot;
+ ElseIf(param = &quot;MIN&quot;) Then
+ bitmapPath = templatePath &amp; &quot;..\wizard\bitmap\minimize.png&quot;
+ End If
+ End If
+ &apos;printdbgInfo oCommandButton.Model
+ oCommandButton.Model.ImageUrl = bitmapPath
+ Exit Sub
+ NOIMAGE:
+End Sub
+
+Sub SetTutorialDocumentPosSize()
+ activDesktopWindow = StarDesktop.activeFrame.ContainerWindow
+ If(activDesktopWindow.posSize.Height &lt; 550) Then
+ activDesktopWindow.setPosSize(0,0,0,550,8)
+ End If
+ If (activDesktopWindow.posSize.Width &lt; 750 ) Then
+ activDesktopWindow.setPosSize(0,0,750,0,4)
+ EndIf
+End Sub
+
+Sub InitRoadMap()
+ RoadMapMain(Functions, myDialog)
+ SetControlModelPosSize(0, 0, 85, 176)
+ SetControlModelText(&quot;Steps&quot;)
+
+ StepSize = Ubound(TutorText())
+ Dim ItemsArray(StepSize) as String
+ For i = 0 To StepSize
+ stepcontent = TutorText(i)
+ iPos = InStr(stepcontent,CHR(13))
+ ItemName = Left(stepcontent, iPos)
+ ItemsArray(i) = ItemName
+ Next i
+ InsertItemsLabels( ItemsArray())
+
+ For i = 1 To StepSize
+ SetItemEnabled( i, False)
+ Next i
+ SetItemEnabled( 0, True)
+End Sub
+
+Sub Destroy()
+ &apos;myDialog.dispose
+ wait 1000
+ ShowInfoDialog.DisposeIDialog()
+
+ &apos; THE DOCUMENT GETS CLOSED HERE!!!!!!!! GPF
+ thisComponent.CurrentController.Frame.close(True)
+
+End Sub
+
+Sub Init
+ GlobalScope.BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ myTutorial = createUNOService(&quot;com.sun.star.wizards.tutorial.executer.CallTutorialFramework&quot;)
+ documentTitle = ThisComponent.getCurrentController.getFrame.Title
+End Sub
+
+Sub InitStep
+ udProps = ThisComponent.DocumentProperties.UserDefinedProperties
+ If udProps.PropertySetInfo.hasPropertyByName(&quot;CurrentStep&quot;) Then
+ TutorStep = udProps.CurrentStep
+ Else
+ udProps.addProperty(&quot;CurrentStep&quot;, 0, TutorStep)
+ End If
+End Sub
+
+Sub setStep
+ ThisComponent.DocumentProperties.UserDefinedProperties.CurrentStep = TutorStep
+End Sub
+
+Sub InitAction()
+ SetStepTitle()
+
+ Dim property(6) As new com.sun.star.beans.PropertyValue
+ property(0).Name = &quot;DocumentTYP&quot;
+ property(0).Value = docTYP
+ property(1).Name = &quot;MethodName&quot;
+ property(1).Value = &quot;setDelay&quot;
+ property(2).Name = &quot;Param&quot;
+ property(2).Value = 0 &apos;key insert speed (Millis)
+ property(3).Name = &quot;Param&quot;
+ property(3).Value = 4 &apos;mouse animate speed (Millis)
+ property(4).Name = &quot;Param&quot;
+ property(4).Value = 2000 &apos;after mouse animate sleep (Millis)
+ property(5).Name = &quot;Param&quot;
+ property(5).Value = 10 &apos;mouse scroll speed (Millis)
+ property(6).Name = &quot;Param&quot;
+ property(6).Value = -1 &apos;mouse speed (step)
+ myTutorial.setPropertyValues(property())
+End Sub
+
+Sub EndDialog
+ oOpenDialogFlag = False
+ If (myDialog.model.done.Label = &quot;Close&quot;) Then
+ TutorialCloseMain()
+ Else
+ DialogVisible = False
+ End If
+End Sub
+
+Sub NextStep
+ GotoStep(TutorStep + 1)
+End Sub
+
+Sub GotoStep(StepIndex)
+ If(StepIndex &lt;= Ubound(TutorText())) Then
+ TutorStep = StepIndex
+ If TutorStep &gt; TutorLastStep Then
+ TutorLastStep = TutorStep
+ End If
+ If(TutorStep = Ubound(TutorText())) Then
+ myDialog.model.next.enabled = False
+ myDialog.model.done.Label = &quot;Done&quot;
+ myDialog.model.show.Label = &quot;Tutorials&quot;
+ Else
+ myDialog.model.next.enabled = True
+ End If
+ SetStepTitle()
+ myDialog.model.myText.Label = GetStepText()
+ CheckForStepShowButtonStatus()
+ SetItemEnabled( TutorStep, True)
+ &apos;setStep()
+ End If
+End Sub
+
+Function GetStepText()
+ Dim tempText As String
+ tempText = TutorText(TutorStep)
+ iPos = InStr(tempText,CHR(13))
+ ResultString = Right(tempText, Len(tempText) - iPos - 1)
+ GetStepText() = ResultString
+End Function
+
+Sub ItemChange(CurrentItemID, SelectitemID)
+ GotoStep(SelectitemID)
+End Sub
+
+Sub SetDisableShowMeButton()
+ myDialog.model.show.enabled = False
+ TutorLastStep = TutorLastStep + 1
+End Sub
+
+Sub Minimize(aEvent)
+ ActionItemsTextField = myDialog.GetControl(&quot;ActionItemsLabel&quot;)
+ FixedLineVertikal = myDialog.GetControl(&quot;FixedLineVertikal&quot;)
+
+ If myDialog.Size.Height = 35 Then
+ myDialog.setPosSize(0,0,0,myHeight,8)
+ oTextField.setVisible(False)
+ ActionItemsTextField.setVisible(True)
+ FixedLineVertikal.setVisible(True)
+ RoadMap.SetVisibleRoadMap(True)
+ Else
+ myDialog.setPosSize(0,0,0,35,8)
+ rmSelectedIndex = RoadMap.GetSelectedIndex() + 1
+ gsTitle = GetStepTitle()
+ oTextField.setText(rmSelectedIndex &amp; &quot;. &quot; &amp; gsTitle)
+ oTextField.setVisible(True)
+ ActionItemsTextField.setVisible(False)
+ FixedLineVertikal.setVisible(False)
+ RoadMap.SetVisibleRoadMap(False)
+ End If
+ If(imageStatus = &quot;MAX&quot;) Then
+ imageStatus = &quot;MIN&quot;
+ ElseIf(imageStatus = &quot;MIN&quot;) Then
+ imageStatus = &quot;MAX&quot;
+ End If
+ setMaxMinImage(imageStatus)
+
+End Sub
+
+Sub SetStepTitle()
+ stepcontent = TutorText(TutorStep)
+ iPos = InStr(stepcontent,CHR(13))
+ stepTitle = Left(stepcontent, iPos)
+ SetStepTitle() = stepTitle
+End Sub
+
+Function GetStepTitle()
+ GetStepTitle() = stepTitle
+End Function
+
+Sub CheckForStepShowButtonStatus()
+ If ((exampleUse.ContainsStepAction() = True And TutorStep = TutorLastStep) Or myDialog.model.show.Label = &quot;Tutorials&quot;) Then
+ myDialog.model.show.enabled = True
+ Else
+ myDialog.model.show.enabled = False
+ End If
+End Sub
+
+Sub CheckForStepNextButtonStatus()
+ If(TutorStep = Ubound(TutorText())) Then
+ myDialog.model.next.enabled = False
+ myDialog.model.done.Label = &quot;Done&quot;
+ End If
+End Sub
+
+Sub Show(aEvent)
+ &apos;ShowInfoMain()
+ If( myDialog.model.show.Label = &quot;Tutorials&quot;) Then
+ oOpenDialogFlag = True
+ DialogVisible = False
+ Else
+ SetMousePosition(aEvent)
+ exampleUse.Action()
+ End If
+End Sub
+
+Sub SetMousePosition(aEvent)
+ MyPoints() = MousePoints(aEvent)
+
+ Dim mousePosition(3) as new com.sun.star.beans.PropertyValue
+ mousePosition(0).Name = &quot;DocumentTYP&quot;
+ mousePosition(0).Value = docTYP
+ mousePosition(1).Name = &quot;MethodName&quot;
+ mousePosition(1).Value = &quot;setMousePosition&quot;
+ mousePosition(2).Name = &quot;Param&quot;
+ mousePosition(2).Value = MyPoints(0)
+ mousePosition(3).Name = &quot;Param&quot;
+ mousePosition(3).Value = MyPoints(1)
+
+ myTutorial.setPropertyValues(mousePosition())
+End Sub
+
+Function MousePoints(aEvent)
+ Dim position(1) As Integer
+ position(0) = myDialog.getControl(&quot;show&quot;).AccessibleContext.LocationOnScreen.X + aEvent.Source.Model.PositionX
+ position(1) = myDialog.getControl(&quot;show&quot;).AccessibleContext.LocationOnScreen.Y + aEvent.Source.Model.PositionY
+ MousePoints = position()
+End Function
+
+Function CheckPath(path() As String)
+ &apos;documentTitle = ThisComponent.getCurrentController.getFrame.Title
+ sTitle = path(0)
+ ResultString = Right(sTitle, 3)
+ iPos = InStr(ResultString,&quot;#&quot;)
+ ResultString = Right(ResultString, Len(ResultString) - iPos)
+ ResultFrameString = InStr (sTitle, &quot;{D}FRAME#&quot;)
+ If ResultFrameString &lt;&gt; 0 Then
+ If Not (sTitle = (&quot;{D}FRAME#&quot; &amp; documentTitle &amp; &quot;#&quot; &amp; ResultString)) Then
+ &apos;path(0) = &quot;{D}FRAME#&quot; &amp; documentTitle &amp; &quot;#&quot; &amp; ResultString
+ path(0) = &quot;FRAME#&quot; &amp; documentTitle &amp; &quot;#&quot; &amp; ResultString
+ sTitle = path(1)
+ ResultString = Right(sTitle, 3)
+ iPos = InStr(ResultString,&quot;#&quot;)
+ ResultString = Right(ResultString, Len(ResultString) - iPos)
+ path(1) = &quot;ROOT_PANE#&quot; &amp; documentTitle &amp; &quot;#&quot; &amp; ResultString
+ Else
+ &apos;path(0) = &quot;{D}FRAME#&quot; &amp; documentTitle &amp; &quot;#&quot; &amp; ResultString
+ path(0) = &quot;FRAME#&quot; &amp; documentTitle &amp; &quot;#&quot; &amp; ResultString
+ End If
+ End If
+End Function
+
+Sub SetVisibleTutorialsDialog(param)
+ myDialog.setVisible(param)
+End Sub
+
+Sub SetVisibleTrue()
+ myDialog.setVisible(True)
+End Sub
+
+Sub SetVisibleFalse()
+ myDialog.setVisible(False)
+End Sub
+
+Sub ExitTutorial()
+ Dim aUrl As new com.sun.star.util.URL
+ oDoc = ThisComponent
+ urlTransformer = createUNOService(&quot;com.sun.star.util.URLTransformer&quot;)
+ aUrl.Complete = &quot;slot:5621&quot;
+ urlTransformer.parseStrict(aUrl)
+ xController = oDoc.getCurrentController()
+ xDispatcher = xController.queryDispatch(aUrl, &quot;&quot;, 0)
+ if NOT isNull(xDispatcher) then
+ xDispatcher.dispatch(aUrl, DimArray())
+ else
+ msgBox &quot;Error! Cannot close document.&quot;
+ End If
+End Sub
+</script:module>
diff --git a/wizards/source/tutorials/RoadMap.xba b/wizards/source/tutorials/RoadMap.xba
new file mode 100644
index 000000000..efcfc03a4
--- /dev/null
+++ b/wizards/source/tutorials/RoadMap.xba
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="RoadMap" script:language="StarBasic">REM ***** BASIC *****
+Dim oControlModel
+Dim oDialogModel
+Dim CurrentItem
+Dim bLongString
+Dim oControl
+Dim oEvent
+Dim oUseDialog As Object
+Dim oModulName As Object
+
+Sub RoadMapMain(ModulNameforItemChange, dialogtoUse)
+ GlobalScope.BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ oUseDialog = dialogtoUse
+ oModulName = ModulNameforItemChange
+ oDialogModel = oUseDialog.Model
+ oControlModel = oUseDialog.Model.CreateInstance(&quot;com.sun.star.awt.UnoControlRoadmapModel&quot;)
+
+ oDialogModel.insertByName(&quot;RoadMap&quot;, oControlModel)
+ oControl = oUseDialog.getControl(&quot;RoadMap&quot;)
+ oEvent = createUnoListener( &quot;CallBack_&quot;, &quot;com.sun.star.awt.XItemListener&quot; )
+ oControl.addItemListener(oEvent)
+ oControlModel.CurrentItemID = 0
+ oControlModel.Complete = True
+ oControlModel.Activated = True
+End Sub
+
+Sub SetVisibleRoadMap(param)
+ oControl.SetVisible(param)
+End Sub
+
+Sub SetDialogModelSize(Width, Height)
+ oDialogModel.Width = Width
+ oDialogModel.Height = Height
+End Sub
+
+Sub SetControlModelPosSize(X, Y, Width, Height)
+ oControlModel.PositionX = X
+ oControlModel.PositionY = Y
+ oControlModel.Width = Width
+ oControlModel.Height = Height
+End Sub
+
+Sub SetControlModelText( ModelText As String)
+ oControlModel.Text = ModelText
+End Sub
+
+Sub InsertItemsLabels( ItemLabelsArray() As String)
+ For i = 0 To Ubound(ItemLabelsArray())
+ oRoadmapItem = oControlModel.createInstance()
+ oRoadmapItem.Label = ItemLabelsArray(i)
+ oRoadmapItem.ID = i
+ oControlModel.insertbyIndex(i, oRoadmapItem)
+ Next i
+End Sub
+
+Sub SetItemEnabled( ItemIndex, param)
+ oControlModel.getByIndex(ItemIndex).Enabled = param
+ oControlModel.CurrentItemID = ItemIndex
+End Sub
+
+Sub AddImagetoControlModel( Url As String)
+ oControlModel.ImageUrl = ConvertToUrl(Url)
+End Sub
+
+Function GetSelectedIndex()
+ GetSelectedIndex() = oControlModel.CurrentItemID
+End Function
+
+Function GetControlModel()
+ GetControlModel = oControlModel
+End Function
+
+Function GetDialogModel()
+ GetDialogModel = oDialogModel
+End Function
+
+Sub Callback_itemStateChanged(aEvent)
+ oModulName.ItemChange(oControlModel.CurrentItemID, aEvent.itemID)
+End Sub
+
+Sub SetComplete(param)
+ oControlModel.Complete = param
+End Sub
+
+Sub SetActivated(param)
+ oControlModel.Activated = param
+End Sub
+
+Sub RemoveItem(ItemIndex)
+ If ItemIndex &gt; -1 Then
+ oControlModel.removeByIndex(ItemIndex)
+ End If
+End Sub
+
+Sub InsertItem(ItemLabel As String)
+ oRoadmapItem = oControlModel.createInstance()
+ oRoadmapItem.Label = ItemLabel
+ oControlModel.insertbyIndex(oControlModel.CurrentItemID, oRoadmapItem)
+End Sub
+
+Sub ReplaceItem(ItemLabel As String)
+ oRoadmapItem = oControlModel.createInstance()
+ oRoadmapItem.Label = ItemLabel
+ oControlModel.replacebyIndex(oControlModel.CurrentItemID, oRoadmapItem)
+End Sub
+
+Sub Callback_disposing(aEvent)
+End Sub
+
+Sub Property_propertyChange(aEvent)
+End Sub
+
+Sub Property_disposing(aEvent)
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/tutorials/ShowInfoDialog.xba b/wizards/source/tutorials/ShowInfoDialog.xba
new file mode 100644
index 000000000..e1da4b596
--- /dev/null
+++ b/wizards/source/tutorials/ShowInfoDialog.xba
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ShowInfoDialog" script:language="StarBasic">REM ***** BASIC *****
+Dim oWnd As Object
+Dim oWnd2 As Object
+Dim oWnd3 As Object
+Dim oDoc as Object
+
+Sub ShowInfoMain
+ prop() = GetShowInfoProperties()
+ Init(prop(0).Value, prop(1).Value, prop(2).Value, prop(3).Value, prop(4).Value, prop(5).Value, prop(6).Value, prop(7).Value, prop(8).Value)
+End Sub
+
+Sub Init(tFieldText As String, windowX, windowY, windowWidth, windowHeight, tFieldX, tFieldY, tFieldWidth, tFieldHeight)
+ toolkit = createUnoService(&quot;com.sun.star.awt.Toolkit&quot;)
+ Dim oWndDescr As new com.sun.star.awt.WindowDescriptor
+ Dim oBounds As new com.sun.star.awt.Rectangle
+ oWndDescr.Type = com.sun.star.awt.WindowClass.TOP
+ oWndDescr.WindowServiceName = &quot;&quot;
+ oWndDescr.ParentIndex = 0
+
+ &apos;officeX = StarDesktop.ActiveFrame.getContainerWindow().AccessibleContext.LocationOnScreen.X
+ &apos;officeY = StarDesktop.ActiveFrame.getContainerWindow().AccessibleContext.LocationOnScreen.Y
+ &apos;officeWidth = StarDesktop.ActiveFrame.getContainerWindow().getPosSize().Width
+ &apos;officeHeight = StarDesktop.ActiveFrame.getContainerWindow().getPosSize().Height
+ officeWidth = thisComponent.CurrentController.Frame.getContainerWindow().getPosSize().Width
+ officeHeight = thisComponent.CurrentController.Frame.getContainerWindow().getPosSize().Height
+
+ &apos;dialogWidth = myTutoShowDialog.getPosSize().Width
+ &apos;dialogHeight = myTutoShowDialog.getPosSize().Height
+ X = officeWidth - windowWidth - windowX
+ Y = officeHeight - windowHeight - windowY
+
+ oBounds.X = X : oBounds.Y = Y
+ oBounds.Width = windowWidth : oBounds.Height = windowHeight
+ oWndDescr.Bounds = oBounds
+ oWndDescr.Parent = thisComponent.CurrentController.Frame.ContainerWindow
+ with com.sun.star.awt.WindowAttribute
+ oWndDescr.WindowAttributes = .CLOSEABLE AND .MOVEABLE AND .SIZEABLE AND .BORDER AND .SHOW
+ end with
+
+ oWnd = toolkit.createWindow(oWndDescr)
+
+ Dim oWndDescr3 As new com.sun.star.awt.WindowDescriptor
+ Dim oBounds3 As new com.sun.star.awt.Rectangle
+ oWndDescr3.Type = com.sun.star.awt.WindowClass.TOP
+ oWndDescr3.WindowServiceName = &quot;fixedimage&quot; &apos;&quot;fixedtext&quot;
+ oWndDescr3.ParentIndex = 0
+ oBounds3.X = 0 : oBounds3.Y = 0
+ oBounds3.Width = tFieldWidth : oBounds3.Height = tFieldHeight
+ oWndDescr3.Bounds = oBounds3
+ oWndDescr3.Parent = oWnd
+ with com.sun.star.awt.WindowAttribute
+ oWndDescr3.WindowAttributes = .CLOSEABLE AND .MOVEABLE AND .SIZEABLE AND .BORDER AND .SHOW
+ end with
+
+ oWnd3= toolkit.createWindow(oWndDescr3)
+ &apos;oWnd2.Text = tFieldText
+ &apos;printdbgInfo(oWnd3)
+ setImage(oWnd3)
+ &apos;oWnd3.Background = 16777215
+&apos; oWnd2.SetBackGround(16776960)
+ oWnd.SetBackGround(16776960)
+&apos; oWnd.FontDescriptors(0).Name = &quot;Albany&quot;
+&apos; oWnd.FontDescriptors(0).StyleName = &quot;BOLD&quot;
+
+ Dim oWndDescr2 As new com.sun.star.awt.WindowDescriptor
+ Dim oBounds2 As new com.sun.star.awt.Rectangle
+ oWndDescr2.Type = com.sun.star.awt.WindowClass.TOP
+ oWndDescr2.WindowServiceName = &quot;fixedtext&quot;
+ oWndDescr2.ParentIndex = 0
+ oBounds2.X = tFieldX : oBounds2.Y = tFieldY
+ oBounds2.Width = tFieldWidth : oBounds2.Height = tFieldHeight
+ oWndDescr2.Bounds = oBounds2
+ oWndDescr2.Parent = oWnd3
+ with com.sun.star.awt.WindowAttribute
+ oWndDescr2.WindowAttributes = .CLOSEABLE AND .MOVEABLE AND .SIZEABLE AND .BORDER AND .SHOW
+ end with
+
+ oWnd2= toolkit.createWindow(oWndDescr2)
+ oWnd2.Text = tFieldText
+ oWnd2.Background = 268435455
+ &apos;printdbgInfo(oWnd2)
+
+ &apos;printdbgInfo oWnd.getPosSize()
+
+End Sub
+
+Function GetShowInfoProperties()
+ stepText = GetStepTitle()
+ Dim Properties(8) As new com.sun.star.beans.NamedValue
+ Properties(0).Name = &quot;ShowInfoDialogText&quot;
+ Properties(0).Value = stepText &amp; &quot;Press [Esc] to abort.&quot;
+ Properties(1).Name = &quot;WindowX&quot;
+ Properties(1).Value = 20
+ Properties(2).Name = &quot;WindowY&quot;
+ Properties(2).Value = 40
+ Properties(3).Name = &quot;WindowWidth&quot;
+ Properties(3).Value = 190
+ Properties(4).Name = &quot;WindowHeight&quot;
+ Properties(4).Value = 50
+ Properties(5).Name = &quot;TFieldX&quot;
+ Properties(5).Value = 7
+ Properties(6).Name = &quot;TFieldY&quot;
+ Properties(6).Value = 8
+ Properties(7).Name = &quot;TFieldWidth&quot;
+ Properties(7).Value = 190
+ Properties(8).Name = &quot;TFieldHeight&quot;
+ Properties(8).Value = 50
+ GetShowInfoProperties = Properties()
+End Function
+
+Sub setShowInfoText()
+ stepText = GetStepTitle()
+ oWnd2.Text = stepText &amp; &quot;Press [Esc] to abort.&quot;
+End Sub
+
+Sub ShowON()
+ setShowInfoText()
+ oWnd.setVisible(True)
+ oWnd3.setVisible(True)
+ oWnd2.setVisible(True)
+End Sub
+
+Sub ShowOFF()
+ &apos;On Local Error Goto NOPROPERTYSETINFO:
+ oWnd.setVisible(False)
+ oWnd2.setVisible(False)
+ oWnd3.setVisible(False)
+ &apos;oDoc.dispose()
+ Exit Sub
+ &apos;NOPROPERTYSETINFO:
+End Sub
+
+Sub DisposeIDialog()
+ &apos;On Local Error Goto NOPROPERTYSETINFO:
+ oWnd3.dispose
+ oWnd2.dispose
+ oWnd.dispose
+ oDoc.dispose()
+ Exit Sub
+ &apos;NOPROPERTYSETINFO:
+End Sub
+
+sub setImage(whatever as Object)
+
+ templatePath = GetPathSettings(&quot;Template&quot;,false, 0)
+ Dim bitmapPath As String
+ iPos = InStr(templatePath,&quot;/&quot;)
+ if(iPos &gt; 0) Then
+ bitmapPath = templatePath &amp; &quot;../wizard/bitmap/tutorial_background.gif&quot;
+ Else
+ bitmapPath = templatePath &amp; &quot;..\wizard\bitmap\tutorial_background.gif&quot;
+ End If
+
+ dim props(0) as new com.sun.star.beans.PropertyValue
+ props(0).Name = &quot;Hidden&quot;
+ props(0).Value = true
+ oDoc = StarDesktop.loadComponentFromUrl(&quot;private:factory/swriter&quot;,&quot;_blank&quot;,0,props())
+ oShape = addControlToDefaultForm(&quot;ImageButton&quot;, 1000, 1000, 2000, 1000)
+ imgControl = oShape.getControl()
+ &apos;imgControl.ImageUrl=&quot;file:///D:/Program%20Files/src680_m11_qwizards1_49_TEST/share/gallery/tutoItem.gif&quot;
+ imgControl.ImageUrl = bitmapPath
+ imgControl.addConsumer(whatever)
+ imgControl.startProduction()
+end sub
+
+Function createControlShape(cKind As String) As Object
+
+ Dim oControlShape As Object
+ Dim oControl As Object
+
+
+ oControlShape = oDoc.createInstance(&quot;com.sun.star.drawing.ControlShape&quot;)
+ oControl = oDoc.createInstance(&quot;com.sun.star.form.component.&quot; &amp; cKind)
+ oControl.setPropertyValue(&quot;DefaultControl&quot;, &quot;com.sun.star.form.control.&quot; &amp; cKind)
+ oControlShape.setControl(oControl)
+
+
+ createControlShape() = oControlShape
+
+End Function
+
+Function createControlShapeWithDefaultControl(cKind As String) As Object
+
+ Dim oControlShape As Object
+ Dim oControl As Object
+
+
+ oControlShape = oDoc.createInstance(&quot;com.sun.star.drawing.ControlShape&quot;)
+ oControl = oDoc.createInstance(&quot;com.sun.star.form.component.&quot; &amp; cKind)
+ oControlShape.setControl(oControl)
+
+
+ createControlShapeWithDefaultControl() = oControlShape
+
+End Function
+
+Function createUNOControlShape(cKind As String, defControl As String) As Object
+
+ Dim oControlShape As Object
+ Dim oControl As Object
+
+
+ oControlShape = oDoc.createInstance(&quot;com.sun.star.drawing.ControlShape&quot;)
+ oControl = oDoc.createInstance(&quot;com.sun.star.form.component.&quot; &amp; cKind)
+ oControl.setPropertyValue(&quot;DefaultControl&quot;, &quot;com.sun.star.awt.&quot; &amp; defControl)
+ oControlShape.setControl(oControl)
+
+
+ createUNOControlShape() = oControlShape
+
+End Function
+
+Function addShape(oShape As Object) As Boolean
+
+ Dim vSize As New com.sun.star.awt.Size
+ Dim oDrawPage As Object
+ Dim oForms As Object
+ Dim oForm As Object
+
+ oDrawPage = oDoc.getDrawPage()
+ oForms = oDrawPage.getForms()
+
+ if oForms.Count = 0 then
+ oForm = oDoc.createInstance(&quot;com.sun.star.form.component.Form&quot;)
+ oForms.insertByIndex(0, oForm)
+ end if
+
+ vSize.Height = 2000 : vSize.Width = 2000
+ oShape.Size = vSize
+ oDrawPage.add(oShape)
+
+ addShape() = true
+
+End Function
+
+sub addControl(cKind as String)
+
+ Dim oDrawPage As Object
+ Dim oForm As Object, oForms As Object
+ Dim oControl As Object, oControlShape As Object
+ Dim aSz As Variant
+ Dim oText As Object
+
+ oDrawPage = oDoc.DrawPage
+ oControlShape = oDoc.createInstance(&quot;com.sun.star.drawing.ControlShape&quot;)
+ oControl = oDoc.createInstance(&quot;com.sun.star.form.component.&quot; + cKind)
+ oForm = oDoc.createInstance(&quot;com.sun.star.form.component.Form&quot;)
+ oforms = oDrawPage.Forms
+ if oforms.count = 0 then
+ oforms.insertbyindex(0,oForm)
+ end if
+ oControlShape.Control = oControl
+ oDrawPage.add(oControlShape)
+
+End sub
+
+Function addControlToDefaultForm(cKind as String, x As Integer, y As Integer, width As Integer, height As Integer) As Object
+
+ Dim oDrawPage As Object
+ Dim oControl As Object, oControlShape As Object
+ Dim pos As New com.sun.star.awt.Point
+ Dim size As New com.sun.star.awt.Size
+
+ pos.X = x
+ pos.Y = y
+ size.Width = width
+ size.Height = height
+
+ oDrawPage = oDoc.DrawPage
+ oControlShape = oDoc.createInstance(&quot;com.sun.star.drawing.ControlShape&quot;)
+ oControl = oDoc.createInstance(&quot;com.sun.star.form.component.&quot; + cKind)
+ oControlShape.Control = oControl
+ oControlShape.Position = pos
+ oControlShape.Size = size
+ oDrawPage.add(oControlShape)
+
+ addControlToDefaultForm() = oControlShape
+
+End Function
+
+Function addShapeToDrawDoc(oPage as Object, nPosX, nPosY as Integer, oType As String) As Object
+ Dim aPoint As New com.sun.star.awt.Point
+ Dim aSize As New com.sun.star.awt.Size
+ Dim oShape As Object
+ Dim servNames As Variant
+
+ aPoint.x = nPosX
+ aPoint.y = nPosY
+ aSize.Width = 2000
+ aSize.Height = 1000
+ oShape = oDoc.createInstance(&quot;com.sun.star.drawing.&quot;+oType+&quot;Shape&quot;)
+ oShape.Size = aSize
+ oShape.Position = aPoint
+
+ if oShape.getPropertySetInfo().hasPropertyByName(&quot;FillColor&quot;) then
+ oShape.FillColor = RGB(128, 255, 0)
+ End If
+
+ oPage.add(oShape)
+
+ addShapeToDrawDoc() = oShape
+End Function
+</script:module>
diff --git a/wizards/source/tutorials/TutorialClose.xba b/wizards/source/tutorials/TutorialClose.xba
new file mode 100644
index 000000000..b4a066b89
--- /dev/null
+++ b/wizards/source/tutorials/TutorialClose.xba
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="TutorialClose" script:language="StarBasic">REM ***** BASIC *****
+Dim myCloseDialog As Object
+
+Sub TutorialCloseMain
+ myCloseDialog = LoadDialog(&quot;Tutorials&quot;,&quot;TutorialCloseDialog&quot;)
+ myCloseDialog.Execute()
+End Sub
+
+Sub CloseYes(aEvent)
+ myCloseDialog.EndExecute()
+ DialogVisible = False
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/tutorials/TutorialCloseDialog.xdl b/wizards/source/tutorials/TutorialCloseDialog.xdl
new file mode 100644
index 000000000..a362b2a44
--- /dev/null
+++ b/wizards/source/tutorials/TutorialCloseDialog.xdl
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="TutorialCloseDialog" dlg:left="173" dlg:top="82" dlg:width="132" dlg:height="38" dlg:closeable="true" dlg:moveable="true">
+ <dlg:styles>
+ <dlg:style dlg:style-id="0" dlg:font-weight="150"/>
+ </dlg:styles>
+ <dlg:bulletinboard>
+ <dlg:button dlg:id="yesButton" dlg:tab-index="1" dlg:left="24" dlg:top="20" dlg:width="50" dlg:height="14" dlg:value="Yes">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.TutorialClose.CloseYes?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="noButton" dlg:tab-index="0" dlg:left="76" dlg:top="20" dlg:width="50" dlg:height="14" dlg:value="No" dlg:button-type="cancel"/>
+ <dlg:text dlg:style-id="0" dlg:id="Label1" dlg:tab-index="2" dlg:left="6" dlg:top="6" dlg:width="120" dlg:height="8" dlg:value="Do you want to close this Tutorial?." dlg:align="center"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/tutorials/TutorialCreator.xba b/wizards/source/tutorials/TutorialCreator.xba
new file mode 100644
index 000000000..34e1276f4
--- /dev/null
+++ b/wizards/source/tutorials/TutorialCreator.xba
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="TutorialCreator" script:language="StarBasic">REM ***** BASIC *****
+Sub TutorialCreatorMain
+ GlobalScope.BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ myTutorial = createUNOService(&quot;com.sun.star.wizards.tutorial.executer.CallTutorialFramework&quot;)
+ myTutorial.trigger(&quot;StartTutorialCreator&quot;)
+End Sub
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/tutorials/TutorialOpen.xba b/wizards/source/tutorials/TutorialOpen.xba
new file mode 100644
index 000000000..5b6001c6c
--- /dev/null
+++ b/wizards/source/tutorials/TutorialOpen.xba
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="TutorialOpen" script:language="StarBasic">REM ***** BASIC *****
+Dim myOpenDialog As Object
+Dim oListBox As Object
+Dim files As Object
+Dim oUcb As Object
+Dim oListener As Object
+
+Sub TutorialOpenMain
+ GlobalScope.BasicLibraries.LoadLibrary(&quot;Tools&quot;)
+ myOpenDialog = LoadDialog(&quot;Tutorials&quot;,&quot;TutorialOpenDialog&quot;)
+ init()
+ myOpenDialog.Execute()
+End Sub
+
+Sub Init
+ On Local Error Goto NOFILE
+ myOpenDialog.Title = &quot;Tutorials&quot;
+ oListBox = myOpenDialog.GetControl(&quot;ListBox&quot;)
+ templatePath = GetPathSettings(&quot;Template&quot;,false, 0)
+ Dim tutorialPath As String
+ iPos = InStr(templatePath,&quot;/&quot;)
+ if(iPos &gt; 0) Then
+ tutorialPath = templatePath &amp; &quot;/tutorials&quot;
+ Else
+ tutorialPath = templatePath &amp; &quot;\tutorials&quot;
+ End If
+ oUcb = createUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
+ files = oUcb.getFolderContents(tutorialPath,true)
+ size = Ubound( files() )
+ Dim tempFiles(size) As String
+ tempCount = 0
+ For iCount = 0 To size
+ completPath = files(iCount)
+ oDocInfo = CreateUnoService(&quot;com.sun.star.document.DocumentProperties&quot;)
+ oDocInfo.Read(completPath)
+ sDocTitle = oDocInfo.Title
+ if(not isNull(sDocTitle) And len(sDocTitle) &gt; 0) Then
+ oListbox.addItem(sDocTitle,0)
+ tempFiles(tempCount) = completPath
+ tempCount = tempCount + 1
+ End If
+ Next iCount
+ &apos;printdbgInfo oListbox
+ size = oListbox.ItemCount - 1
+ Dim tempFiles2(size) As String
+ For iCount = 0 To size
+ tempFiles2(iCount) = tempFiles(iCount)
+ Next iCount
+ files() = tempFiles2()
+ Exit Sub
+ NOFILE:
+ If Err &lt;&gt; 0 Then
+ Msgbox &quot;No file found error!&quot; &amp; CHR(13) &amp; &quot;Path: ...\share\template\...\tutorials\&quot;
+ myOpenDialog.model.Open.enabled = False
+ End If
+End Sub
+
+Sub ItemSelected(oEvent)
+ On Local Error Goto NOFILE
+ completPath = files(Ubound(files()) - oEvent.Selected)
+ oTextField = myOpenDialog.GetControl(&quot;Label&quot;) &apos;TextField
+ oTextField.setText(&quot;&quot;)
+ Dim NoArgs() as new com.sun.star.beans.PropertyValue
+ oDocInfo = CreateUnoService(&quot;com.sun.star.document.DocumentProperties&quot;)
+ oDocInfo.Read(completPath)
+ sDocDescription = oDocInfo.Description
+ if(not isNull(sDocTitle) And len(sDocDescription) &gt; 0) Then
+ oTextField.setText(sDocDescription)
+ Else
+ oTextField.setText(&quot;Not Description!!!.&quot;)
+ End If
+ Exit Sub
+ NOFILE:
+ If Err &lt;&gt; 0 Then
+ Msgbox &quot;Open file error!&quot;
+ End If
+End Sub
+
+Sub OpenTutorial(aEvent)
+ completPath = files(Ubound(files()) - oListBox.getSelectedItemPos())
+ Dim Args(2) as new com.sun.star.beans.PropertyValue
+ Args(1).Name = &quot;MacroExecutionMode&quot;
+ Args(1).Value = com.sun.star.document.MacroExecMode.ALWAYS_EXECUTE
+ Args(2).Name = &quot;AsTemplate&quot;
+ Args(2).Value = true
+
+ StarDesktop.LoadComponentFromURL(completPath,&quot;_default&quot;,0, Args())
+ myOpenDialog.endExecute()
+End Sub
+
+Sub Cancel(aEvent)
+ myOpenDialog.endExecute()
+End Sub
+</script:module> \ No newline at end of file
diff --git a/wizards/source/tutorials/TutorialOpenDialog.xdl b/wizards/source/tutorials/TutorialOpenDialog.xdl
new file mode 100644
index 000000000..d9a6009a3
--- /dev/null
+++ b/wizards/source/tutorials/TutorialOpenDialog.xdl
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="TutorialOpenDialog" dlg:left="158" dlg:top="58" dlg:width="250" dlg:height="200" dlg:closeable="true" dlg:moveable="true">
+ <dlg:bulletinboard>
+ <dlg:button dlg:id="Open" dlg:tab-index="1" dlg:left="141" dlg:top="180" dlg:width="50" dlg:height="14" dlg:value="Open">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.TutorialOpen.OpenTutorial?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="Cancel" dlg:tab-index="2" dlg:left="194" dlg:top="180" dlg:width="50" dlg:height="14" dlg:value="Cancel">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.TutorialOpen.Cancel?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:menulist dlg:id="ListBox" dlg:tab-index="0" dlg:left="8" dlg:top="17" dlg:width="98" dlg:height="155">
+ <script:event script:event-name="on-performaction" script:location="application" script:macro-name="Tutorials.TutorialOpen.OpenTutorial" script:language="StarBasic"/>
+ <script:event script:event-name="on-itemstatechange" script:location="application" script:macro-name="Tutorials.TutorialOpen.ItemSelected" script:language="StarBasic"/>
+ </dlg:menulist>
+ <dlg:fixedline dlg:id="FixedLine" dlg:tab-index="3" dlg:left="6" dlg:top="6" dlg:width="100" dlg:height="8" dlg:value="Tutorials"/>
+ <dlg:fixedline dlg:id="FixedLine1" dlg:tab-index="4" dlg:left="6" dlg:top="176" dlg:width="238" dlg:height="1"/>
+ <dlg:fixedline dlg:id="FixedLine2" dlg:tab-index="5" dlg:left="110" dlg:top="6" dlg:width="134" dlg:height="8" dlg:value="Description"/>
+ <dlg:fixedline dlg:id="FixedLine3" dlg:tab-index="6" dlg:left="267" dlg:top="44" dlg:width="0" dlg:height="2"/>
+ <dlg:text dlg:id="Label" dlg:tab-index="7" dlg:left="112" dlg:top="17" dlg:width="132" dlg:height="155" dlg:multiline="true"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/tutorials/TutorialsDialog.xdl b/wizards/source/tutorials/TutorialsDialog.xdl
new file mode 100644
index 000000000..f8a2ee211
--- /dev/null
+++ b/wizards/source/tutorials/TutorialsDialog.xdl
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="TutorialsDialog" dlg:left="149" dlg:top="54" dlg:width="250" dlg:height="200" dlg:closeable="true" dlg:moveable="true">
+ <dlg:styles>
+ <dlg:style dlg:style-id="0" dlg:font-weight="150"/>
+ </dlg:styles>
+ <dlg:bulletinboard>
+ <dlg:button dlg:id="CommandButton" dlg:tab-index="3" dlg:left="232" dlg:top="4" dlg:width="13" dlg:height="13" dlg:value="C">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.Functions.Minimize?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:id="myText" dlg:tab-index="4" dlg:left="91" dlg:top="26" dlg:width="153" dlg:height="145" dlg:value="This text explains all the action items that the user can do to follow the current step highlighted in the road map at the left side of the tutorial window.&#x0a;&#x0a;1. Open the Format menu&#x0a;2. Choose the Paragraph command&#x0a;3. Click the Numbering tab&#x0a;&#x0a;The first step will always explain what the current tutorial is about.&#x0a;&#x0a;The last step - it is highlighted currently in the road map - will summarize what the user now has seen or learned." dlg:multiline="true"/>
+ <dlg:button dlg:id="show" dlg:tab-index="1" dlg:left="142" dlg:top="180" dlg:width="50" dlg:height="14" dlg:value="Show me">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.Functions.Show?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:button dlg:id="next" dlg:tab-index="0" dlg:left="89" dlg:top="180" dlg:width="50" dlg:height="14" dlg:value="Next &gt;&gt;">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.Functions.NextStep?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:style-id="0" dlg:id="myTextField" dlg:tab-index="5" dlg:left="6" dlg:top="6" dlg:width="192" dlg:height="8" dlg:value="Current Step (in Road Map)"/>
+ <dlg:button dlg:id="done" dlg:tab-index="2" dlg:left="195" dlg:top="180" dlg:width="50" dlg:height="14" dlg:value="Close">
+ <script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:Tutorials.Functions.EndDialog?language=Basic&amp;location=application" script:language="Script"/>
+ </dlg:button>
+ <dlg:text dlg:style-id="0" dlg:id="ActionItemsLabel" dlg:tab-index="8" dlg:left="91" dlg:top="8" dlg:width="45" dlg:height="8" dlg:value="Action Items"/>
+ <dlg:fixedline dlg:id="FixedLineHorizontal" dlg:tab-index="7" dlg:left="0" dlg:top="176" dlg:width="250" dlg:height="1"/>
+ <dlg:fixedline dlg:id="FixedLineVertikal" dlg:tab-index="6" dlg:left="85" dlg:top="0" dlg:width="1" dlg:height="176" dlg:align="vertical"/>
+ </dlg:bulletinboard>
+</dlg:window> \ No newline at end of file
diff --git a/wizards/source/tutorials/dialog.xlb b/wizards/source/tutorials/dialog.xlb
new file mode 100644
index 000000000..e02b20688
--- /dev/null
+++ b/wizards/source/tutorials/dialog.xlb
@@ -0,0 +1,7 @@
+<?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="Tutorials" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="TutorialsDialog"/>
+ <library:element library:name="TutorialOpenDialog"/>
+ <library:element library:name="TutorialCloseDialog"/>
+</library:library> \ No newline at end of file
diff --git a/wizards/source/tutorials/script.xlb b/wizards/source/tutorials/script.xlb
new file mode 100644
index 000000000..30280c6b1
--- /dev/null
+++ b/wizards/source/tutorials/script.xlb
@@ -0,0 +1,10 @@
+<?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="Tutorials" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="Functions"/>
+ <library:element library:name="TutorialCreator"/>
+ <library:element library:name="TutorialOpen"/>
+ <library:element library:name="RoadMap"/>
+ <library:element library:name="ShowInfoDialog"/>
+ <library:element library:name="TutorialClose"/>
+</library:library> \ No newline at end of file