SF_Register.xba 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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_Register" 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 SFDialogs 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 Explicit
  10. &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
  11. &apos;&apos;&apos; SF_Register
  12. &apos;&apos;&apos; ===========
  13. &apos;&apos;&apos; The ScriptForge framework includes
  14. &apos;&apos;&apos; the master ScriptForge library
  15. &apos;&apos;&apos; a number of &quot;associated&quot; libraries SF*
  16. &apos;&apos;&apos; any user/contributor extension wanting to fit into the framework
  17. &apos;&apos;&apos;
  18. &apos;&apos;&apos; The main methods in this module allow the current library to cling to ScriptForge
  19. &apos;&apos;&apos; - RegisterScriptServices
  20. &apos;&apos;&apos; Register the list of services implemented by the current library
  21. &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
  22. REM ================================================================= DEFINITIONS
  23. &apos;&apos;&apos; Event management of dialogs requires to being able to rebuild a Dialog object
  24. &apos;&apos;&apos; from its com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl UNO instance
  25. &apos;&apos;&apos; For that purpose, the started dialogs are buffered in a global array of _DialogCache types
  26. Type _DialogCache
  27. Terminated As Boolean
  28. XUnoDialog As Object
  29. BasicDialog As Object
  30. End Type
  31. REM ================================================================== EXCEPTIONS
  32. Private Const DIALOGNOTFOUNDERROR = &quot;DIALOGNOTFOUNDERROR&quot;
  33. REM ============================================================== PUBLIC METHODS
  34. REM -----------------------------------------------------------------------------
  35. Public Sub RegisterScriptServices() As Variant
  36. &apos;&apos;&apos; Register into ScriptForge the list of the services implemented by the current library
  37. &apos;&apos;&apos; Each library pertaining to the framework must implement its own version of this method
  38. &apos;&apos;&apos;
  39. &apos;&apos;&apos; It consists in successive calls to the RegisterService() and RegisterEventManager() methods
  40. &apos;&apos;&apos; with 2 arguments:
  41. &apos;&apos;&apos; ServiceName: the name of the service as a case-insensitive string
  42. &apos;&apos;&apos; ServiceReference: the reference as an object
  43. &apos;&apos;&apos; If the reference refers to a module, then return the module as an object:
  44. &apos;&apos;&apos; GlobalScope.Library.Module
  45. &apos;&apos;&apos; If the reference is a class instance, then return a string referring to the method
  46. &apos;&apos;&apos; containing the New statement creating the instance
  47. &apos;&apos;&apos; &quot;libraryname.modulename.function&quot;
  48. With GlobalScope.ScriptForge.SF_Services
  49. .RegisterService(&quot;Dialog&quot;, &quot;SFDialogs.SF_Register._NewDialog&quot;) &apos; Reference to the function initializing the service
  50. .RegisterEventManager(&quot;DialogEvent&quot;, &quot;SFDialogs.SF_Register._EventManager&quot;) &apos; Reference to the events manager
  51. &apos;TODO
  52. End With
  53. End Sub &apos; SFDialogs.SF_Register.RegisterScriptServices
  54. REM =========================================================== PRIVATE FUNCTIONS
  55. REM -----------------------------------------------------------------------------
  56. Private Function _AddDialogToCache(ByRef pvUnoDialog As Object _
  57. , ByRef pvBasicDialog As Object _
  58. ) As Long
  59. &apos;&apos;&apos; Add a new entry in the cache array with the references of the actual dialog
  60. &apos;&apos;&apos; If relevant, the last entry of the cache is reused.
  61. &apos;&apos;&apos; The cache is located in the global _SF_ variable
  62. &apos;&apos;&apos; Args:
  63. &apos;&apos;&apos; pvUnoDialog: the com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl of the dialog box
  64. &apos;&apos;&apos; pvBasicDialog: its corresponding Basic object
  65. &apos;&apos;&apos; Returns:
  66. &apos;&apos;&apos; The index of the new or modified entry
  67. Dim vCache As New _DialogCache &apos; Entry to be added
  68. Dim lIndex As Long &apos; UBound of _SF_.SFDialogs
  69. Dim vCacheArray As Variant &apos; Alias of _SF_.SFDialogs
  70. Try:
  71. vCacheArray = _SF_.SFDialogs
  72. If IsEmpty(vCacheArray) Then vCacheArray = Array()
  73. lIndex = UBound(vCacheArray)
  74. If lIndex &lt; LBound(vCacheArray) Then
  75. ReDim vCacheArray(0 To 0)
  76. lIndex = 0
  77. ElseIf Not vCacheArray(lIndex).Terminated Then &apos; Often last entry can be reused
  78. lIndex = lIndex + 1
  79. ReDim Preserve vCacheArray(0 To lIndex)
  80. End If
  81. With vCache
  82. .Terminated = False
  83. Set .XUnoDialog = pvUnoDialog
  84. Set .BasicDialog = pvBasicDialog
  85. End With
  86. vCacheArray(lIndex) = vCache
  87. _SF_.SFDialogs = vCacheArray
  88. Finally:
  89. _AddDialogToCache = lIndex
  90. Exit Function
  91. End Function &apos; SFDialogs.SF_Register._AddDialogToCache
  92. REM -----------------------------------------------------------------------------
  93. Private Sub _CleanCacheEntry(ByVal plIndex As Long)
  94. &apos;&apos;&apos; Clean the plIndex-th entry in the dialogs cache
  95. &apos;&apos;&apos; Args:
  96. &apos;&apos;&apos; plIndex: must fit within the actual boundaries of the cache, otherwise the request is ignored
  97. Dim vCache As New _DialogCache &apos; Cleaned entry
  98. With _SF_
  99. If Not IsArray(.SFDialogs) Then Exit Sub
  100. If plIndex &lt; LBound(.SFDialogs) Or plIndex &gt; UBound(.SFDialogs) Then Exit Sub
  101. With vCache
  102. .Terminated = True
  103. Set .XUnoDialog = Nothing
  104. Set .BasicDialog = Nothing
  105. End With
  106. .SFDialogs(plIndex) = vCache
  107. End With
  108. Finally:
  109. Exit Sub
  110. End Sub &apos; SFDialogs.SF_Register._CleanCacheEntry
  111. REM -----------------------------------------------------------------------------
  112. Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
  113. &apos;&apos;&apos; Returns a Dialog or DialogControl object corresponding with the Basic dialog
  114. &apos;&apos;&apos; which triggered the event in argument
  115. &apos;&apos;&apos; This method should be triggered only thru the invocation of CreateScriptService
  116. &apos;&apos;&apos; Args:
  117. &apos;&apos;&apos; pvEvent: com.sun.star.xxx
  118. &apos;&apos;&apos; Returns:
  119. &apos;&apos;&apos; the output of a Dialog or DialogControl service or Nothing
  120. &apos;&apos;&apos; Example:
  121. &apos;&apos;&apos; Sub TriggeredByEvent(ByRef poEvent As Object)
  122. &apos;&apos;&apos; Dim oDlg As Object
  123. &apos;&apos;&apos; Set oDlg = CreateScriptService(&quot;SFDialogs.DialogEvent&quot;, poEvent)
  124. &apos;&apos;&apos; If Not IsNull(oDlg) Then
  125. &apos;&apos;&apos; &apos; ... (a valid dialog or one of its controls has been identified)
  126. &apos;&apos;&apos; End Sub
  127. Dim oSource As Object &apos; Return value
  128. Dim oEventSource As Object &apos; Event UNO source
  129. Dim vEvent As Variant &apos; Alias of pvArgs(0)
  130. Dim sSourceType As String &apos; Implementation name of event source
  131. Dim oDialog As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
  132. Dim bControl As Boolean &apos; True when control event
  133. &apos; Never abort while an event is processed
  134. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Finally
  135. Set oSource = Nothing
  136. Check:
  137. If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
  138. If UBound(pvArgs) &gt;= 0 Then vEvent = pvArgs(0) Else vEvent = Empty
  139. If VarType(vEvent) &lt;&gt; ScriptForge.V_OBJECT Then GoTo Finally
  140. If Not ScriptForge.SF_Session.HasUnoProperty(vEvent, &quot;Source&quot;) Then GoTo Finally
  141. Try:
  142. Set oEventSource = vEvent.Source
  143. sSourceType = ScriptForge.SF_Session.UnoObjectType(oEventSource)
  144. Set oDialog = Nothing
  145. Select Case True
  146. Case sSourceType = &quot;stardiv.Toolkit.UnoDialogControl&quot; &apos; A dialog
  147. &apos; Search the dialog in the cache
  148. Set oDialog = _FindDialogInCache(oEventSource)
  149. bControl = False
  150. Case Left(sSourceType, 16) = &quot;stardiv.Toolkit.&quot; &apos; A dialog control
  151. Set oDialog = _FindDialogInCache(oEventSource.Context)
  152. bControl = True
  153. Case Else
  154. End Select
  155. If Not IsNull(oDialog) Then
  156. If bControl Then Set oSource = oDialog.Controls(oEventSource.Model.Name) Else Set oSource = oDialog
  157. End If
  158. Finally:
  159. Set _EventManager = oSource
  160. Exit Function
  161. End Function &apos; SFDialogs.SF_Register._EventManager
  162. REM -----------------------------------------------------------------------------
  163. Private Function _FindDialogInCache(ByRef poDialog As Object) As Object
  164. &apos;&apos;&apos; Find the dialog based on its XUnoDialog
  165. &apos;&apos;&apos; The dialog must not be terminated
  166. &apos;&apos;&apos; Returns:
  167. &apos;&apos;&apos; The corresponding Basic dialog part or Nothing
  168. Dim oBasicDialog As Object &apos; Return value
  169. Dim oCache As _DialogCache &apos; Entry in the cache
  170. Set oBasicDialog = Nothing
  171. Try:
  172. For Each oCache In _SF_.SFDialogs
  173. If EqualUnoObjects(poDialog, oCache.XUnoDialog) And Not oCache.Terminated Then
  174. Set oBasicDialog = oCache.BasicDialog
  175. Exit For
  176. End If
  177. Next oCache
  178. Finally:
  179. Set _FindDialogInCache = oBasicDialog
  180. Exit Function
  181. End Function &apos; SFDialogs.SF_Register._FindDialogInCache
  182. REM -----------------------------------------------------------------------------
  183. Public Function _NewDialog(Optional ByVal pvArgs As Variant) As Object
  184. &apos;&apos;&apos; Create a new instance of the SF_Dialog class
  185. &apos;&apos;&apos; Args:
  186. &apos;&apos;&apos; Container: either &quot;GlobalScope&quot; or a WindowName. Default = the active window
  187. &apos;&apos;&apos; see the definition of WindowName in the description of the UI service
  188. &apos;&apos;&apos; Library: the name of the library hosting the dialog. Default = &quot;Standard&quot;
  189. &apos;&apos;&apos; DialogName: The name of the dialog
  190. &apos;&apos;&apos; Library and dialog names are case-sensitive
  191. &apos;&apos;&apos; Context: When called from Python, the context must be provided : XSCRIPTCONTEXT
  192. &apos;&apos;&apos; Returns: the instance or Nothing
  193. Dim oDialog As Object &apos; Return value
  194. Dim vContainer As Variant &apos; Alias of pvArgs(0)
  195. Dim vLibrary As Variant &apos; Alias of pvArgs(1)
  196. Dim vDialogName As Variant &apos; Alias of pvArgs(2)
  197. Dim oLibraries As Object &apos; com.sun.star.comp.sfx2.DialogLibraryContainer
  198. Dim vContext As Variant &apos; com.sun.star.uno.XComponentContext
  199. Dim oDialogProvider As Object &apos; com.sun.star.io.XInputStreamProvider
  200. Dim oEnum As Object &apos; com.sun.star.container.XEnumeration
  201. Dim oComp As Object &apos; com.sun.star.lang.XComponent
  202. Dim oDialogControl As Object &apos; com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
  203. Dim vWindow As Window &apos; A single component
  204. Dim sScope As String &apos; &quot;application&quot; or &quot;document&quot;
  205. Dim sURI As String &apos; URI of the targeted dialog
  206. Dim oUi As Object &apos; &quot;UI&quot; service
  207. Dim bFound As Boolean &apos; True if WindowName is found on the desktop
  208. Const cstService = &quot;SFDialogs.Dialog&quot;
  209. Const cstGlobal = &quot;GlobalScope&quot;
  210. If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  211. Check:
  212. If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
  213. If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs) &apos; Needed when _NewDialog called from _EventManager
  214. If UBound(pvArgs) &gt;= 0 Then vContainer = pvArgs(0) Else vContainer = &quot;&quot;
  215. If UBound(pvArgs) &gt;= 1 Then vLibrary = pvArgs(1)
  216. If IsEmpty(vLibrary) Then vLibrary = &quot;Standard&quot;
  217. If UBound(pvArgs) &gt;= 2 Then vDialogName = pvArgs(2) Else vDialogName = Empty &apos; Use Empty to force mandatory status
  218. If Not ScriptForge.SF_Utils._Validate(vContainer, &quot;Container&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
  219. If Not ScriptForge.SF_Utils._Validate(vLibrary, &quot;Library&quot;, V_STRING) Then GoTo Finally
  220. If Not ScriptForge.SF_Utils._Validate(vDialogName, &quot;DialogName&quot;, V_STRING) Then GoTo Finally
  221. If UBound(pvArgs) &gt;= 3 Then vContext = pvArgs(3) Else vContext = Nothing
  222. If Not ScriptForge.SF_Utils._Validate(vContext, &quot;DialogName&quot;, V_OBJECT) Then GoTo Finally
  223. Set oDialog = Nothing
  224. Try:
  225. &apos; Determine the library container hosting the dialog
  226. Set oUi = ScriptForge.SF_Register.CreateScriptService(&quot;UI&quot;)
  227. Set oComp = Nothing
  228. If VarType(vContainer) = V_STRING Then
  229. bFound = ( UCase(vContainer) = UCase(cstGlobal) )
  230. End If
  231. If Not bFound Then
  232. Select Case VarType(vContainer)
  233. Case V_STRING
  234. If Len(vContainer) &gt; 0 Then
  235. bFound = False
  236. Set oEnum = StarDesktop.Components().createEnumeration
  237. Do While oEnum.hasMoreElements
  238. Set oComp = oEnum.nextElement
  239. vWindow = oUi._IdentifyWindow(oComp)
  240. With vWindow
  241. &apos; Does the current window match the argument ?
  242. If (Len(.WindowFileName) &gt; 0 And .WindowFileName = ScriptForge.SF_FileSystem._ConvertToUrl(vContainer)) _
  243. Or (Len(.WindowName) &gt; 0 And .WindowName = vContainer) _
  244. Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = vContainer) Then
  245. bFound = True
  246. Exit Do
  247. End If
  248. End With
  249. Loop
  250. Else
  251. bFound = True
  252. Set oComp = StarDesktop.CurrentComponent
  253. vWindow = oUi._IdentifyWindow(oComp)
  254. End If
  255. Case V_OBJECT &apos; com.sun.star.lang.XComponent
  256. bFound = True
  257. vWindow = oUi._IdentifyWindow(vContainer)
  258. Set oComp = vContainer
  259. End Select
  260. If Not bFound Then GoTo CatchNotFound
  261. If Len(vWindow.DocumentType) = 0 Then GoTo CatchNotFound
  262. End If
  263. &apos; Determine the dialog provider
  264. Select Case True
  265. Case IsNull(vContext) And IsNull(oComp) &apos; Basic and GlobalScope
  266. Set oDialogProvider = GetProcessServiceManager.createInstance(&quot;com.sun.star.awt.DialogProvider&quot;)
  267. Case IsNull(vContext) And Not IsNull(oComp) &apos; Basic and Document
  268. Set oDialogProvider = GetProcessServiceManager.createInstanceWithArguments(&quot;com.sun.star.awt.DialogProvider&quot;, Array(oComp))
  269. Case Not IsNull(vContext) And IsNull(oComp) &apos; Python and GlobalScope
  270. Set oDialogProvider = vContext.getServiceManager().createInstanceWithContext(&quot;com.sun.star.awt.DialogProvider&quot;, vContext)
  271. Case Not IsNull(vContext) And Not IsNull(oComp) &apos; Python and Document
  272. Set oDialogProvider = vContext.getServiceManager().createInstanceWithArguments(&quot;com.sun.star.awt.DialogProvider&quot;, Array(oComp))
  273. End Select
  274. &apos; Create the graphical interface
  275. sScope = Iif(IsNull(oComp), &quot;application&quot;, &quot;document&quot;)
  276. sURI = &quot;vnd.sun.star.script:&quot; &amp; vLibrary &amp; &quot;.&quot; &amp; vDialogName &amp; &quot;?location=&quot; &amp; sScope
  277. On Local Error GoTo CatchNotFound
  278. Set oDialogControl = oDialogProvider.createDialog(sURI)
  279. &apos; Initialize the basic SF_Dialog instance to return to the user script
  280. Set oDialog = New SF_Dialog
  281. With oDialog
  282. Set .[Me] = oDialog
  283. If VarType(vContainer) = V_STRING Then ._Container = vContainer Else ._Container = vWindow.WindowName
  284. ._Library = vLibrary
  285. ._Name = vDialogName
  286. Set ._DialogProvider = oDialogProvider
  287. Set ._DialogControl = oDialogControl
  288. ._Initialize()
  289. End With
  290. Finally:
  291. Set _NewDialog = oDialog
  292. Exit Function
  293. Catch:
  294. GoTo Finally
  295. CatchNotFound:
  296. ScriptForge.SF_Exception.RaiseFatal(DIALOGNOTFOUNDERROR, &quot;Service&quot;, cstService _
  297. , &quot;Container&quot;, vContainer, &quot;Library&quot;, vLibrary, &quot;DialogName&quot;, vDialogName)
  298. GoTo Finally
  299. End Function &apos; SFDialogs.SF_Register._NewDialog
  300. REM ============================================== END OF SFDIALOGS.SF_REGISTER
  301. </script:module>