summaryrefslogtreecommitdiffstats
path: root/wizards/source/sfdialogs/SF_Register.xba
blob: e81dbb069fa8c7c96617925fb3b14587f24b244b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Register" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM ===			The ScriptForge library and its associated libraries are part of the LibreOffice project.				===
REM	===						The SFDialogs library is one of the associated libraries.									===
REM ===					Full documentation is available on https://help.libreoffice.org/								===
REM =======================================================================================================================

Option Compatible
Option Explicit

&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos;	SF_Register
&apos;&apos;&apos;	===========
&apos;&apos;&apos;		The ScriptForge framework includes
&apos;&apos;&apos;			the master ScriptForge library
&apos;&apos;&apos;			a number of &quot;associated&quot; libraries SF*
&apos;&apos;&apos;			any user/contributor extension wanting to fit into the framework 
&apos;&apos;&apos;
&apos;&apos;&apos;		The main methods in this module allow the current library to cling to ScriptForge
&apos;&apos;&apos;			- RegisterScriptServices
&apos;&apos;&apos;				Register the list of services implemented by the current library
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;

REM ================================================================= DEFINITIONS

&apos;&apos;&apos;	Event management of dialogs requires to being able to rebuild a Dialog object
&apos;&apos;&apos;	from its com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl UNO instance
&apos;&apos;&apos;	For that purpose, the started dialogs are buffered in a global array of _DialogCache types

Type _DialogCache
	Terminated				As Boolean
	XUnoDialog				As Object
	BasicDialog				As Object
End Type

REM ================================================================== EXCEPTIONS

Private Const DIALOGNOTFOUNDERROR	=	&quot;DIALOGNOTFOUNDERROR&quot;
	
REM ============================================================== PUBLIC METHODS

REM -----------------------------------------------------------------------------
Public Sub RegisterScriptServices() As Variant
&apos;&apos;&apos;	Register into ScriptForge the list of the services implemented by the current library
&apos;&apos;&apos;	Each library pertaining to the framework must implement its own version of this method
&apos;&apos;&apos;
&apos;&apos;&apos;	It consists in successive calls to the RegisterService() and RegisterEventManager() methods
&apos;&apos;&apos;	with 2 arguments:
&apos;&apos;&apos;		ServiceName: the name of the service as a case-insensitive string
&apos;&apos;&apos;		ServiceReference: the reference as an object
&apos;&apos;&apos;			If the reference refers to a module, then return the module as an object:
&apos;&apos;&apos;				GlobalScope.Library.Module
&apos;&apos;&apos;			If the reference is a class instance, then return a string referring to the method
&apos;&apos;&apos;			containing the New statement creating the instance
&apos;&apos;&apos;				&quot;libraryname.modulename.function&quot;

	With GlobalScope.ScriptForge.SF_Services
		.RegisterService(&quot;Dialog&quot;,				&quot;SFDialogs.SF_Register._NewDialog&quot;)			&apos;	Reference to the function initializing the service
		.RegisterEventManager(&quot;DialogEvent&quot;,	&quot;SFDialogs.SF_Register._EventManager&quot;)		&apos;	Reference to the events manager
		&apos;TODO
	End With

End Sub			&apos;	SFDialogs.SF_Register.RegisterScriptServices

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
Private Function _AddDialogToCache(ByRef pvUnoDialog As Object _
										, ByRef pvBasicDialog As Object _
										) As Long
&apos;&apos;&apos;	Add a new entry in the cache array with the references of the actual dialog
&apos;&apos;&apos;	If relevant, the last entry of the cache is reused.
&apos;&apos;&apos;	The cache is located in the global _SF_ variable
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvUnoDialog: the com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl of the dialog box
&apos;&apos;&apos;		pvBasicDialog: its corresponding Basic object
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The index of the new or modified entry

Dim vCache As New _DialogCache		&apos;	Entry to be added
Dim lIndex As Long					&apos;	UBound of _SF_.SFDialogs
Dim vCacheArray As Variant			&apos;	Alias of _SF_.SFDialogs

Try:
	vCacheArray = _SF_.SFDialogs

	If IsEmpty(vCacheArray) Then vCacheArray = Array()
	lIndex = UBound(vCacheArray)
	If lIndex &lt; LBound(vCacheArray) Then
		ReDim vCacheArray(0 To 0)
		lIndex = 0
	ElseIf Not vCacheArray(lIndex).Terminated Then		&apos;	Often last entry can be reused
		lIndex = lIndex + 1
		ReDim Preserve vCacheArray(0 To lIndex)
	End If
	
	With vCache
		.Terminated = False
		Set .XUnoDialog = pvUnoDialog
		Set .BasicDialog = pvBasicDialog
	End With
	vCacheArray(lIndex) = vCache
	
	_SF_.SFDialogs = vCacheArray

Finally:
	_AddDialogToCache = lIndex
	Exit Function
End Function	&apos;	SFDialogs.SF_Register._AddDialogToCache

REM -----------------------------------------------------------------------------
Private Sub _CleanCacheEntry(ByVal plIndex As Long)
&apos;&apos;&apos;	Clean the plIndex-th entry in the dialogs cache
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		plIndex: must fit within the actual boundaries of the cache, otherwise the request is ignored

Dim vCache As New _DialogCache		&apos;	Cleaned entry

	With _SF_
		If Not IsArray(.SFDialogs) Then Exit Sub
		If plIndex &lt; LBound(.SFDialogs) Or plIndex &gt; UBound(.SFDialogs) Then Exit Sub

		With vCache
			.Terminated = True
			Set .XUnoDialog = Nothing
			Set .BasicDialog = Nothing
		End With
		.SFDialogs(plIndex) = vCache
	End With
	
Finally:
	Exit Sub
End Sub			&apos;	SFDialogs.SF_Register._CleanCacheEntry

REM -----------------------------------------------------------------------------
Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
&apos;&apos;&apos;	Returns a Dialog or DialogControl object corresponding with the Basic dialog
&apos;&apos;&apos;	which triggered the event in argument
&apos;&apos;&apos;	This method should be triggered only thru the invocation of CreateScriptService
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvEvent: com.sun.star.xxx
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		the output of a Dialog or DialogControl service or Nothing
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		Sub TriggeredByEvent(ByRef poEvent As Object)
&apos;&apos;&apos;			Dim oDlg As Object
&apos;&apos;&apos;			Set oDlg = CreateScriptService(&quot;SFDialogs.DialogEvent&quot;, poEvent)
&apos;&apos;&apos;			If Not IsNull(oDlg) Then
&apos;&apos;&apos;				&apos; ... (a valid dialog or one of its controls has been identified)
&apos;&apos;&apos;		End Sub

Dim oSource As Object			&apos;	Return value
Dim oEventSource As Object		&apos;	Event UNO source
Dim vEvent As Variant			&apos;	Alias of pvArgs(0)
Dim sSourceType As String		&apos;	Implementation name of event source
Dim oDialog As Object			&apos;	com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
Dim bControl As Boolean			&apos;	True when control event

	&apos;	Never abort while an event is processed
	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Finally
	Set oSource = Nothing

Check:
	If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
	If UBound(pvArgs) &gt;= 0 Then vEvent = pvArgs(0) Else vEvent = Empty
	If VarType(vEvent) &lt;&gt; ScriptForge.V_OBJECT Then GoTo Finally
	If Not ScriptForge.SF_Session.HasUnoProperty(vEvent, &quot;Source&quot;) Then GoTo Finally

Try:
	Set oEventSource = vEvent.Source
	sSourceType = ScriptForge.SF_Session.UnoObjectType(oEventSource)
	
	Set oDialog = Nothing
	Select Case True
		Case sSourceType = &quot;stardiv.Toolkit.UnoDialogControl&quot;		&apos;	A dialog
			&apos;	Search the dialog in the cache
			Set oDialog = _FindDialogInCache(oEventSource)
			bControl = False
		Case Left(sSourceType, 16) = &quot;stardiv.Toolkit.&quot;				&apos;	A dialog control
			Set oDialog = _FindDialogInCache(oEventSource.Context)
			bControl = True
		Case Else
	End Select

	If Not IsNull(oDialog) Then
		If bControl Then Set oSource = oDialog.Controls(oEventSource.Model.Name) Else Set oSource = oDialog
	End If

Finally:
	Set _EventManager = oSource
	Exit Function
End Function	&apos;	SFDialogs.SF_Register._EventManager

REM -----------------------------------------------------------------------------
Private Function _FindDialogInCache(ByRef poDialog As Object) As Object
&apos;&apos;&apos;	Find the dialog based on its XUnoDialog
&apos;&apos;&apos;	The dialog must not be terminated
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The corresponding Basic dialog part or Nothing

Dim oBasicDialog As Object		&apos;	Return value
Dim oCache As _DialogCache		&apos;	Entry in the cache

	Set oBasicDialog = Nothing

Try:
	For Each oCache In _SF_.SFDialogs
		If EqualUnoObjects(poDialog, oCache.XUnoDialog) And Not oCache.Terminated Then
			Set oBasicDialog = oCache.BasicDialog
			Exit For
		End If
	Next oCache

Finally:
	Set _FindDialogInCache = oBasicDialog
	Exit Function
End Function	&apos;	SFDialogs.SF_Register._FindDialogInCache

REM -----------------------------------------------------------------------------
Public Function _NewDialog(Optional ByVal pvArgs As Variant) As Object
&apos;&apos;&apos;	Create a new instance of the SF_Dialog class
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Container: either &quot;GlobalScope&quot; or a WindowName. Default = the active window
&apos;&apos;&apos;					see the definition of WindowName in the description of the UI service
&apos;&apos;&apos;		Library: the name of the library hosting the dialog. Default = &quot;Standard&quot;
&apos;&apos;&apos;		DialogName: The name of the dialog
&apos;&apos;&apos;			Library and dialog names are case-sensitive
&apos;&apos;&apos;		Context: When called from Python, the context must be provided : XSCRIPTCONTEXT
&apos;&apos;&apos;	Returns: the instance or Nothing

Dim oDialog As Object				&apos;	Return value
Dim vContainer As Variant			&apos;	Alias of pvArgs(0)
Dim vLibrary As Variant				&apos;	Alias of pvArgs(1)
Dim vDialogName As Variant			&apos;	Alias of pvArgs(2)
Dim oLibraries As Object			&apos;	com.sun.star.comp.sfx2.DialogLibraryContainer
Dim vContext As Variant				&apos;	com.sun.star.uno.XComponentContext
Dim oDialogProvider As Object		&apos;	com.sun.star.io.XInputStreamProvider
Dim oEnum As Object					&apos;	com.sun.star.container.XEnumeration
Dim oComp As Object					&apos;	com.sun.star.lang.XComponent
Dim oDialogControl As Object		&apos;	com.sun.star.awt.XControl - stardiv.Toolkit.UnoDialogControl
Dim vWindow As Window				&apos;	A single component
Dim sScope As String				&apos;	&quot;application&quot; or &quot;document&quot;
Dim sURI As String					&apos;	URI of the targeted dialog
Dim oUi As Object					&apos;	&quot;UI&quot; service
Dim bFound As Boolean				&apos;	True if WindowName is found on the desktop
Const cstService = &quot;SFDialogs.Dialog&quot;
Const cstGlobal = &quot;GlobalScope&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
	If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)		&apos;	Needed when _NewDialog called from _EventManager
	If UBound(pvArgs) &gt;= 0 Then vContainer = pvArgs(0) Else vContainer = &quot;&quot;
	If UBound(pvArgs) &gt;= 1 Then vLibrary = pvArgs(1)
	If IsEmpty(vLibrary) Then vLibrary = &quot;Standard&quot;
	If UBound(pvArgs) &gt;= 2 Then vDialogName = pvArgs(2) Else vDialogName = Empty	&apos;	Use Empty to force mandatory status
	If Not ScriptForge.SF_Utils._Validate(vContainer, &quot;Container&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
	If Not ScriptForge.SF_Utils._Validate(vLibrary, &quot;Library&quot;, V_STRING) Then GoTo Finally
	If Not ScriptForge.SF_Utils._Validate(vDialogName, &quot;DialogName&quot;, V_STRING) Then GoTo Finally
	If UBound(pvArgs) &gt;= 3 Then vContext = pvArgs(3) Else vContext = Nothing
	If Not ScriptForge.SF_Utils._Validate(vContext, &quot;DialogName&quot;, V_OBJECT) Then GoTo Finally
	Set oDialog = Nothing

Try:
	&apos;	Determine the library container hosting the dialog
	Set oUi = ScriptForge.SF_Register.CreateScriptService(&quot;UI&quot;)
	Set oComp = Nothing
	If VarType(vContainer) = V_STRING Then
		bFound = ( UCase(vContainer) = UCase(cstGlobal) )
	End If
	If Not bFound Then
		Select Case VarType(vContainer)
			Case V_STRING
				If Len(vContainer) &gt; 0 Then
					bFound = False
					Set oEnum = StarDesktop.Components().createEnumeration
					Do While oEnum.hasMoreElements
						Set oComp = oEnum.nextElement
						vWindow = oUi._IdentifyWindow(oComp)
						With vWindow
							&apos;	Does the current window match the argument ?
							If	(Len(.WindowFileName) &gt; 0 And .WindowFileName = ScriptForge.SF_FileSystem._ConvertToUrl(vContainer)) _
								Or (Len(.WindowName) &gt; 0 And .WindowName = vContainer) _
								Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = vContainer) Then
									bFound = True
									Exit Do
								End If
						End With
					Loop
				Else
					bFound = True
					Set oComp = StarDesktop.CurrentComponent
					vWindow = oUi._IdentifyWindow(oComp)
				End If
			Case V_OBJECT	&apos;	com.sun.star.lang.XComponent
				bFound = True
				vWindow = oUi._IdentifyWindow(vContainer)
				Set oComp = vContainer
		End Select
		If Not bFound Then GoTo CatchNotFound
		If Len(vWindow.DocumentType) = 0 Then GoTo CatchNotFound
	End If

	&apos;	Determine the dialog provider
	Select Case True
		Case IsNull(vContext) And IsNull(oComp)			&apos;	Basic and GlobalScope
			Set oDialogProvider = GetProcessServiceManager.createInstance(&quot;com.sun.star.awt.DialogProvider&quot;)
		Case IsNull(vContext) And Not IsNull(oComp)		&apos;	Basic and Document
			Set oDialogProvider = GetProcessServiceManager.createInstanceWithArguments(&quot;com.sun.star.awt.DialogProvider&quot;, Array(oComp))
		Case Not IsNull(vContext) And IsNull(oComp)		&apos;	Python and GlobalScope
			Set oDialogProvider = vContext.getServiceManager().createInstanceWithContext(&quot;com.sun.star.awt.DialogProvider&quot;, vContext)
		Case Not IsNull(vContext) And Not IsNull(oComp)	&apos;	Python and Document
			Set oDialogProvider = vContext.getServiceManager().createInstanceWithArguments(&quot;com.sun.star.awt.DialogProvider&quot;, Array(oComp))
	End Select

	&apos;	Create the graphical interface
	sScope = Iif(IsNull(oComp), &quot;application&quot;, &quot;document&quot;)
	sURI = &quot;vnd.sun.star.script:&quot; &amp; vLibrary &amp; &quot;.&quot; &amp; vDialogName &amp; &quot;?location=&quot; &amp; sScope
	On Local Error GoTo CatchNotFound
	Set oDialogControl = oDialogProvider.createDialog(sURI)

	&apos;	Initialize the basic SF_Dialog instance to return to the user script
	Set oDialog = New SF_Dialog
	With oDialog
		Set .[Me] = oDialog
		If VarType(vContainer) = V_STRING Then ._Container = vContainer Else ._Container = vWindow.WindowName
		._Library = vLibrary
		._Name = vDialogName
		Set ._DialogProvider = oDialogProvider
		Set ._DialogControl = oDialogControl
		._Initialize()
	End With

Finally:
	Set _NewDialog = oDialog
	Exit Function
Catch:
	GoTo Finally
CatchNotFound:
	ScriptForge.SF_Exception.RaiseFatal(DIALOGNOTFOUNDERROR, &quot;Service&quot;, cstService _
		, &quot;Container&quot;, vContainer, &quot;Library&quot;, vLibrary, &quot;DialogName&quot;, vDialogName)
	GoTo Finally
End Function	&apos;	SFDialogs.SF_Register._NewDialog

REM ============================================== END OF SFDIALOGS.SF_REGISTER
</script:module>