This commit is contained in:
Jane
2024-07-16 15:55:31 +08:00
parent 8f4ec86367
commit 29bc31ade5
12411 changed files with 8139339 additions and 0 deletions

View File

@@ -0,0 +1,996 @@
<?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;OpenQuery&quot; _
, &quot;OpenSql&quot; _
, &quot;OpenTable&quot; _
, &quot;RunSql&quot; _
)
End Function &apos; SFDatabases.SF_Database.Methods
REM -----------------------------------------------------------------------------
Public Function OpenQuery(Optional ByVal QueryName As Variant) As Object
&apos;&apos;&apos; Open the query given by its name
&apos;&apos;&apos; The datasheet will live independently from any other (typically Base) component
&apos;&apos;&apos; Args:
&apos;&apos;&apos; QueryName: a valid query name as a case-sensitive string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Datasheet class instance if the query could be opened, otherwise Nothing
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; Query name is invalid
&apos;&apos;&apos; Example:
&apos;&apos;&apos; oDb.OpenQuery(&quot;myQuery&quot;)
Dim oOpen As Object &apos; Return value
Const cstThisSub = &quot;SFDatabases.Database.OpenQuery&quot;
Const cstSubArgs = &quot;QueryName&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Set oOpen = Nothing
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not ScriptForge.SF_Utils._Validate(QueryName, &quot;QueryName&quot;, V_STRING, Queries) Then GoTo Finally
End If
Try:
Set oOpen = _OpenDatasheet(QueryName, com.sun.star.sdb.CommandType.QUERY _
, _Connection.Queries.getByName(QueryName).EscapeProcessing)
Finally:
Set OpenQuery = oOpen
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Base.OpenQuery
REM -----------------------------------------------------------------------------
Public Function OpenSql(Optional ByRef Sql As Variant _
, Optional ByVal DirectSql As Variant _
) As Object
&apos;&apos;&apos; Open the datasheet based on a SQL SELECT statement.
&apos;&apos;&apos; The datasheet will live independently from any other (typically Base) component
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Sql: a valid Sql statement as a case-sensitive string.
&apos;&apos;&apos; Identifiers may be surrounded by square brackets
&apos;&apos;&apos; DirectSql: when True, the statement is processed by the targeted RDBMS
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Datasheet class instance if it could be opened, otherwise Nothing
&apos;&apos;&apos; Example:
&apos;&apos;&apos; oDb.OpenSql(&quot;SELECT * FROM [Customers] ORDER BY [CITY]&quot;)
Dim oOpen As Object &apos; Return value
Const cstThisSub = &quot;SFDatabases.Database.OpenSql&quot;
Const cstSubArgs = &quot;Sql, [DirectSql=False]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Set oOpen = Nothing
Check:
If IsMissing(DirectSql) Or IsEmpty(DirectSql) Then DirectSql = False
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not ScriptForge.SF_Utils._Validate(Sql, &quot;Sql&quot;, V_STRING) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(DirectSql, &quot;DirectSql&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Try:
Set oOpen = _OpenDatasheet(_ReplaceSquareBrackets(Sql), com.sun.star.sdb.CommandType.COMMAND, Not DirectSql)
Finally:
Set OpenSql = oOpen
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Base.OpenSql
REM -----------------------------------------------------------------------------
Public Function OpenTable(Optional ByVal TableName As Variant) As Object
&apos;&apos;&apos; Open the table given by its name
&apos;&apos;&apos; The datasheet will live independently from any other (typically Base) component
&apos;&apos;&apos; Args:
&apos;&apos;&apos; TableName: a valid table name as a case-sensitive string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Datasheet class instance if the table could be opened, otherwise Nothing
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; Table name is invalid
&apos;&apos;&apos; Example:
&apos;&apos;&apos; oDb.OpenTable(&quot;myTable&quot;)
Dim oOpen As Object &apos; Return value
Const cstThisSub = &quot;SFDatabases.Database.OpenTable&quot;
Const cstSubArgs = &quot;TableName&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Set oOpen = Nothing
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not ScriptForge.SF_Utils._Validate(TableName, &quot;TableName&quot;, V_STRING, Tables) Then GoTo Finally
End If
Try:
Set oOpen = _OpenDatasheet(TableName, com.sun.star.sdb.CommandType.TABLE, True)
Finally:
Set OpenTable = oOpen
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Base.OpenTable
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 or com.sun.star.awt.XTabControllerModel
&apos;&apos;&apos; plColIndex: the index of the column to extract the value from. Starts at 1
&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 = Empty &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(oStream.getLength())
End If
If lSize &lt;= cstMaxBinLength And pbReturnBinary Then
vValue = Array()
oStream.readBytes(vValue, lSize)
Else &apos; Return length of field, not content
vValue = lSize
End If
End If
End If
If Not IsNull(oStream) Then oStream.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 -----------------------------------------------------------------------------
Public Function _OpenDatasheet(Optional ByVal psCommand As Variant _
, piDatasheetType As Integer _
, pbEscapeProcessing As Boolean _
) As Object
&apos;&apos;&apos; Open the datasheet given by its name and its type
&apos;&apos;&apos; The datasheet will live independently from any other component
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psCommand: a valid table or query name or an SQL statement as a case-sensitive string
&apos;&apos;&apos; piDatasheetType: one of the com.sun.star.sdb.CommandType constants
&apos;&apos;&apos; pbEscapeProcessing: == Not DirectSql
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Datasheet class instance if the datasheet could be opened, otherwise Nothing
Dim oOpen As Object &apos; Return value
Dim oNewDatasheet As Object &apos; com.sun.star.lang.XComponent
Dim oURL As Object &apos; com.sun.star.util.URL
Dim oDispatch As Object &apos; com.sun.star.frame.XDispatch
Dim vArgs As Variant &apos; Array of property values
On Local Error GoTo Catch
Set oOpen = Nothing
Try:
&apos; Setup the dispatcher
Set oURL = New com.sun.star.util.URL
oURL.Complete = &quot;.component:DB/DataSourceBrowser&quot;
Set oDispatch = StarDesktop.queryDispatch(oURL, &quot;_blank&quot;, com.sun.star.frame.FrameSearchFlag.CREATE)
&apos; Setup the arguments of the component to create
With ScriptForge.SF_Utils
vArgs = Array( _
._MakePropertyValue(&quot;ActiveConnection&quot;, _Connection) _
, ._MakePropertyValue(&quot;CommandType&quot;, piDatasheetType) _
, ._MakePropertyValue(&quot;Command&quot;, psCommand) _
, ._MakePropertyValue(&quot;ShowMenu&quot;, True) _
, ._MakePropertyValue(&quot;ShowTreeView&quot;, False) _
, ._MakePropertyValue(&quot;ShowTreeViewButton&quot;, False) _
, ._MakePropertyValue(&quot;Filter&quot;, &quot;&quot;) _
, ._MakePropertyValue(&quot;ApplyFilter&quot;, False) _
, ._MakePropertyValue(&quot;EscapeProcessing&quot;, pbEscapeProcessing) _
)
End With
&apos; Open the targeted datasheet
Set oNewDatasheet = oDispatch.dispatchWithReturnValue(oURL, vArgs)
If Not IsNull(oNewDatasheet) Then Set oOpen = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Datasheet&quot;, oNewDatasheet, [Me])
Finally:
Set _OpenDatasheet = oOpen
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Base._OpenDatasheet
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>

View File

@@ -0,0 +1,894 @@
<?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_Datasheet" 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_Datasheet
&apos;&apos;&apos; ============
&apos;&apos;&apos; A datasheet is the visual representation of tabular data produced by a database.
&apos;&apos;&apos; In the user interface of LibreOffice it is the result of the opening of
&apos;&apos;&apos; a table or a query. In this case the concerned Base document must be open.
&apos;&apos;&apos;
&apos;&apos;&apos; In the context of ScriptForge, a datasheet may be opened automatically by script code :
&apos;&apos;&apos; - either by reproducing the behaviour of the user interface
&apos;&apos;&apos; - or at any moment. In this case the Base document may or may not be opened.
&apos;&apos;&apos; Additionally, any SELECT SQL statement may trigger the datasheet display.
&apos;&apos;&apos;
&apos;&apos;&apos; The proposed API allows for either datasheets (opened manually of by code) in particular
&apos;&apos;&apos; to know which cell is selected and its content.
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation:
&apos;&apos;&apos; 1) From an open Base document
&apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
&apos;&apos;&apos; Set oBase = ui.getDocument(&quot;/home/user/Documents/myDb.odb&quot;)
&apos;&apos;&apos; Set oSheet1 = oBase.OpenTable(&quot;Customers&quot;) &apos; or OpenQuery(...)
&apos;&apos;&apos; Set oSheet2 = oBase.Datasheets(&quot;Products&quot;) &apos; when the datasheet has been opened manually
&apos;&apos;&apos; 2) Independently from a Base document
&apos;&apos;&apos; Set oDatabase = CreateScriptService(&quot;Database&quot;, &quot;/home/user/Documents/myDb.odb&quot;)
&apos;&apos;&apos; Set oSheet = oDatabase.OpenTable(&quot;Customers&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_datasheet.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 DOCUMENTDEADERROR = &quot;DOCUMENTDEADERROR&quot;
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object &apos; Base instance when opened from a Base document by code
&apos; or Database instance when opened without Base document
Private ObjectType As String &apos; Must be DATASHEET
Private ServiceName As String
Private _Component As Object &apos; com.sun.star.lang.XComponent - org.openoffice.comp.dbu.ODatasourceBrowser
Private _Frame As Object &apos; com.sun.star.frame.XFrame
Private _ParentBase As Object &apos; The parent SF_Base instance (may be void)
Private _ParentDatabase As Object &apos; The parent SF_Database instance (must not be void)
Private _SheetType As String &apos; TABLE, QUERY or SQL
Private _ParentType As String &apos; BASE or DATABASE
Private _BaseFileName As String &apos; URL format of parent Base file
Private _Command As String &apos; Table name, query name or SQL statement
Private _DirectSql As Boolean &apos; When True, SQL processed by RDBMS
Private _TabControllerModel As Object &apos; com.sun.star.awt.XTabControllerModel - com.sun.star.comp.forms.ODatabaseForm
Private _ControlModel As Object &apos; com.sun.star.awt.XControlModel - com.sun.star.form.OGridControlModel
Private _ControlView As Object &apos; com.sun.star.awt.XControl - org.openoffice.comp.dbu.ODatasourceBrowser
Private _ColumnHeaders As Variant &apos; List of column headers as an array of strings
REM ============================================================ MODULE CONSTANTS
REM ====================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;DATASHEET&quot;
ServiceName = &quot;SFDatabases.Datasheet&quot;
Set _Component = Nothing
Set _Frame = Nothing
Set _ParentBase = Nothing
Set _ParentDatabase = Nothing
_SheetType = &quot;&quot;
_ParentType = &quot;&quot;
_BaseFileName = &quot;&quot;
_Command = &quot;&quot;
_DirectSql = False
Set _TabControllerModel = Nothing
Set _ControlModel = Nothing
Set _ControlView = Nothing
_ColumnHeaders = Array()
End Sub &apos; SFDatabases.SF_Datasheet Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; SFDatabases.SF_Datasheet Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; SFDatabases.SF_Datasheet Explicit Destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get ColumnHeaders() As Variant
&apos;&apos;&apos; Returns the list of column headers of the datasheet as an array of strings
ColumnHeaders = _PropertyGet(&quot;ColumnHeaders&quot;)
End Property &apos; SFDatabases.SF_Datasheet.ColumnHeaders
REM -----------------------------------------------------------------------------
Property Get CurrentColumn() As String
&apos;&apos;&apos; Returns the currently selected column by its name
CurrentColumn = _PropertyGet(&quot;CurrentColumn&quot;)
End Property &apos; SFDatabases.SF_Datasheet.CurrentColumn
REM -----------------------------------------------------------------------------
Property Get CurrentRow() As Long
&apos;&apos;&apos; Returns the currently selected row by its number &gt;= 1
CurrentRow = _PropertyGet(&quot;CurrentRow&quot;)
End Property &apos; SFDatabases.SF_Datasheet.CurrentRow
REM -----------------------------------------------------------------------------
Property Get DatabaseFileName() As String
&apos;&apos;&apos; Returns the file name of the Base file in FSO.FileNaming format
DatabaseFileName = _PropertyGet(&quot;DatabaseFileName&quot;)
End Property &apos; SFDatabases.SF_Datasheet.DatabaseFileName
REM -----------------------------------------------------------------------------
Property Get Filter() As Variant
&apos;&apos;&apos; The Filter is a SQL WHERE clause without the WHERE keyword
Filter = _PropertyGet(&quot;Filter&quot;)
End Property &apos; SFDatabases.SF_Datasheet.Filter (get)
REM -----------------------------------------------------------------------------
Property Let Filter(Optional ByVal pvFilter As Variant)
&apos;&apos;&apos; Set the updatable property Filter
&apos;&apos;&apos; Table and field names may be surrounded by square brackets
&apos;&apos;&apos; When the argument is the zero-length string, the actual filter is removed
_PropertySet(&quot;Filter&quot;, pvFilter)
End Property &apos; SFDatabases.SF_Datasheet.Filter (let)
REM -----------------------------------------------------------------------------
Property Get LastRow() As Long
&apos;&apos;&apos; Returns the total number of rows
&apos;&apos;&apos; The process may imply to move the cursor to the last available row.
&apos;&apos;&apos; Afterwards the cursor is reset to the current row.
LastRow = _PropertyGet(&quot;LastRow&quot;)
End Property &apos; SFDatabases.SF_Datasheet.LastRow
REM -----------------------------------------------------------------------------
Property Get OrderBy() As Variant
&apos;&apos;&apos; The Order is a SQL ORDER BY clause without the ORDER BY keywords
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
&apos;&apos;&apos; Table and field names may be surrounded by square brackets
&apos;&apos;&apos; When the argument is the zero-length string, the actual sort is removed
_PropertySet(&quot;OrderBy&quot;, pvOrderBy)
End Property &apos; SFDocuments.SF_Form.OrderBy (let)
REM -----------------------------------------------------------------------------
Property Get ParentDatabase() As Object
&apos;&apos;&apos; Returns the database instance to which the datasheet belongs
Set ParentDatabase = _PropertyGet(&quot;ParentDatabase&quot;)
End Property &apos; SFDatabases.SF_Datasheet.ParentDatabase
REM -----------------------------------------------------------------------------
Property Get Source() As String
&apos;&apos;&apos; Returns the source of the data: table name, query name or sql statement
Source = _PropertyGet(&quot;Source&quot;)
End Property &apos; SFDatabases.SF_Datasheet.Source
REM -----------------------------------------------------------------------------
Property Get SourceType() As String
&apos;&apos;&apos; Returns thetype of source of the data: TABLE, QUERY or SQL
SourceType = _PropertyGet(&quot;SourceType&quot;)
End Property &apos; SFDatabases.SF_Datasheet.SourceType
REM -----------------------------------------------------------------------------
Property Get XComponent() As Object
&apos;&apos;&apos; Returns the com.sun.star.lang.XComponent UNO object representing the datasheet
XComponent = _PropertyGet(&quot;XComponent&quot;)
End Property &apos; SFDocuments.SF_Document.XComponent
REM -----------------------------------------------------------------------------
Property Get XControlModel() As Object
&apos;&apos;&apos; Returns the com.sun.star.lang.XControl UNO object representing the datasheet
XControlModel = _PropertyGet(&quot;XControlModel&quot;)
End Property &apos; SFDocuments.SF_Document.XControlModel
REM -----------------------------------------------------------------------------
Property Get XTabControllerModel() As Object
&apos;&apos;&apos; Returns the com.sun.star.lang.XTabControllerModel UNO object representing the datasheet
XTabControllerModel = _PropertyGet(&quot;XTabControllerModel&quot;)
End Property &apos; SFDocuments.SF_Document.XTabControllerModel
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Sub Activate()
&apos;&apos;&apos; Make the actual datasheet active
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oSheet.Activate()
Dim oContainer As Object &apos; com.sun.star.awt.XWindow
Const cstThisSub = &quot;SFDatabases.Datasheet.Activate&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsStillAlive() Then GoTo Finally
Try:
Set oContainer = _Component.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
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; SFDatabases.SF_Datasheet.Activate
REM -----------------------------------------------------------------------------
Public Function CloseDatasheet() As Boolean
&apos;&apos;&apos; Close the actual datasheet
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True when successful
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oSheet.CloseDatasheet()
Dim bClose As Boolean &apos; Return value
Const cstThisSub = &quot;SFDatabases.Datasheet.CloseDatasheet&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 _IsStillAlive() Then GoTo Finally
Try:
_TabControllerModel.close()
_Frame.close(True)
_Frame.dispose()
Dispose()
bClose = True
Finally:
CloseDatasheet = bClose
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet.CloseDatasheet
REM -----------------------------------------------------------------------------
Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
, Optional ByVal Before As Variant _
, Optional ByVal SubmenuChar As Variant _
) As Object
&apos;&apos;&apos; Create a new menu entry in the datasheet&apos;s menubar
&apos;&apos;&apos; The menu is not intended to be saved neither in the LibreOffice global environment, nor elsewhere
&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; 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;.uno: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;SFDatabases.Datasheet.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 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;, _Component, MenuHeader, Before, SubmenuChar)
Finally:
Set CreateMenu = oMenu
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Document.CreateMenu
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 propRATTCerty
&apos;&apos;&apos; If the property does not exist, returns Null
Const cstThisSub = &quot;SFDatabases.Datasheet.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_Datasheet.GetProperty
REM -----------------------------------------------------------------------------
Public Function GetText(Optional ByVal Column As Variant) As String
&apos;&apos;&apos; Get the text in the given column of the current row.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Column: the name of the column as a string or its position (&gt;= 1). Default = the current column
&apos;&apos;&apos; If the argument exceeds the number of columns, the last column is selected.
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The text in the cell as a string as how it is displayed
&apos;&apos;&apos; Note that the position of the cursor is left unchanged.
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oSheet.GetText(&quot;ShipCity&quot;)) &apos; Extract the text on the current row from the column &quot;ShipCity&quot;
Dim sText As String &apos; Return Text
Dim lCol As Long &apos; Numeric index of Column in lists of columns
Dim lMaxCol As Long &apos; Index of last column
Const cstThisSub = &quot;SFDatabases.Datasheet.GetText&quot;
Const cstSubArgs = &quot;[Column=0]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sText = &quot;&quot;
Check:
If IsMissing(Column) Or IsEmpty(Column) Then Column = 0
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If VarType(Column) &lt;&gt; V_STRING Then
If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
Else
If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, V_STRING, _ColumnHeaders) Then GoTo Catch
End If
End If
Try:
&apos; Position the column - The index to be passed starts at 0
With _ControlView
If VarType(Column) = V_STRING Then
lCol = ScriptForge.SF_Array.IndexOf(_ColumnHeaders, Column, CaseSensitive := False)
Else
lCol = -1
If Column &gt;= 1 Then
lMaxCol = .Count - 1
If Column &gt; lMaxCol + 1 Then lCol = lMaxCol Else lCol = Column - 1
End If
End If
If lCol &gt;= 0 Then sText = .getByIndex(lCol).Text
End With
Finally:
GetText = sText
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet.GetText
REM -----------------------------------------------------------------------------
Public Function GetValue(Optional ByVal Column As Variant) As Variant
&apos;&apos;&apos; Get the value in the given column of the current row.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Column: the name of the column as a string or its position (&gt;= 1). Default = the current column
&apos;&apos;&apos; If the argument exceeds the number of columns, the last column is selected.
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The value in the cell as a valid Basic type
&apos;&apos;&apos; Typical types are: STRING, INTEGER, LONG, FLOAT, DOUBLE, DATE, NULL
&apos;&apos;&apos; Binary types are returned as a LONG giving their length, not their content
&apos;&apos;&apos; An EMPTY return value means that the value could not be retrieved.
&apos;&apos;&apos; Note that the position of the cursor is left unchanged.
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oSheet.GetValue(&quot;ShipCity&quot;)) &apos; Extract the value on the current row from the column &quot;ShipCity&quot;
Dim vValue As Variant &apos; Return value
Dim lCol As Long &apos; Numeric index of Column in lists of columns
Dim lMaxCol As Long &apos; Index of last column
Const cstThisSub = &quot;SFDatabases.Datasheet.GetValue&quot;
Const cstSubArgs = &quot;[Column=0]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vValue = Empty
Check:
If IsMissing(Column) Or IsEmpty(Column) Then Column = 0
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If VarType(Column) &lt;&gt; V_STRING Then
If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
Else
If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, V_STRING, _ColumnHeaders) Then GoTo Catch
End If
End If
Try:
&apos; Position the column - The index to be passed starts at 1
If VarType(Column) = V_STRING Then
lCol = ScriptForge.SF_Array.IndexOf(_ColumnHeaders, Column, CaseSensitive := False) + 1
Else
lCol = 0
If Column &gt;= 1 Then
lMaxCol = _ControlView.Count
If Column &gt; lMaxCol Then lCol = lMaxCol Else lCol = Column
End If
End If
&apos; The _TabControllerModel acts exactly as a result set, from which the generic _GetColumnValue can extract the searched value
If lCol &gt;= 1 Then vValue = _ParentDatabase._GetColumnValue(_TabControllerModel, lCol)
Finally:
GetValue = vValue
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet.GetValue
REM -----------------------------------------------------------------------------
Public Function GoToCell(Optional ByVal Row As Variant _
, Optional ByVal Column As Variant _
) As Boolean
&apos;&apos;&apos; Set the cursor on the given row and the given column.
&apos;&apos;&apos; If the requested row exceeds the number of available rows, the cursor is set on the last row.
&apos;&apos;&apos; If the requested column exceeds the number of available columns, the selected column is the last one.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Row: the row number (&gt;= 1) as a numeric value. Default= no change
&apos;&apos;&apos; Column: the name of the column as a string or its position (&gt;= 1). Default = the current column
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True when successful
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oSheet.GoToCell(1000000, &quot;ShipCity&quot;)) &apos; Set the cursor on he last row, column &quot;ShipCity&quot;
Dim bGoTo As Boolean &apos; Return value
Dim lCol As Long &apos; Numeric index of Column in list of columns
Dim lMaxCol As Long &apos; Index of last column
Const cstThisSub = &quot;SFDatabases.Datasheet.GoToCell&quot;
Const cstSubArgs = &quot;[Row=0], [Column=0]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bGoTo = False
Check:
If IsMissing(Row) Or IsEmpty(Row) Then Row = 0
If IsMissing(Column) Or IsEmpty(Column) Then Column = 0
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(Row, &quot;Row&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
If VarType(Column) &lt;&gt; V_STRING Then
If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
Else
If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, V_STRING, _ColumnHeaders) Then GoTo Catch
End If
End If
Try:
&apos; Position the row
With _TabControllerModel
If Row &lt;= 0 Then Row = .Row Else .absolute(Row)
&apos; Does Row exceed the total number of rows ?
If .IsRowCountFinal And Row &gt; .RowCount Then .absolute(.RowCount)
End With
&apos; Position the column
With _ControlView
If VarType(Column) = V_STRING Then
lCol = ScriptForge.SF_Array.IndexOf(_ColumnHeaders, Column, CaseSensitive := False)
Else
lCol = -1
If Column &gt;= 1 Then
lMaxCol = .Count - 1
If Column &gt; lMaxCol + 1 Then lCol = lMaxCol Else lCol = Column - 1
End If
End If
If lCol &gt;= 0 Then .setCurrentColumnPosition(lCol)
End With
bGoTo = True
Finally:
GoToCell = bGoTo
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet.GoToCell
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;CloseDatasheet&quot; _
, &quot;CreateMenu&quot; _
, &quot;GetText&quot; _
, &quot;GetValue&quot; _
, &quot;GoToCell&quot; _
, &quot;RemoveMenu&quot; _
)
End Function &apos; SFDatabases.SF_Datasheet.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Model class as an array
Properties = Array( _
&quot;ColumnHeaders&quot; _
, &quot;CurrentColumn&quot; _
, &quot;CurrentRow&quot; _
, &quot;DatabaseFileName&quot; _
, &quot;Filter&quot; _
, &quot;LastRow&quot; _
, &quot;OrderBy&quot; _
, &quot;ParentDatabase&quot; _
, &quot;Source&quot; _
, &quot;SourceType&quot; _
, &quot;XComponent&quot; _
, &quot;XControlModel&quot; _
, &quot;XTabControllerModel&quot; _
)
End Function &apos; SFDatabases.SF_Datasheet.Properties
REM -----------------------------------------------------------------------------
Public Function RemoveMenu(Optional ByVal MenuHeader 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; 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;SFDatabases.Datasheet.RemoveMenu&quot;
Const cstSubArgs = &quot;MenuHeader&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() Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
End If
Try:
Set oLayout = _Component.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; SFDatabases.SF_Datasheet.RemoveMenu
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.Datasheet.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; SFDatabases.SF_Datasheet.SetProperty
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Public Sub _Initialize()
&apos;&apos;&apos; Called immediately after instance creation to complete the initial values
&apos;&apos;&apos; An eventual error must be trapped in the calling routine to cancel the instance creation
Dim iType As Integer &apos; One of the com.sun.star.sdb.CommandType constants
Dim oColumn As Object &apos; A single column
Dim oColumnDescriptor As Object &apos; A single column descriptor
Dim FSO As Object : Set FSO = ScriptForge.SF_FileSystem
Dim i As Long
Try:
If IsNull([_Parent]) Then _ParentType = &quot;&quot; Else _ParentType = [_Parent].ObjectType
With _Component
&apos; The existence of _Component.Selection must be checked upfront
_Command = ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;Command&quot;)
iType = ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;CommandType&quot;)
Select Case iType
Case com.sun.star.sdb.CommandType.TABLE : _SheetType = &quot;TABLE&quot;
Case com.sun.star.sdb.CommandType.QUERY : _SheetType = &quot;QUERY&quot;
Case com.sun.star.sdb.CommandType.COMMAND : _SheetType = &quot;SQL&quot;
End Select
_BaseFileName = ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;DataSourceName&quot;)
_DirectSql = Not ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;EscapeProcessing&quot;)
&apos; Useful UNO objects
Set _Frame = .Frame
Set _ControlView = .CurrentControl
Set _TabControllerModel = .com_sun_star_awt_XTabController_getModel()
Set _ControlModel = _ControlView.getModel()
End With
&apos; Retrieve the parent database instance
With _TabControllerModel
Select Case _ParentType
Case &quot;BASE&quot;
Set _ParentDatabase = [_Parent].GetDatabase(.User, .Password)
Set _ParentBase = [_Parent]
Case &quot;DATABASE&quot;
Set _ParentDatabase = [_Parent]
Set _ParentBase = Nothing
Case &quot;&quot; &apos; Derive the DATABASE instance from what can be found in the Component
Set _ParentDatabase = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Database&quot; _
, FSO._ConvertFromUrl(_BaseFileName), , , .User, .Password)
_ParentType = &quot;DATABASE&quot;
Set _ParentBase = Nothing
End Select
&apos; Load column headers
_ColumnHeaders = .getColumns().getElementNames()
End With
Finally:
Exit Sub
End Sub &apos; SFDatabases.SF_Datasheet._Initialize
REM -----------------------------------------------------------------------------
Private Function _IsStillAlive(Optional ByVal pbError As Boolean) As Boolean
&apos;&apos;&apos; Returns True if the datasheet 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; pbError: if True (default), raise a fatal error
Dim bAlive As Boolean &apos; Return value
Dim sName As String &apos; Used in error message
On Local Error GoTo Catch &apos; Anticipate DisposedException errors or alike
If IsMissing(pbError) Then pbError = True
Try:
&apos; Check existence of datasheet
bAlive = Not IsNull(_Component.ComponentWindow)
Finally:
If pbError And Not bAlive Then
sName = _Command
Dispose()
If pbError Then ScriptForge.SF_Exception.RaiseFatal(DOCUMENTDEADERROR, sName)
End If
_IsStillAlive = bAlive
Exit Function
Catch:
bAlive = False
On Error GoTo 0
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet._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
Dim lRow As Long &apos; Actual row number
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;
cstThisSub = &quot;SFDatabases.Datasheet.get&quot; &amp; psProperty
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsStillAlive(False) Then GoTo Finally
Select Case psProperty
Case &quot;ColumnHeaders&quot;
_PropertyGet = _ColumnHeaders
Case &quot;CurrentColumn&quot;
_PropertyGet = _ColumnHeaders(_ControlView.getCurrentColumnPosition())
Case &quot;CurrentRow&quot;
_PropertyGet = _TabControllerModel.Row
Case &quot;DatabaseFileName&quot;
_PropertyGet = ScriptForge.SF_FileSystem._ConvertFromUrl(_BaseFileName)
Case &quot;Filter&quot;
_PropertyGet = _TabControllerModel.Filter
Case &quot;LastRow&quot;
With _TabControllerModel
If .IsRowCountFinal Then
_PropertyGet = .RowCount
Else
lRow = .Row
If lRow &gt; 0 Then
.last()
_PropertyGet = .RowCount
.absolute(lRow)
Else
_PropertyGet = 0
End If
End If
End With
Case &quot;OrderBy&quot;
_PropertyGet = _TabControllerModel.Order
Case &quot;ParentDatabase&quot;
Set _PropertyGet = _ParentDatabase
Case &quot;Source&quot;
_PropertyGet = _Command
Case &quot;SourceType&quot;
_PropertyGet = _SheetType
Case &quot;XComponent&quot;
Set _PropertyGet = _Component
Case &quot;XControlModel&quot;
Set _PropertyGet = _ControlModel
Case &quot;XTabControllerModel&quot;
Set _PropertyGet = _TabControllerModel
Case Else
_PropertyGet = Null
End Select
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet._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 cstThisSub As String
Const cstSubArgs = &quot;Value&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bSet = False
cstThisSub = &quot;SFDatabases.Datasheet.set&quot; &amp; psProperty
ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsStillAlive() Then GoTo Finally
bSet = True
Select Case UCase(psProperty)
Case UCase(&quot;Filter&quot;)
If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Filter&quot;, V_STRING) Then GoTo Finally
With _TabControllerModel
If Len(pvValue) &gt; 0 Then .Filter = _ParentDatabase._ReplaceSquareBrackets(pvValue) Else .Filter = &quot;&quot;
.ApplyFilter = ( Len(pvValue) &gt; 0 )
.reload()
End With
Case UCase(&quot;OrderBy&quot;)
If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;OrderBy&quot;, V_STRING) Then GoTo Finally
With _TabControllerModel
If Len(pvValue) &gt; 0 Then .Order = _ParentDatabase._ReplaceSquareBrackets(pvValue) Else .Order = &quot;&quot;
.reload()
End With
Case Else
bSet = False
End Select
Finally:
_PropertySet = bSet
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Datasheet._PropertySet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the Datasheet instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[DATASHEET]: tablename,base file url&quot;
_Repr = &quot;[DATASHEET]: &quot; &amp; _Command &amp; &quot;,&quot; &amp; _BaseFileName
End Function &apos; SFDatabases.SF_Datasheet._Repr
REM ============================================ END OF SFDATABASES.SF_DATASHEET
</script:module>

View File

@@ -0,0 +1,270 @@
<?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;)
.RegisterService(&quot;Datasheet&quot;, &quot;SFDatabases.SF_Register._NewDatasheet&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;&apos;&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;&apos;&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 -----------------------------------------------------------------------------
Public Function _NewDatasheet(Optional ByVal pvArgs As Variant) As Object
&apos; Optional ByRef poComponent As Object _
&apos; , Optional ByRef poParent As Object _
&apos; ) As Object
&apos;&apos;&apos; Create a new instance of the SF_Datasheet class
&apos;&apos;&apos; Called from
&apos;&apos;&apos; base.Datasheets()
&apos;&apos;&apos; base.OpenTable()
&apos;&apos;&apos; base.OpenQuery()
&apos;&apos;&apos; database.OpenTable()
&apos;&apos;&apos; database.OpenQuery()
&apos;&apos;&apos; database.OpenSql()
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Component: the component of the new datasheet
&apos;&apos;&apos; com.sun.star.lang.XComponent - org.openoffice.comp.dbu.ODatasourceBrowser
&apos;&apos;&apos; Parent: the parent SF_Database or SF_Base instance having produced the new datasheet
&apos;&apos;&apos; When absent, the SF_Database instance will be derived from the component
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The instance or Nothing
Dim oDatasheet As Object &apos; Return value
Dim oParent As Object &apos; The parent SF_Database or SF_Base instance having produced the new datasheet
Dim oComponent As Object &apos; The component of the new datasheet
Dim oWindow As Object &apos; ui.Window user-defined type
Dim oUi As Object : Set oUi = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.UI&quot;)
Const TABLEDATA = &quot;TableData&quot;
Const QUERYDATA = &quot;QueryData&quot;
Const SQLDATA = &quot;SqlData&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Set oDatasheet = Nothing
Check:
&apos; Get, check and assign arguments
If Not IsArray(pvArgs) Then GoTo Catch
If UBound(pvArgs) &gt;= 0 Then
Set oComponent = pvArgs(0)
End If
If UBound(pvArgs) = 0 Then
Set oParent = Nothing
ElseIf UBound(pvArgs) = 1 Then
Set oParent = pvArgs(1)
Else
GoTo Catch
End If
&apos; Check the validity of the proposed window: is it really a datasheet ? Otherwise, do nothing
If IsNull(oComponent) Then GoTo Catch
Set oWindow = oUi._IdentifyWindow(oComponent)
With oWindow
If .DocumentType &lt;&gt; TABLEDATA And .DocumentType &lt;&gt; QUERYDATA And .DocumentType &lt;&gt; SQLDATA Then GoTo Catch
End With
If IsEmpty(oComponent.Selection) Then GoTo Catch
Try:
Set oDatasheet = New SF_Datasheet
With oDatasheet
Set .[Me] = oDatasheet
Set .[_Parent] = oParent
Set ._Component = oComponent
&apos; Achieve the initialization
._Initialize()
End With
Finally:
Set _NewDatasheet = oDatasheet
Exit Function
Catch:
Set oDatasheet = Nothing
GoTo Finally
End Function &apos; SFDatabases.SF_Register._NewDatasheet
REM ============================================== END OF SFDATABASES.SF_REGISTER
</script:module>

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -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="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:element library:name="SF_Datasheet"/>
</library:library>