SF_Datasheet.xba 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
  3. <script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Datasheet" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
  4. REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
  5. REM === The SFDatabases library is one of the associated libraries. ===
  6. REM === Full documentation is available on https://help.libreoffice.org/ ===
  7. REM =======================================================================================================================
  8. Option Compatible
  9. Option ClassModule
  10. Option Explicit
  11. &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
  12. &apos;&apos;&apos; SF_Datasheet
  13. &apos;&apos;&apos; ============
  14. &apos;&apos;&apos; A datasheet is the visual representation of tabular data produced by a database.
  15. &apos;&apos;&apos; In the user interface of LibreOffice it is the result of the opening of
  16. &apos;&apos;&apos; a table or a query. In this case the concerned Base document must be open.
  17. &apos;&apos;&apos;
  18. &apos;&apos;&apos; In the context of ScriptForge, a datasheet may be opened automatically by script code :
  19. &apos;&apos;&apos; - either by reproducing the behaviour of the user interface
  20. &apos;&apos;&apos; - or at any moment. In this case the Base document may or may not be opened.
  21. &apos;&apos;&apos; Additionally, any SELECT SQL statement may trigger the datasheet display.
  22. &apos;&apos;&apos;
  23. &apos;&apos;&apos; The proposed API allows for either datasheets (opened manually of by code) in particular
  24. &apos;&apos;&apos; to know which cell is selected and its content.
  25. &apos;&apos;&apos;
  26. &apos;&apos;&apos; Service invocation:
  27. &apos;&apos;&apos; 1) From an open Base document
  28. &apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
  29. &apos;&apos;&apos; Set oBase = ui.getDocument(&quot;/home/user/Documents/myDb.odb&quot;)
  30. &apos;&apos;&apos; Set oSheet1 = oBase.OpenTable(&quot;Customers&quot;) &apos; or OpenQuery(...)
  31. &apos;&apos;&apos; Set oSheet2 = oBase.Datasheets(&quot;Products&quot;) &apos; when the datasheet has been opened manually
  32. &apos;&apos;&apos; 2) Independently from a Base document
  33. &apos;&apos;&apos; Set oDatabase = CreateScriptService(&quot;Database&quot;, &quot;/home/user/Documents/myDb.odb&quot;)
  34. &apos;&apos;&apos; Set oSheet = oDatabase.OpenTable(&quot;Customers&quot;)
  35. &apos;&apos;&apos;
  36. &apos;&apos;&apos; Detailed user documentation:
  37. &apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_datasheet.html?DbPAR=BASIC
  38. &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
  39. REM ================================================================== EXCEPTIONS
  40. Private Const DOCUMENTDEADERROR = &quot;DOCUMENTDEADERROR&quot;
  41. REM ============================================================= PRIVATE MEMBERS
  42. Private [Me] As Object
  43. Private [_Parent] As Object &apos; Base instance when opened from a Base document by code
  44. &apos; or Database instance when opened without Base document
  45. Private ObjectType As String &apos; Must be DATASHEET
  46. Private ServiceName As String
  47. Private _Component As Object &apos; com.sun.star.lang.XComponent - org.openoffice.comp.dbu.ODatasourceBrowser
  48. Private _Frame As Object &apos; com.sun.star.frame.XFrame
  49. Private _ParentBase As Object &apos; The parent SF_Base instance (may be void)
  50. Private _ParentDatabase As Object &apos; The parent SF_Database instance (must not be void)
  51. Private _SheetType As String &apos; TABLE, QUERY or SQL
  52. Private _ParentType As String &apos; BASE or DATABASE
  53. Private _BaseFileName As String &apos; URL format of parent Base file
  54. Private _Command As String &apos; Table name, query name or SQL statement
  55. Private _DirectSql As Boolean &apos; When True, SQL processed by RDBMS
  56. Private _TabControllerModel As Object &apos; com.sun.star.awt.XTabControllerModel - com.sun.star.comp.forms.ODatabaseForm
  57. Private _ControlModel As Object &apos; com.sun.star.awt.XControlModel - com.sun.star.form.OGridControlModel
  58. Private _ControlView As Object &apos; com.sun.star.awt.XControl - org.openoffice.comp.dbu.ODatasourceBrowser
  59. Private _ColumnHeaders As Variant &apos; List of column headers as an array of strings
  60. REM ============================================================ MODULE CONSTANTS
  61. REM ====================================================== CONSTRUCTOR/DESTRUCTOR
  62. REM -----------------------------------------------------------------------------
  63. Private Sub Class_Initialize()
  64. Set [Me] = Nothing
  65. Set [_Parent] = Nothing
  66. ObjectType = &quot;DATASHEET&quot;
  67. ServiceName = &quot;SFDatabases.Datasheet&quot;
  68. Set _Component = Nothing
  69. Set _Frame = Nothing
  70. Set _ParentBase = Nothing
  71. Set _ParentDatabase = Nothing
  72. _SheetType = &quot;&quot;
  73. _ParentType = &quot;&quot;
  74. _BaseFileName = &quot;&quot;
  75. _Command = &quot;&quot;
  76. _DirectSql = False
  77. Set _TabControllerModel = Nothing
  78. Set _ControlModel = Nothing
  79. Set _ControlView = Nothing
  80. _ColumnHeaders = Array()
  81. End Sub &apos; SFDatabases.SF_Datasheet Constructor
  82. REM -----------------------------------------------------------------------------
  83. Private Sub Class_Terminate()
  84. Call Class_Initialize()
  85. End Sub &apos; SFDatabases.SF_Datasheet Destructor
  86. REM -----------------------------------------------------------------------------
  87. Public Function Dispose() As Variant
  88. Call Class_Terminate()
  89. Set Dispose = Nothing
  90. End Function &apos; SFDatabases.SF_Datasheet Explicit Destructor
  91. REM ================================================================== PROPERTIES
  92. REM -----------------------------------------------------------------------------
  93. Property Get ColumnHeaders() As Variant
  94. &apos;&apos;&apos; Returns the list of column headers of the datasheet as an array of strings
  95. ColumnHeaders = _PropertyGet(&quot;ColumnHeaders&quot;)
  96. End Property &apos; SFDatabases.SF_Datasheet.ColumnHeaders
  97. REM -----------------------------------------------------------------------------
  98. Property Get CurrentColumn() As String
  99. &apos;&apos;&apos; Returns the currently selected column by its name
  100. CurrentColumn = _PropertyGet(&quot;CurrentColumn&quot;)
  101. End Property &apos; SFDatabases.SF_Datasheet.CurrentColumn
  102. REM -----------------------------------------------------------------------------
  103. Property Get CurrentRow() As Long
  104. &apos;&apos;&apos; Returns the currently selected row by its number &gt;= 1
  105. CurrentRow = _PropertyGet(&quot;CurrentRow&quot;)
  106. End Property &apos; SFDatabases.SF_Datasheet.CurrentRow
  107. REM -----------------------------------------------------------------------------
  108. Property Get DatabaseFileName() As String
  109. &apos;&apos;&apos; Returns the file name of the Base file in FSO.FileNaming format
  110. DatabaseFileName = _PropertyGet(&quot;DatabaseFileName&quot;)
  111. End Property &apos; SFDatabases.SF_Datasheet.DatabaseFileName
  112. REM -----------------------------------------------------------------------------
  113. Property Get Filter() As Variant
  114. &apos;&apos;&apos; The Filter is a SQL WHERE clause without the WHERE keyword
  115. Filter = _PropertyGet(&quot;Filter&quot;)
  116. End Property &apos; SFDatabases.SF_Datasheet.Filter (get)
  117. REM -----------------------------------------------------------------------------
  118. Property Let Filter(Optional ByVal pvFilter As Variant)
  119. &apos;&apos;&apos; Set the updatable property Filter
  120. &apos;&apos;&apos; Table and field names may be surrounded by square brackets
  121. &apos;&apos;&apos; When the argument is the zero-length string, the actual filter is removed
  122. _PropertySet(&quot;Filter&quot;, pvFilter)
  123. End Property &apos; SFDatabases.SF_Datasheet.Filter (let)
  124. REM -----------------------------------------------------------------------------
  125. Property Get LastRow() As Long
  126. &apos;&apos;&apos; Returns the total number of rows
  127. &apos;&apos;&apos; The process may imply to move the cursor to the last available row.
  128. &apos;&apos;&apos; Afterwards the cursor is reset to the current row.
  129. LastRow = _PropertyGet(&quot;LastRow&quot;)
  130. End Property &apos; SFDatabases.SF_Datasheet.LastRow
  131. REM -----------------------------------------------------------------------------
  132. Property Get OrderBy() As Variant
  133. &apos;&apos;&apos; The Order is a SQL ORDER BY clause without the ORDER BY keywords
  134. OrderBy = _PropertyGet(&quot;OrderBy&quot;)
  135. End Property &apos; SFDocuments.SF_Form.OrderBy (get)
  136. REM -----------------------------------------------------------------------------
  137. Property Let OrderBy(Optional ByVal pvOrderBy As Variant)
  138. &apos;&apos;&apos; Set the updatable property OrderBy
  139. &apos;&apos;&apos; Table and field names may be surrounded by square brackets
  140. &apos;&apos;&apos; When the argument is the zero-length string, the actual sort is removed
  141. _PropertySet(&quot;OrderBy&quot;, pvOrderBy)
  142. End Property &apos; SFDocuments.SF_Form.OrderBy (let)
  143. REM -----------------------------------------------------------------------------
  144. Property Get ParentDatabase() As Object
  145. &apos;&apos;&apos; Returns the database instance to which the datasheet belongs
  146. Set ParentDatabase = _PropertyGet(&quot;ParentDatabase&quot;)
  147. End Property &apos; SFDatabases.SF_Datasheet.ParentDatabase
  148. REM -----------------------------------------------------------------------------
  149. Property Get Source() As String
  150. &apos;&apos;&apos; Returns the source of the data: table name, query name or sql statement
  151. Source = _PropertyGet(&quot;Source&quot;)
  152. End Property &apos; SFDatabases.SF_Datasheet.Source
  153. REM -----------------------------------------------------------------------------
  154. Property Get SourceType() As String
  155. &apos;&apos;&apos; Returns thetype of source of the data: TABLE, QUERY or SQL
  156. SourceType = _PropertyGet(&quot;SourceType&quot;)
  157. End Property &apos; SFDatabases.SF_Datasheet.SourceType
  158. REM -----------------------------------------------------------------------------
  159. Property Get XComponent() As Object
  160. &apos;&apos;&apos; Returns the com.sun.star.lang.XComponent UNO object representing the datasheet
  161. XComponent = _PropertyGet(&quot;XComponent&quot;)
  162. End Property &apos; SFDocuments.SF_Document.XComponent
  163. REM -----------------------------------------------------------------------------
  164. Property Get XControlModel() As Object
  165. &apos;&apos;&apos; Returns the com.sun.star.lang.XControl UNO object representing the datasheet
  166. XControlModel = _PropertyGet(&quot;XControlModel&quot;)
  167. End Property &apos; SFDocuments.SF_Document.XControlModel
  168. REM -----------------------------------------------------------------------------
  169. Property Get XTabControllerModel() As Object
  170. &apos;&apos;&apos; Returns the com.sun.star.lang.XTabControllerModel UNO object representing the datasheet
  171. XTabControllerModel = _PropertyGet(&quot;XTabControllerModel&quot;)
  172. End Property &apos; SFDocuments.SF_Document.XTabControllerModel
  173. REM ===================================================================== METHODS
  174. REM -----------------------------------------------------------------------------
  175. Public Sub Activate()
  176. &apos;&apos;&apos; Make the actual datasheet active
  177. &apos;&apos;&apos; Args:
  178. &apos;&apos;&apos; Returns:
  179. &apos;&apos;&apos; Examples:
  180. &apos;&apos;&apos; oSheet.Activate()
  181. Dim oContainer As Object &apos; com.sun.star.awt.XWindow
  182. Const cstThisSub = &quot;SFDatabases.Datasheet.Activate&quot;
  183. Const cstSubArgs = &quot;&quot;
  184. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  185. Check:
  186. SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  187. If Not _IsStillAlive() Then GoTo Finally
  188. Try:
  189. Set oContainer = _Component.Frame.ContainerWindow
  190. With oContainer
  191. If .isVisible() = False Then .setVisible(True)
  192. .IsMinimized = False
  193. .setFocus()
  194. .toFront() &apos; Force window change in Linux
  195. Wait 1 &apos; Bypass desynchro issue in Linux
  196. End With
  197. Finally:
  198. SF_Utils._ExitFunction(cstThisSub)
  199. Exit Sub
  200. Catch:
  201. GoTo Finally
  202. End Sub &apos; SFDatabases.SF_Datasheet.Activate
  203. REM -----------------------------------------------------------------------------
  204. Public Function CloseDatasheet() As Boolean
  205. &apos;&apos;&apos; Close the actual datasheet
  206. &apos;&apos;&apos; Args:
  207. &apos;&apos;&apos; Returns:
  208. &apos;&apos;&apos; True when successful
  209. &apos;&apos;&apos; Examples:
  210. &apos;&apos;&apos; oSheet.CloseDatasheet()
  211. Dim bClose As Boolean &apos; Return value
  212. Const cstThisSub = &quot;SFDatabases.Datasheet.CloseDatasheet&quot;
  213. Const cstSubArgs = &quot;&quot;
  214. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  215. bClose = False
  216. Check:
  217. SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  218. If Not _IsStillAlive() Then GoTo Finally
  219. Try:
  220. _TabControllerModel.close()
  221. _Frame.close(True)
  222. _Frame.dispose()
  223. Dispose()
  224. bClose = True
  225. Finally:
  226. CloseDatasheet = bClose
  227. SF_Utils._ExitFunction(cstThisSub)
  228. Exit Function
  229. Catch:
  230. GoTo Finally
  231. End Function &apos; SFDatabases.SF_Datasheet.CloseDatasheet
  232. REM -----------------------------------------------------------------------------
  233. Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
  234. , Optional ByVal Before As Variant _
  235. , Optional ByVal SubmenuChar As Variant _
  236. ) As Object
  237. &apos;&apos;&apos; Create a new menu entry in the datasheet&apos;s menubar
  238. &apos;&apos;&apos; The menu is not intended to be saved neither in the LibreOffice global environment, nor elsewhere
  239. &apos;&apos;&apos; The method returns a SFWidgets.Menu instance. Its methods let define the menu further.
  240. &apos;&apos;&apos; Args:
  241. &apos;&apos;&apos; MenuHeader: the name/header of the menu
  242. &apos;&apos;&apos; Before: the place where to put the new menu on the menubar (string or number &gt;= 1)
  243. &apos;&apos;&apos; When not found =&gt; last position
  244. &apos;&apos;&apos; SubmenuChar: the delimiter used in menu trees. Default = &quot;&gt;&quot;
  245. &apos;&apos;&apos; Returns:
  246. &apos;&apos;&apos; A SFWidgets.Menu instance or Nothing
  247. &apos;&apos;&apos; Examples:
  248. &apos;&apos;&apos; Dim oMenu As Object
  249. &apos;&apos;&apos; Set oMenu = oDoc.CreateMenu(&quot;My menu&quot;, Before := &quot;Styles&quot;)
  250. &apos;&apos;&apos; With oMenu
  251. &apos;&apos;&apos; .AddItem(&quot;Item 1&quot;, Command := &quot;.uno:About&quot;)
  252. &apos;&apos;&apos; &apos;...
  253. &apos;&apos;&apos; .Dispose() &apos; When definition is complete, the menu instance may be disposed
  254. &apos;&apos;&apos; End With
  255. &apos;&apos;&apos; &apos; ...
  256. Dim oMenu As Object &apos; return value
  257. Const cstThisSub = &quot;SFDatabases.Datasheet.CreateMenu&quot;
  258. Const cstSubArgs = &quot;MenuHeader, [Before=&quot;&quot;&quot;&quot;], [SubmenuChar=&quot;&quot;&gt;&quot;&quot;]&quot;
  259. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  260. Set oMenu = Nothing
  261. Check:
  262. If IsMissing(Before) Or IsEmpty(Before) Then Before = &quot;&quot;
  263. If IsMissing(SubmenuChar) Or IsEmpty(SubmenuChar) Then SubmenuChar = &quot;&quot;
  264. If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  265. If Not _IsStillAlive() Then GoTo Finally
  266. If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
  267. If Not ScriptForge.SF_Utils._Validate(Before, &quot;Before&quot;, V_STRING) Then GoTo Finally
  268. If Not ScriptForge.SF_Utils._Validate(SubmenuChar, &quot;SubmenuChar&quot;, V_STRING) Then GoTo Finally
  269. End If
  270. Try:
  271. Set oMenu = ScriptForge.SF_Services.CreateScriptService(&quot;SFWidgets.Menu&quot;, _Component, MenuHeader, Before, SubmenuChar)
  272. Finally:
  273. Set CreateMenu = oMenu
  274. ScriptForge.SF_Utils._ExitFunction(cstThisSub)
  275. Exit Function
  276. Catch:
  277. GoTo Finally
  278. End Function &apos; SFDatabases.SF_Document.CreateMenu
  279. REM -----------------------------------------------------------------------------
  280. Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
  281. &apos;&apos;&apos; Return the actual value of the given property
  282. &apos;&apos;&apos; Args:
  283. &apos;&apos;&apos; PropertyName: the name of the property as a string
  284. &apos;&apos;&apos; Returns:
  285. &apos;&apos;&apos; The actual value of the propRATTCerty
  286. &apos;&apos;&apos; If the property does not exist, returns Null
  287. Const cstThisSub = &quot;SFDatabases.Datasheet.GetProperty&quot;
  288. Const cstSubArgs = &quot;&quot;
  289. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  290. GetProperty = Null
  291. Check:
  292. If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  293. If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
  294. End If
  295. Try:
  296. GetProperty = _PropertyGet(PropertyName)
  297. Finally:
  298. ScriptForge.SF_Utils._ExitFunction(cstThisSub)
  299. Exit Function
  300. Catch:
  301. GoTo Finally
  302. End Function &apos; SFDatabases.SF_Datasheet.GetProperty
  303. REM -----------------------------------------------------------------------------
  304. Public Function GetText(Optional ByVal Column As Variant) As String
  305. &apos;&apos;&apos; Get the text in the given column of the current row.
  306. &apos;&apos;&apos; Args:
  307. &apos;&apos;&apos; Column: the name of the column as a string or its position (&gt;= 1). Default = the current column
  308. &apos;&apos;&apos; If the argument exceeds the number of columns, the last column is selected.
  309. &apos;&apos;&apos; Returns:
  310. &apos;&apos;&apos; The text in the cell as a string as how it is displayed
  311. &apos;&apos;&apos; Note that the position of the cursor is left unchanged.
  312. &apos;&apos;&apos; Examples:
  313. &apos;&apos;&apos; oSheet.GetText(&quot;ShipCity&quot;)) &apos; Extract the text on the current row from the column &quot;ShipCity&quot;
  314. Dim sText As String &apos; Return Text
  315. Dim lCol As Long &apos; Numeric index of Column in lists of columns
  316. Dim lMaxCol As Long &apos; Index of last column
  317. Const cstThisSub = &quot;SFDatabases.Datasheet.GetText&quot;
  318. Const cstSubArgs = &quot;[Column=0]&quot;
  319. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  320. sText = &quot;&quot;
  321. Check:
  322. If IsMissing(Column) Or IsEmpty(Column) Then Column = 0
  323. If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  324. If Not _IsStillAlive() Then GoTo Finally
  325. If VarType(Column) &lt;&gt; V_STRING Then
  326. If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
  327. Else
  328. If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, V_STRING, _ColumnHeaders) Then GoTo Catch
  329. End If
  330. End If
  331. Try:
  332. &apos; Position the column - The index to be passed starts at 0
  333. With _ControlView
  334. If VarType(Column) = V_STRING Then
  335. lCol = ScriptForge.SF_Array.IndexOf(_ColumnHeaders, Column, CaseSensitive := False)
  336. Else
  337. lCol = -1
  338. If Column &gt;= 1 Then
  339. lMaxCol = .Count - 1
  340. If Column &gt; lMaxCol + 1 Then lCol = lMaxCol Else lCol = Column - 1
  341. End If
  342. End If
  343. If lCol &gt;= 0 Then sText = .getByIndex(lCol).Text
  344. End With
  345. Finally:
  346. GetText = sText
  347. SF_Utils._ExitFunction(cstThisSub)
  348. Exit Function
  349. Catch:
  350. GoTo Finally
  351. End Function &apos; SFDatabases.SF_Datasheet.GetText
  352. REM -----------------------------------------------------------------------------
  353. Public Function GetValue(Optional ByVal Column As Variant) As Variant
  354. &apos;&apos;&apos; Get the value in the given column of the current row.
  355. &apos;&apos;&apos; Args:
  356. &apos;&apos;&apos; Column: the name of the column as a string or its position (&gt;= 1). Default = the current column
  357. &apos;&apos;&apos; If the argument exceeds the number of columns, the last column is selected.
  358. &apos;&apos;&apos; Returns:
  359. &apos;&apos;&apos; The value in the cell as a valid Basic type
  360. &apos;&apos;&apos; Typical types are: STRING, INTEGER, LONG, FLOAT, DOUBLE, DATE, NULL
  361. &apos;&apos;&apos; Binary types are returned as a LONG giving their length, not their content
  362. &apos;&apos;&apos; An EMPTY return value means that the value could not be retrieved.
  363. &apos;&apos;&apos; Note that the position of the cursor is left unchanged.
  364. &apos;&apos;&apos; Examples:
  365. &apos;&apos;&apos; oSheet.GetValue(&quot;ShipCity&quot;)) &apos; Extract the value on the current row from the column &quot;ShipCity&quot;
  366. Dim vValue As Variant &apos; Return value
  367. Dim lCol As Long &apos; Numeric index of Column in lists of columns
  368. Dim lMaxCol As Long &apos; Index of last column
  369. Const cstThisSub = &quot;SFDatabases.Datasheet.GetValue&quot;
  370. Const cstSubArgs = &quot;[Column=0]&quot;
  371. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  372. vValue = Empty
  373. Check:
  374. If IsMissing(Column) Or IsEmpty(Column) Then Column = 0
  375. If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  376. If Not _IsStillAlive() Then GoTo Finally
  377. If VarType(Column) &lt;&gt; V_STRING Then
  378. If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
  379. Else
  380. If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, V_STRING, _ColumnHeaders) Then GoTo Catch
  381. End If
  382. End If
  383. Try:
  384. &apos; Position the column - The index to be passed starts at 1
  385. If VarType(Column) = V_STRING Then
  386. lCol = ScriptForge.SF_Array.IndexOf(_ColumnHeaders, Column, CaseSensitive := False) + 1
  387. Else
  388. lCol = 0
  389. If Column &gt;= 1 Then
  390. lMaxCol = _ControlView.Count
  391. If Column &gt; lMaxCol Then lCol = lMaxCol Else lCol = Column
  392. End If
  393. End If
  394. &apos; The _TabControllerModel acts exactly as a result set, from which the generic _GetColumnValue can extract the searched value
  395. If lCol &gt;= 1 Then vValue = _ParentDatabase._GetColumnValue(_TabControllerModel, lCol)
  396. Finally:
  397. GetValue = vValue
  398. SF_Utils._ExitFunction(cstThisSub)
  399. Exit Function
  400. Catch:
  401. GoTo Finally
  402. End Function &apos; SFDatabases.SF_Datasheet.GetValue
  403. REM -----------------------------------------------------------------------------
  404. Public Function GoToCell(Optional ByVal Row As Variant _
  405. , Optional ByVal Column As Variant _
  406. ) As Boolean
  407. &apos;&apos;&apos; Set the cursor on the given row and the given column.
  408. &apos;&apos;&apos; If the requested row exceeds the number of available rows, the cursor is set on the last row.
  409. &apos;&apos;&apos; If the requested column exceeds the number of available columns, the selected column is the last one.
  410. &apos;&apos;&apos; Args:
  411. &apos;&apos;&apos; Row: the row number (&gt;= 1) as a numeric value. Default= no change
  412. &apos;&apos;&apos; Column: the name of the column as a string or its position (&gt;= 1). Default = the current column
  413. &apos;&apos;&apos; Returns:
  414. &apos;&apos;&apos; True when successful
  415. &apos;&apos;&apos; Examples:
  416. &apos;&apos;&apos; oSheet.GoToCell(1000000, &quot;ShipCity&quot;)) &apos; Set the cursor on he last row, column &quot;ShipCity&quot;
  417. Dim bGoTo As Boolean &apos; Return value
  418. Dim lCol As Long &apos; Numeric index of Column in list of columns
  419. Dim lMaxCol As Long &apos; Index of last column
  420. Const cstThisSub = &quot;SFDatabases.Datasheet.GoToCell&quot;
  421. Const cstSubArgs = &quot;[Row=0], [Column=0]&quot;
  422. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  423. bGoTo = False
  424. Check:
  425. If IsMissing(Row) Or IsEmpty(Row) Then Row = 0
  426. If IsMissing(Column) Or IsEmpty(Column) Then Column = 0
  427. If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  428. If Not _IsStillAlive() Then GoTo Finally
  429. If Not ScriptForge.SF_Utils._Validate(Row, &quot;Row&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
  430. If VarType(Column) &lt;&gt; V_STRING Then
  431. If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
  432. Else
  433. If Not ScriptForge.SF_Utils._Validate(Column, &quot;Column&quot;, V_STRING, _ColumnHeaders) Then GoTo Catch
  434. End If
  435. End If
  436. Try:
  437. &apos; Position the row
  438. With _TabControllerModel
  439. If Row &lt;= 0 Then Row = .Row Else .absolute(Row)
  440. &apos; Does Row exceed the total number of rows ?
  441. If .IsRowCountFinal And Row &gt; .RowCount Then .absolute(.RowCount)
  442. End With
  443. &apos; Position the column
  444. With _ControlView
  445. If VarType(Column) = V_STRING Then
  446. lCol = ScriptForge.SF_Array.IndexOf(_ColumnHeaders, Column, CaseSensitive := False)
  447. Else
  448. lCol = -1
  449. If Column &gt;= 1 Then
  450. lMaxCol = .Count - 1
  451. If Column &gt; lMaxCol + 1 Then lCol = lMaxCol Else lCol = Column - 1
  452. End If
  453. End If
  454. If lCol &gt;= 0 Then .setCurrentColumnPosition(lCol)
  455. End With
  456. bGoTo = True
  457. Finally:
  458. GoToCell = bGoTo
  459. SF_Utils._ExitFunction(cstThisSub)
  460. Exit Function
  461. Catch:
  462. GoTo Finally
  463. End Function &apos; SFDatabases.SF_Datasheet.GoToCell
  464. REM -----------------------------------------------------------------------------
  465. Public Function Methods() As Variant
  466. &apos;&apos;&apos; Return the list of public methods of the Model service as an array
  467. Methods = Array( _
  468. &quot;Activate&quot; _
  469. , &quot;CloseDatasheet&quot; _
  470. , &quot;CreateMenu&quot; _
  471. , &quot;GetText&quot; _
  472. , &quot;GetValue&quot; _
  473. , &quot;GoToCell&quot; _
  474. , &quot;RemoveMenu&quot; _
  475. )
  476. End Function &apos; SFDatabases.SF_Datasheet.Methods
  477. REM -----------------------------------------------------------------------------
  478. Public Function Properties() As Variant
  479. &apos;&apos;&apos; Return the list or properties of the Model class as an array
  480. Properties = Array( _
  481. &quot;ColumnHeaders&quot; _
  482. , &quot;CurrentColumn&quot; _
  483. , &quot;CurrentRow&quot; _
  484. , &quot;DatabaseFileName&quot; _
  485. , &quot;Filter&quot; _
  486. , &quot;LastRow&quot; _
  487. , &quot;OrderBy&quot; _
  488. , &quot;ParentDatabase&quot; _
  489. , &quot;Source&quot; _
  490. , &quot;SourceType&quot; _
  491. , &quot;XComponent&quot; _
  492. , &quot;XControlModel&quot; _
  493. , &quot;XTabControllerModel&quot; _
  494. )
  495. End Function &apos; SFDatabases.SF_Datasheet.Properties
  496. REM -----------------------------------------------------------------------------
  497. Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
  498. &apos;&apos;&apos; Remove a menu entry in the document&apos;s menubar
  499. &apos;&apos;&apos; The removal is not intended to be saved neither in the LibreOffice global environment, nor in the document
  500. &apos;&apos;&apos; Args:
  501. &apos;&apos;&apos; MenuHeader: the name/header of the menu, without tilde &quot;~&quot;, as a case-sensitive string
  502. &apos;&apos;&apos; Returns:
  503. &apos;&apos;&apos; True when successful
  504. &apos;&apos;&apos; Examples:
  505. &apos;&apos;&apos; oDoc.RemoveMenu(&quot;File&quot;)
  506. &apos;&apos;&apos; &apos; ...
  507. Dim bRemove As Boolean &apos; Return value
  508. Dim oLayout As Object &apos; com.sun.star.comp.framework.LayoutManager
  509. Dim oMenuBar As Object &apos; com.sun.star.awt.XMenuBar or stardiv.Toolkit.VCLXMenuBar
  510. Dim sName As String &apos; Menu name
  511. Dim iMenuId As Integer &apos; Menu identifier
  512. Dim iMenuPosition As Integer &apos; Menu position &gt;= 0
  513. Dim i As Integer
  514. Const cstTilde = &quot;~&quot;
  515. Const cstThisSub = &quot;SFDatabases.Datasheet.RemoveMenu&quot;
  516. Const cstSubArgs = &quot;MenuHeader&quot;
  517. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  518. bRemove = False
  519. Check:
  520. If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  521. If Not _IsStillAlive() Then GoTo Finally
  522. If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
  523. End If
  524. Try:
  525. Set oLayout = _Component.Frame.LayoutManager
  526. Set oMenuBar = oLayout.getElement(&quot;private:resource/menubar/menubar&quot;).XMenuBar
  527. &apos; Search the menu identifier to remove by its name, Mark its position
  528. With oMenuBar
  529. iMenuPosition = -1
  530. For i = 0 To .ItemCount - 1
  531. iMenuId = .getItemId(i)
  532. sName = Replace(.getItemText(iMenuId), cstTilde, &quot;&quot;)
  533. If MenuHeader= sName Then
  534. iMenuPosition = i
  535. Exit For
  536. End If
  537. Next i
  538. &apos; Remove the found menu item
  539. If iMenuPosition &gt;= 0 Then
  540. .removeItem(iMenuPosition, 1)
  541. bRemove = True
  542. End If
  543. End With
  544. Finally:
  545. RemoveMenu = bRemove
  546. ScriptForge.SF_Utils._ExitFunction(cstThisSub)
  547. Exit Function
  548. Catch:
  549. GoTo Finally
  550. End Function &apos; SFDatabases.SF_Datasheet.RemoveMenu
  551. REM -----------------------------------------------------------------------------
  552. Public Function SetProperty(Optional ByVal PropertyName As Variant _
  553. , Optional ByRef Value As Variant _
  554. ) As Boolean
  555. &apos;&apos;&apos; Set a new value to the given property
  556. &apos;&apos;&apos; Args:
  557. &apos;&apos;&apos; PropertyName: the name of the property as a string
  558. &apos;&apos;&apos; Value: its new value
  559. &apos;&apos;&apos; Exceptions
  560. &apos;&apos;&apos; ARGUMENTERROR The property does not exist
  561. Const cstThisSub = &quot;SFDatabases.Datasheet.SetProperty&quot;
  562. Const cstSubArgs = &quot;PropertyName, Value&quot;
  563. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  564. SetProperty = False
  565. Check:
  566. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  567. If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
  568. End If
  569. Try:
  570. SetProperty = _PropertySet(PropertyName, Value)
  571. Finally:
  572. SF_Utils._ExitFunction(cstThisSub)
  573. Exit Function
  574. Catch:
  575. GoTo Finally
  576. End Function &apos; SFDatabases.SF_Datasheet.SetProperty
  577. REM =========================================================== PRIVATE FUNCTIONS
  578. REM -----------------------------------------------------------------------------
  579. Public Sub _Initialize()
  580. &apos;&apos;&apos; Called immediately after instance creation to complete the initial values
  581. &apos;&apos;&apos; An eventual error must be trapped in the calling routine to cancel the instance creation
  582. Dim iType As Integer &apos; One of the com.sun.star.sdb.CommandType constants
  583. Dim oColumn As Object &apos; A single column
  584. Dim oColumnDescriptor As Object &apos; A single column descriptor
  585. Dim FSO As Object : Set FSO = ScriptForge.SF_FileSystem
  586. Dim i As Long
  587. Try:
  588. If IsNull([_Parent]) Then _ParentType = &quot;&quot; Else _ParentType = [_Parent].ObjectType
  589. With _Component
  590. &apos; The existence of _Component.Selection must be checked upfront
  591. _Command = ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;Command&quot;)
  592. iType = ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;CommandType&quot;)
  593. Select Case iType
  594. Case com.sun.star.sdb.CommandType.TABLE : _SheetType = &quot;TABLE&quot;
  595. Case com.sun.star.sdb.CommandType.QUERY : _SheetType = &quot;QUERY&quot;
  596. Case com.sun.star.sdb.CommandType.COMMAND : _SheetType = &quot;SQL&quot;
  597. End Select
  598. _BaseFileName = ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;DataSourceName&quot;)
  599. _DirectSql = Not ScriptForge.SF_Utils._GetPropertyValue(.Selection, &quot;EscapeProcessing&quot;)
  600. &apos; Useful UNO objects
  601. Set _Frame = .Frame
  602. Set _ControlView = .CurrentControl
  603. Set _TabControllerModel = .com_sun_star_awt_XTabController_getModel()
  604. Set _ControlModel = _ControlView.getModel()
  605. End With
  606. &apos; Retrieve the parent database instance
  607. With _TabControllerModel
  608. Select Case _ParentType
  609. Case &quot;BASE&quot;
  610. Set _ParentDatabase = [_Parent].GetDatabase(.User, .Password)
  611. Set _ParentBase = [_Parent]
  612. Case &quot;DATABASE&quot;
  613. Set _ParentDatabase = [_Parent]
  614. Set _ParentBase = Nothing
  615. Case &quot;&quot; &apos; Derive the DATABASE instance from what can be found in the Component
  616. Set _ParentDatabase = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Database&quot; _
  617. , FSO._ConvertFromUrl(_BaseFileName), , , .User, .Password)
  618. _ParentType = &quot;DATABASE&quot;
  619. Set _ParentBase = Nothing
  620. End Select
  621. &apos; Load column headers
  622. _ColumnHeaders = .getColumns().getElementNames()
  623. End With
  624. Finally:
  625. Exit Sub
  626. End Sub &apos; SFDatabases.SF_Datasheet._Initialize
  627. REM -----------------------------------------------------------------------------
  628. Private Function _IsStillAlive(Optional ByVal pbError As Boolean) As Boolean
  629. &apos;&apos;&apos; Returns True if the datasheet has not been closed manually or incidentally since the last use
  630. &apos;&apos;&apos; If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
  631. &apos;&apos;&apos; Args:
  632. &apos;&apos;&apos; pbError: if True (default), raise a fatal error
  633. Dim bAlive As Boolean &apos; Return value
  634. Dim sName As String &apos; Used in error message
  635. On Local Error GoTo Catch &apos; Anticipate DisposedException errors or alike
  636. If IsMissing(pbError) Then pbError = True
  637. Try:
  638. &apos; Check existence of datasheet
  639. bAlive = Not IsNull(_Component.ComponentWindow)
  640. Finally:
  641. If pbError And Not bAlive Then
  642. sName = _Command
  643. Dispose()
  644. If pbError Then ScriptForge.SF_Exception.RaiseFatal(DOCUMENTDEADERROR, sName)
  645. End If
  646. _IsStillAlive = bAlive
  647. Exit Function
  648. Catch:
  649. bAlive = False
  650. On Error GoTo 0
  651. GoTo Finally
  652. End Function &apos; SFDatabases.SF_Datasheet._IsStillAlive
  653. REM -----------------------------------------------------------------------------
  654. Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
  655. &apos;&apos;&apos; Return the value of the named property
  656. &apos;&apos;&apos; Args:
  657. &apos;&apos;&apos; psProperty: the name of the property
  658. Dim lRow As Long &apos; Actual row number
  659. Dim cstThisSub As String
  660. Const cstSubArgs = &quot;&quot;
  661. cstThisSub = &quot;SFDatabases.Datasheet.get&quot; &amp; psProperty
  662. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  663. ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  664. If Not _IsStillAlive(False) Then GoTo Finally
  665. Select Case psProperty
  666. Case &quot;ColumnHeaders&quot;
  667. _PropertyGet = _ColumnHeaders
  668. Case &quot;CurrentColumn&quot;
  669. _PropertyGet = _ColumnHeaders(_ControlView.getCurrentColumnPosition())
  670. Case &quot;CurrentRow&quot;
  671. _PropertyGet = _TabControllerModel.Row
  672. Case &quot;DatabaseFileName&quot;
  673. _PropertyGet = ScriptForge.SF_FileSystem._ConvertFromUrl(_BaseFileName)
  674. Case &quot;Filter&quot;
  675. _PropertyGet = _TabControllerModel.Filter
  676. Case &quot;LastRow&quot;
  677. With _TabControllerModel
  678. If .IsRowCountFinal Then
  679. _PropertyGet = .RowCount
  680. Else
  681. lRow = .Row
  682. If lRow &gt; 0 Then
  683. .last()
  684. _PropertyGet = .RowCount
  685. .absolute(lRow)
  686. Else
  687. _PropertyGet = 0
  688. End If
  689. End If
  690. End With
  691. Case &quot;OrderBy&quot;
  692. _PropertyGet = _TabControllerModel.Order
  693. Case &quot;ParentDatabase&quot;
  694. Set _PropertyGet = _ParentDatabase
  695. Case &quot;Source&quot;
  696. _PropertyGet = _Command
  697. Case &quot;SourceType&quot;
  698. _PropertyGet = _SheetType
  699. Case &quot;XComponent&quot;
  700. Set _PropertyGet = _Component
  701. Case &quot;XControlModel&quot;
  702. Set _PropertyGet = _ControlModel
  703. Case &quot;XTabControllerModel&quot;
  704. Set _PropertyGet = _TabControllerModel
  705. Case Else
  706. _PropertyGet = Null
  707. End Select
  708. Finally:
  709. ScriptForge.SF_Utils._ExitFunction(cstThisSub)
  710. Exit Function
  711. Catch:
  712. GoTo Finally
  713. End Function &apos; SFDatabases.SF_Datasheet._PropertyGet
  714. REM -----------------------------------------------------------------------------
  715. Private Function _PropertySet(Optional ByVal psProperty As String _
  716. , Optional ByVal pvValue As Variant _
  717. ) As Boolean
  718. &apos;&apos;&apos; Set the new value of the named property
  719. &apos;&apos;&apos; Args:
  720. &apos;&apos;&apos; psProperty: the name of the property
  721. &apos;&apos;&apos; pvValue: the new value of the given property
  722. &apos;&apos;&apos; Returns:
  723. &apos;&apos;&apos; True if successful
  724. Dim bSet As Boolean &apos; Return value
  725. Dim cstThisSub As String
  726. Const cstSubArgs = &quot;Value&quot;
  727. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  728. bSet = False
  729. cstThisSub = &quot;SFDatabases.Datasheet.set&quot; &amp; psProperty
  730. ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  731. If Not _IsStillAlive() Then GoTo Finally
  732. bSet = True
  733. Select Case UCase(psProperty)
  734. Case UCase(&quot;Filter&quot;)
  735. If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Filter&quot;, V_STRING) Then GoTo Finally
  736. With _TabControllerModel
  737. If Len(pvValue) &gt; 0 Then .Filter = _ParentDatabase._ReplaceSquareBrackets(pvValue) Else .Filter = &quot;&quot;
  738. .ApplyFilter = ( Len(pvValue) &gt; 0 )
  739. .reload()
  740. End With
  741. Case UCase(&quot;OrderBy&quot;)
  742. If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;OrderBy&quot;, V_STRING) Then GoTo Finally
  743. With _TabControllerModel
  744. If Len(pvValue) &gt; 0 Then .Order = _ParentDatabase._ReplaceSquareBrackets(pvValue) Else .Order = &quot;&quot;
  745. .reload()
  746. End With
  747. Case Else
  748. bSet = False
  749. End Select
  750. Finally:
  751. _PropertySet = bSet
  752. ScriptForge.SF_Utils._ExitFunction(cstThisSub)
  753. Exit Function
  754. Catch:
  755. GoTo Finally
  756. End Function &apos; SFDatabases.SF_Datasheet._PropertySet
  757. REM -----------------------------------------------------------------------------
  758. Private Function _Repr() As String
  759. &apos;&apos;&apos; Convert the Datasheet instance to a readable string, typically for debugging purposes (DebugPrint ...)
  760. &apos;&apos;&apos; Args:
  761. &apos;&apos;&apos; Return:
  762. &apos;&apos;&apos; &quot;[DATASHEET]: tablename,base file url&quot;
  763. _Repr = &quot;[DATASHEET]: &quot; &amp; _Command &amp; &quot;,&quot; &amp; _BaseFileName
  764. End Function &apos; SFDatabases.SF_Datasheet._Repr
  765. REM ============================================ END OF SFDATABASES.SF_DATASHEET
  766. </script:module>