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_PythonHelper" script:
language=
"StarBasic" script:
moduleType=
"normal">REM =======================================================================================================================
4 REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
5 REM === Full documentation is available on https://help.libreoffice.org/ ===
6 REM =======================================================================================================================
11 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
12 ''' SF_PythonHelper (aka Basic)
13 ''' ===============
14 ''' Singleton class implementing the
"ScriptForge.Basic
" service
15 ''' Implemented as a usual Basic module
17 ''' The
"Basic
" service must be called ONLY from a PYTHON script
18 ''' Service invocations: Next Python code lines are equivalent:
19 ''' bas = CreateScriptService(
'ScriptForge.Basic
')
20 ''' bas = CreateScriptService(
'Basic
')
22 ''' This service proposes a collection of methods to be executed in a Python context
23 ''' to simulate the exact behaviour of the identical Basic builtin method.
24 ''' Typical example:
25 ''' bas.MsgBox(
'This has to be displayed in a message box
')
27 ''' The service includes also an agnostic
"Python Dispatcher
" function.
28 ''' It dispatches Python script requests to execute Basic services to the
29 ''' appropriate properties and methods via dynamic call techniques
31 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
33 REM ================================================================== EXCEPTIONS
35 REM ============================================================ MODULE CONSTANTS
37 REM ===================================================== CONSTRUCTOR/DESTRUCTOR
39 REM -----------------------------------------------------------------------------
40 Public Function Dispose() As Variant
42 End Function
' ScriptForge.SF_PythonHelper Explicit destructor
44 REM ================================================================== PROPERTIES
46 REM -----------------------------------------------------------------------------
47 Property Get ObjectType As String
48 ''' Only to enable object representation
49 ObjectType =
"SF_PythonHelper
"
50 End Property
' ScriptForge.SF_PythonHelper.ObjectType
52 REM -----------------------------------------------------------------------------
53 Property Get ServiceName As String
54 ''' Internal use
55 ServiceName =
"ScriptForge.Basic
"
56 End Property
' ScriptForge.SF_PythonHelper.ServiceName
58 REM ============================================================== PUBLIC METHODS
60 REM -----------------------------------------------------------------------------
61 Public Function PyCDate(ByVal DateArg As Variant) As Variant
62 ''' Convenient function to replicate CDate() in Python scripts
63 ''' Args:
64 ''' DateArg: a date as a string or as a double
65 ''' Returns:
66 ''' The converted date as a UNO DateTime structure
67 ''' If the input argument could not be recognized as a date, return the argument unchanged
68 ''' Example: (Python code)
69 ''' a = bas.CDate(
'2021-
02-
18')
71 Dim vDate As Variant
' Return value
72 Const cstThisSub =
"Basic.CDate
"
73 Const cstSubArgs =
"datearg
"
75 On Local Error GoTo Catch
79 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
82 vDate = CDate(DateArg)
85 If VarType(vDate) = V_DATE Then PyCDate = CDateToUnoDateTime(vDate) Else PyCDate = DateArg
86 SF_Utils._ExitFunction(cstThisSub)
91 End Function
' ScriptForge.SF_PythonHelper.PyCDate
93 REM -----------------------------------------------------------------------------
94 Public Function PyConvertFromUrl(ByVal FileName As Variant) As String
95 ''' Convenient function to replicate ConvertFromUrl() in Python scripts
96 ''' Args:
97 ''' FileName: a string representing a file in URL format
98 ''' Returns:
99 ''' The same file name in native operating system notation
100 ''' Example: (Python code)
101 ''' a = bas.ConvertFromUrl(
'file:////boot.sys
')
103 Dim sFileName As String
' Return value
104 Const cstThisSub =
"Basic.ConvertFromUrl
"
105 Const cstSubArgs =
"filename
"
107 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
108 sFileName =
""
111 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
114 sFileName = ConvertFromUrl(FileName)
117 PyConvertFromUrl = sFileName
118 SF_Utils._ExitFunction(cstThisSub)
122 End Function
' ScriptForge.SF_PythonHelper.PyConvertFromUrl
124 REM -----------------------------------------------------------------------------
125 Public Function PyConvertToUrl(ByVal FileName As Variant) As String
126 ''' Convenient function to replicate ConvertToUrl() in Python scripts
127 ''' Args:
128 ''' FileName: a string representing a file in native operating system notation
129 ''' Returns:
130 ''' The same file name in URL format
131 ''' Example: (Python code)
132 ''' a = bas.ConvertToUrl(
'C:\boot.sys
')
134 Dim sFileName As String
' Return value
135 Const cstThisSub =
"Basic.ConvertToUrl
"
136 Const cstSubArgs =
"filename
"
138 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
139 sFileName =
""
142 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
145 sFileName = ConvertToUrl(FileName)
148 PyConvertToUrl = sFileName
149 SF_Utils._ExitFunction(cstThisSub)
153 End Function
' ScriptForge.SF_PythonHelper.PyConvertToUrl
155 REM -----------------------------------------------------------------------------
156 Public Function PyCreateUnoService(ByVal UnoService As Variant) As Variant
157 ''' Convenient function to replicate CreateUnoService() in Python scripts
158 ''' Args:
159 ''' UnoService: a string representing the service to create
160 ''' Returns:
161 ''' A UNO object
162 ''' Example: (Python code)
163 ''' a = bas.CreateUnoService(
'com.sun.star.i18n.CharacterClassification
')
165 Dim vUno As Variant
' Return value
166 Const cstThisSub =
"Basic.CreateUnoService
"
167 Const cstSubArgs =
"unoservice
"
169 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
173 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
176 Set vUno = CreateUnoService(UnoService)
179 Set PyCreateUnoService = vUno
180 SF_Utils._ExitFunction(cstThisSub)
184 End Function
' ScriptForge.SF_PythonHelper.PyCreateUnoService
186 REM -----------------------------------------------------------------------------
187 Public Function PyDateAdd(ByVal Add As Variant _
188 , ByVal Count As Variant _
189 , ByVal DateArg As Variant _
191 ''' Convenient function to replicate DateAdd() in Python scripts
192 ''' Args:
193 ''' Add: The unit to add
194 ''' Count: how many times to add (might be negative)
195 ''' DateArg: a date as a com.sun.star.util.DateTime UNO structure
196 ''' Returns:
197 ''' The new date as a string in iso format
198 ''' Example: (Python code)
199 ''' a = bas.DateAdd(
'd
',
1, bas.Now())
' Tomorrow
201 Dim vNewDate As Variant
' Return value
202 Dim vDate As Date
' Alias of DateArg
203 Const cstThisSub =
"Basic.DateAdd
"
204 Const cstSubArgs =
"add, count, datearg
"
206 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
207 vNewDate =
""
210 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
213 If VarType(DateArg) = V_OBJECT Then
214 vDate = CDateFromUnoDateTime(DateArg)
216 vDate = SF_Utils._CStrToDate(DateArg)
218 vNewDate = DateAdd(Add, Count, vDate)
221 If VarType(vNewDate) = V_DATE Then PyDateAdd = CDateToUnoDateTime(vNewDate) Else PyDateAdd = vNewDate
222 SF_Utils._ExitFunction(cstThisSub)
226 End Function
' ScriptForge.SF_PythonHelper.PyDateAdd
228 REM -----------------------------------------------------------------------------
229 Public Function PyDateDiff(ByVal Add As Variant _
230 , ByVal Date1 As Variant _
231 , ByVal Date2 As Variant _
232 , ByVal WeekStart As Variant _
233 , ByVal YearStart As Variant _
235 ''' Convenient function to replicate DateDiff() in Python scripts
236 ''' Args:
237 ''' Add: The unit of the date interval
238 ''' Date1, Date2: the two dates to be compared
239 ''' WeekStart: the starting day of a week
240 ''' YearStart: the starting week of a year
241 ''' Returns:
242 ''' The number of intervals expressed in Adds
243 ''' Example: (Python code)
244 ''' a = bas.DateDiff(
'd
', bas.DateAdd(
'd
',
1, bas.Now()), bas.Now())
' -
1 day
246 Dim lDiff As Long
' Return value
247 Dim vDate1 As Date
' Alias of Date1
248 Dim vDate2 As Date
' Alias of Date2
249 Const cstThisSub =
"Basic.DateDiff
"
250 Const cstSubArgs =
"add, date1, date2, [weekstart=
1], [yearstart=
1]
"
252 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
256 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
259 If VarType(Date1) = V_OBJECT Then
260 vDate1 = CDateFromUnoDateTime(Date1)
262 vDate1 = SF_Utils._CStrToDate(Date1)
264 If VarType(Date2) = V_OBJECT Then
265 vDate2 = CDateFromUnoDateTime(Date2)
267 vDate2 = SF_Utils._CStrToDate(Date2)
269 lDiff = DateDiff(Add, vDate1, vDate2, WeekStart, YearStart)
274 SF_Utils._ExitFunction(cstThisSub)
278 End Function
' ScriptForge.SF_PythonHelper.PyDateDiff
280 REM -----------------------------------------------------------------------------
281 Public Function PyDatePart(ByVal Add As Variant _
282 , ByVal DateArg As Variant _
283 , ByVal WeekStart As Variant _
284 , ByVal YearStart As Variant _
286 ''' Convenient function to replicate DatePart() in Python scripts
287 ''' Args:
288 ''' Add: The unit of the date interval
289 ''' DateArg: The date from which to extract a part
290 ''' WeekStart: the starting day of a week
291 ''' YearStart: the starting week of a year
292 ''' Returns:
293 ''' The specified part of the date
294 ''' Example: (Python code)
295 ''' a = bas.DatePart(
'y
', bas.Now())
' day of year
297 Dim lPart As Long
' Return value
298 Dim vDate As Date
' Alias of DateArg
299 Const cstThisSub =
"Basic.DatePart
"
300 Const cstSubArgs =
"add, datearg, [weekstart=
1], [yearstart=
1]
"
302 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
306 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
309 If VarType(DateArg) = V_OBJECT Then
310 vDate = CDateFromUnoDateTime(DateArg)
312 vDate = SF_Utils._CStrToDate(DateArg)
314 lPart = DatePart(Add, vDate, WeekStart, YearStart)
319 SF_Utils._ExitFunction(cstThisSub)
323 End Function
' ScriptForge.SF_PythonHelper.PyDatePart
325 REM -----------------------------------------------------------------------------
326 Public Function PyDateValue(ByVal DateArg As Variant) As Variant
327 ''' Convenient function to replicate DateValue() in Python scripts
328 ''' Args:
329 ''' DateArg: a date as a string
330 ''' Returns:
331 ''' The converted date as a UNO DateTime structure
332 ''' Example: (Python code)
333 ''' a = bas.DateValue(
'2021-
02-
18')
335 Dim vDate As Variant
' Return value
336 Const cstThisSub =
"Basic.DateValue
"
337 Const cstSubArgs =
"datearg
"
339 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
343 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
346 vDate = DateValue(DateArg)
349 If VarType(vDate) = V_DATE Then PyDateValue = CDateToUnoDateTime(vDate) Else PyDateValue = vDate
350 SF_Utils._ExitFunction(cstThisSub)
354 End Function
' ScriptForge.SF_PythonHelper.PyDateValue
356 REM -----------------------------------------------------------------------------
357 Public Function PyFormat(ByVal Value As Variant _
358 , ByVal Pattern As Variant _
360 ''' Convenient function to replicate Format() in Python scripts
361 ''' Args:
362 ''' Value: a date or a number
363 ''' Pattern: the format to apply
364 ''' Returns:
365 ''' The formatted value
366 ''' Example: (Python code)
367 ''' MsgBox bas.Format(
6328.2,
'##,##
0.00')
369 Dim sFormat As String
' Return value
370 Dim vValue As Variant
' Alias of Value
371 Const cstThisSub =
"Basic.Format
"
372 Const cstSubArgs =
"value, pattern
"
374 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
375 sFormat =
""
378 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
381 If VarType(Value) = V_OBJECT Then vValue = CDateFromUnoDateTime(Value) ELse vValue = Value
382 If IsEmpty(Pattern) Or Len(Pattern) =
0 Then sFormat = Str(vValue) Else sFormat = Format(vValue, Pattern)
387 SF_Utils._ExitFunction(cstThisSub)
391 End Function
' ScriptForge.SF_PythonHelper.PyFormat
393 REM -----------------------------------------------------------------------------
394 Public Function PyGetGuiType() As Integer
395 ''' Convenient function to replicate GetGuiType() in Python scripts
396 ''' Args:
397 ''' Returns:
398 ''' The GetGuiType value
399 ''' Example: (Python code)
400 ''' MsgBox bas.GetGuiType()
402 Const cstThisSub =
"Basic.GetGuiType
"
403 Const cstSubArgs =
""
406 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
409 PyGetGuiType = GetGuiType()
413 SF_Utils._ExitFunction(cstThisSub)
415 End Function
' ScriptForge.SF_PythonHelper.PyGetGuiType
417 REM -----------------------------------------------------------------------------
418 Public Function PyGetSystemTicks() As Long
419 ''' Convenient function to replicate GetSystemTicks() in Python scripts
420 ''' Args:
421 ''' Returns:
422 ''' The GetSystemTicks value
423 ''' Example: (Python code)
424 ''' MsgBox bas.GetSystemTicks()
426 Const cstThisSub =
"Basic.GetSystemTicks
"
427 Const cstSubArgs =
""
430 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
433 PyGetSystemTicks = GetSystemTicks()
437 SF_Utils._ExitFunction(cstThisSub)
439 End Function
' ScriptForge.SF_PythonHelper.PyGetSystemTicks
441 REM -----------------------------------------------------------------------------
442 Public Function PyGlobalScope(ByVal Library As Variant) As Object
443 ''' Convenient function to replicate GlobalScope() in Python scripts
444 ''' Args:
445 ''' Library:
"Basic
" or
"Dialog
"
446 ''' Returns:
447 ''' The GlobalScope value
448 ''' Example: (Python code)
449 ''' MsgBox bas.GlobalScope.BasicLibraries()
451 Const cstThisSub =
"Basic.GlobalScope.BasicLibraries
" ' or DialogLibraries
452 Const cstSubArgs =
""
455 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
459 Case
"Basic
"
460 PyGlobalScope = GlobalScope.BasicLibraries()
461 Case
"Dialog
"
462 PyGlobalScope = GlobalScope.DialogLibraries()
467 SF_Utils._ExitFunction(cstThisSub)
469 End Function
' ScriptForge.SF_PythonHelper.PyGlobalScope
471 REM -----------------------------------------------------------------------------
472 Public Function PyInputBox(ByVal Msg As Variant _
473 , ByVal Title As Variant _
474 , ByVal Default As Variant _
475 , Optional ByVal XPosTwips As Variant _
476 , Optional ByVal YPosTwips As Variant _
478 ''' Convenient function to replicate InputBox() in Python scripts
479 ''' Args:
480 ''' Msg: String expression displayed as the message in the dialog box
481 ''' Title: String expression displayed in the title bar of the dialog box
482 ''' Default: String expression displayed in the text box as default if no other input is given
483 ''' XPosTwips: Integer expression that specifies the horizontal position of the dialog
484 ''' YPosTwips: Integer expression that specifies the vertical position of the dialog
485 ''' If XPosTwips and YPosTwips are omitted, the dialog is centered on the screen
486 ''' The position is specified in twips.
487 ''' Returns:
488 ''' The entered value or
"" if the user pressed the Cancel button
489 ''' Example: (Python code)
490 ''' a = bas.InputBox (
'Please enter a phrase:
',
'Dear User
')
492 Dim sInput As String
' Return value
493 Const cstThisSub =
"Basic.InputBox
"
494 Const cstSubArgs =
"msg, [title=
''], [default=
''], [xpostwips], [ypostwips]
"
496 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
497 sInput =
""
500 If IsMissing(YPosTwips) Then YPosTwips =
1
501 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
504 If IsMissing(XPosTwips) Then
505 sInput = InputBox(Msg, Title, Default)
507 sInput = InputBox(Msg, Title, Default, XPosTwips, YPosTwips)
512 SF_Utils._ExitFunction(cstThisSub)
516 End Function
' ScriptForge.SF_PythonHelper.PyInputBox
518 REM -----------------------------------------------------------------------------
519 Public Function PyMsgBox(ByVal Text As Variant _
520 , ByVal DialogType As Variant _
521 , ByVal DialogTitle As Variant _
523 ''' Convenient function to replicate MsgBox() in Python scripts
524 ''' Args:
525 ''' Text: String expression displayed as a message in the dialog box
526 ''' DialogType: Any integer expression that defines the number and type of buttons or icons displayed
527 ''' DialogTitle: String expression displayed in the title bar of the dialog
528 ''' Returns:
529 ''' The pressed button
530 ''' Example: (Python code)
531 ''' a = bas.MsgBox (
'Please press a button:
', bas.MB_EXCLAMATION,
'Dear User
')
533 Dim iMsg As Integer
' Return value
534 Const cstThisSub =
"Basic.MsgBox
"
535 Const cstSubArgs =
"text, [dialogtype=
0], [dialogtitle]
"
537 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
541 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
544 iMsg = MsgBox(Text, DialogType, DialogTitle)
548 SF_Utils._ExitFunction(cstThisSub)
552 End Function
' ScriptForge.SF_PythonHelper.PyMsgBox
554 REM ============================================================= PRIVATE METHODS
556 REM -----------------------------------------------------------------------------
557 Public Function _PythonDispatcher(ByRef BasicObject As Variant _
558 , ByVal CallType As Variant _
559 , ByVal Script As Variant _
560 , ParamArray Args() As Variant _
562 ''' Called from Python only
563 ''' The method calls the method Script associated with the BasicObject class or module
564 ''' with the given arguments
565 ''' The invocation of the method can be a Property Get, Property Let or a usual call
566 ''' NB: arguments and return values must not be
2D arrays
567 ''' The implementation intends to be as AGNOSTIC as possible in terms of objects nature and methods called
568 ''' The method returns the value effectively returned by the called component,
569 ''' completed with additional metadata. The whole is packaged in a
1D array.
570 ''' Args:
571 ''' BasicObject: a module or a class instance - May also be the reserved string:
"SF_Services
"
572 ''' CallType: one of the constants applicable to a CallByName statement + optional protocol flags
573 ''' Script: the name of the method or property
574 ''' Args: the arguments to pass to the method. Input arguments can contain symbolic constants for Null, Missing, etc.
575 ''' Returns:
576 ''' A
1D array:
577 ''' [
0] The returned value - scalar, object or
1D array
578 ''' [
1] The VarType() of the returned value
579 ''' Null, Empty and Nothing have different vartypes but return all None to Python
580 ''' Additionally, when array:
581 ''' [
2] Number of dimensions in Basic
582 ''' Additionally, when Basic object:
583 ''' [
2] Module (
1), Class instance (
2) or UNO (
3)
584 ''' [
3] The object
's ObjectType
585 ''' [
4] The object
's service name
586 ''' [
5] The object
's name
587 ''' When an error occurs Python receives None as a scalar. This determines the occurrence of a failure
589 Dim vReturn As Variant
' The value returned by the invoked property or method
590 Dim vReturnArray As Variant
' Return value
591 Dim vBasicObject As Variant
' Alias of BasicObject to avoid
"Object reference not set
" error
592 Dim iNbArgs As Integer
' Number of valid input arguments
593 Dim vArg As Variant
' Alias for a single argument
594 Dim vArgs() As Variant
' Alias for Args()
595 Dim sScript As String
' Argument of ExecuteBasicScript()
596 Dim vParams As Variant
' Array of arguments to pass to a ParamArray
597 Dim sObjectType As String
' Alias of object.ObjectType
598 Dim sServiceName As String
' Alias of BasicObject.ServiceName
599 Dim bBasicClass As Boolean
' True when BasicObject is a class
600 Dim sLibrary As String
' Library where the object belongs to
601 Dim bUno As Boolean
' Return value is a UNO object
602 Dim bDict As Boolean
' Return value is a Basic SF_Dictionary class instance
603 Dim oDict As Object
' SF_Dictionary class instance
604 Dim oObjDesc As Object
' _ObjectDescriptor type
605 Dim iDims As Integer
' # of dims of vReturn when array
606 Dim sess As Object : Set sess = ScriptForge.SF_Session
607 Dim i As Long, j As Long
609 ' Conventional special input or output values
610 Const cstNoArgs =
"+++NOARGS+++
", cstSymEmpty =
"+++EMPTY+++
", cstSymNull =
"+++NULL+++
", cstSymMissing =
"+++MISSING+++
"
612 ' https://support.office.com/en-us/article/CallByName-fonction-
49ce9475-c315-
4f13-
8d35-e98cfe98729a
613 ' Determines the CallType
614 Const vbGet =
2, vbLet =
4, vbMethod =
1, vbSet =
8
615 ' Protocol flags
616 Const cstPost =
16 ' Requires a hardcoded post-processing
617 Const cstDictArg =
32 ' May contain a Dictionary argument
618 Const cstDateArg =
64 ' May contain a date argument
619 Const cstDateRet =
128 ' Return value can be a date
620 Const cstUno =
256 ' Return value can be a UNO object
621 Const cstArgArray =
512 ' Any argument can be a
2D array
622 Const cstRetArray =
1024 ' Return value can be an array
623 Const cstObject =
2048 ' 1st argument is a Basic object when numeric
624 Const cstHardCode =
4096 ' Method must not be executed with CallByName()
625 ' Returned object nature
626 Const objMODULE =
1, objCLASS =
2, objDICT =
3, objUNO =
4
629 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
630 _PythonDispatcher = Null
632 ' Ignore Null basic objects (Null = Null or Nothing)
633 If IsNull(BasicObject) Or IsEmpty(BasicObject) Then GoTo Catch
635 ' Reinterpret arguments one by one into vArgs
636 ' - convert UNO dates/times
637 ' - identify conventional NoArgs/Empty/Null/Missing constants
638 ' - convert arrays of property values into Dictionary
642 If UBound(Args)
>=
0 Then
643 For i =
0 To UBound(Args)
645 ' Are there arguments ?
646 If i =
0 And VarType(vArg) = V_STRING Then
647 If vArg = cstNoArgs Then Exit For
649 ' Is
1st argument a reference to a Basic object ?
650 If i =
0 And (( CallType And cstObject ) = cstObject) And SF_Utils._VarTypeExt(vArg) = V_NUMERIC Then
651 If vArg
< 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
652 If vArg
> UBound(_SF_.PythonStorage) Then GoTo Catch
653 vArg = _SF_.PythonStorage(vArg)
654 ' Is argument a symbolic constant for Null, Empty, ... , or a date, or a dictionary ?
655 ElseIf VarType(vArg) = V_STRING Then
656 If Len(vArg) =
0 Then
657 ElseIf vArg = cstSymEmpty Then
659 ElseIf vArg = cstSymNull Then
661 ElseIf vArg = cstSymMissing Then
662 Exit For
' Next arguments must be missing also
664 ElseIf VarType(vArg) = V_OBJECT Then
665 If ( CallType And cstDateArg ) = cstDateArg Then vArg = CDateFromUnoDateTime(vArg)
666 ElseIf ( CallType And cstDictArg ) = cstDictArg Then
667 If IsArray(vArg) Then
668 If UBound(vArg)
>=
0 Then
669 If sess.UnoObjectType(vArg(
0)) =
"com.sun.star.beans.PropertyValue
" Then
670 ' Create a dictionary - keys in Python dicts are case-sensitive
671 Set oDict = CreateScriptService(
"ScriptForge.Dictionary
", True)
672 oDict.ImportFromPropertyValues(vArg, Overwrite := True)
678 iNbArgs = iNbArgs +
1
680 ReDim Preserve vArgs(iNbArgs)
681 vArgs(iNbArgs) = vArg
686 ' Dispatching strategy: based on next constraints
687 ' (
1) Bug https://bugs.documentfoundation.org/show_bug.cgi?id=
138155
688 ' The CallByName function fails when returning an array
689 ' (
2) Python has tuples and tuple of tuples, not
2D arrays
690 ' (
3) Passing
2D arrays through a script provider always transform it into a sequence of sequences
691 ' (
4) The CallByName function takes exclusive control on the targeted object up to its exit
692 ' (
5) A script provider returns a Basic Date variable as Empty
694 ' 1. All methods in any module are invoked with CallByName
695 ' 2. Properties in any service are got and set with obj.GetProperty/SetProperty(...)
697 ' 3. Methods in usual modules are called by ExecuteBasicScript() when they manipulate arrays
698 ' 4. Methods in class modules using a
2D array or returning arrays, or methods using ParamArray,
699 ''' are hardcoded as exceptions or are not implemented
700 ' 5. Due to constraint (
4), a predefined list of method calls must be hardcoded to avoid blocking use of CallByName
701 ' The concerned methods are flagged with cstHardCode
704 ' Initialize Python persistent storage at
1st call
705 If IsEmpty(.PythonStorage) Then ._InitPythonStorage()
706 ' Reset any error
708 ' Set Python trigger to manage signatures in error messages
709 .TriggeredByPython = True
712 Select case VarType(BasicObject)
714 ' Special entry for CreateScriptService()
715 vBasicObject = BasicObject
716 If vBasicObject =
"SF_Services
" Then
717 If UBound(vArgs) =
0 Then vParams = Array() Else vParams = SF_Array.Slice(vArgs,
1)
718 Select Case UBound(vParams)
719 Case -
1 : vReturn = SF_Services.CreateScriptService(vArgs(
0))
720 Case
0 : vReturn = SF_Services.CreateScriptService(vArgs(
0), vParams(
0))
721 Case
1 : vReturn = SF_Services.CreateScriptService(vArgs(
0), vParams(
0), vParams(
1))
722 Case
2 : vReturn = SF_Services.CreateScriptService(vArgs(
0), vParams(
0), vParams(
1), vParams(
2))
723 Case
3 : vReturn = SF_Services.CreateScriptService(vArgs(
0), vParams(
0), vParams(
1), vParams(
2), vParams(
3))
724 Case
4 : vReturn = SF_Services.CreateScriptService(vArgs(
0), vParams(
0), vParams(
1), vParams(
2), vParams(
3), vParams(
4))
727 If VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
728 vBasicObject = vReturn
729 sObjectType = vBasicObject.ObjectType
730 bBasicClass = ( Left(sObjectType,
3)
<> "SF_
" )
733 ' Implement dispatching strategy
735 If BasicObject
< 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
736 If BasicObject
> UBound(_SF_.PythonStorage) Then GoTo Catch
737 vBasicObject = _SF_.PythonStorage(BasicObject)
738 sObjectType = vBasicObject.ObjectType
739 sServiceName = vBasicObject.ServiceName
741 ' Basic modules have type =
"SF_*
"
742 bBasicClass = ( Left(sObjectType,
3)
<> "SF_
" )
743 sLibrary = Split(sServiceName,
".
")(
0)
745 ' Methods in standard modules are called by ExecuteBasicScript() when arrays are returned
746 If Not bBasicClass And (CallType And vbMethod) = vbMethod And (CallType And cstRetArray) = cstRetArray Then
747 sScript = sLibrary
& ".
" & sObjectType
& ".
" & Script
748 ' Force validation in targeted function, not in ExecuteBasicScript()
750 Select Case UBound(vArgs)
751 Case -
1 : vReturn = sess.ExecuteBasicScript(, sScript)
752 Case
0 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0))
753 Case
1 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1))
754 Case
2 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1), vArgs(
2))
755 Case
3 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3))
756 Case
4 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4))
757 Case
5 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5))
758 Case
6 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6))
759 Case
7 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7))
763 ' Properties in any service are got and set with obj.GetProperty/SetProperty(...)
764 ElseIf (CallType And vbGet) = vbGet Then
' In some cases (Calc ...) GetProperty may have an argument
765 If UBound(vArgs)
< 0 Then vReturn = vBasicObject.GetProperty(Script) Else vReturn = vBasicObject.GetProperty(Script, vArgs(
0))
766 ElseIf (CallType And vbLet) = vbLet Then
767 vReturn = vBasicObject.SetProperty(Script, vArgs(
0))
769 ' Methods in class modules using a
2D array or returning arrays are hardcoded as exceptions. Bug #
138155
770 ElseIf ((CallType And vbMethod) + (CallType And cstArgArray)) = vbMethod + cstArgArray Or _
771 ((CallType And vbMethod) + (CallType And cstRetArray)) = vbMethod + cstRetArray Then
772 If Script =
"Methods
" Then
773 vReturn = vBasicObject.Methods()
774 ElseIf Script =
"Properties
" Then
775 vReturn = vBasicObject.Properties()
777 Select Case sServiceName
778 Case
"SFDatabases.Database
"
779 If Script =
"GetRows
" Then vReturn = vBasicObject.GetRows(vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3))
780 Case
"SFDatabases.Dataset
"
781 If Script =
"GetRows
" Then vReturn = vBasicObject.GetRows(vArgs(
0), vArgs(
1))
782 Case
"SFDialogs.Dialog
"
783 If Script =
"Controls
" Then vReturn = vBasicObject.Controls(vArgs(
0))
784 Case
"SFDialogs.DialogControl
"
785 If Script =
"SetTableData
" Then vReturn = vBasicObject.SetTableData(vArgs(
0), vArgs(
1), vArgs(
2))
786 Case
"SFDocuments.Document
"
788 Case
"ContextMenus
" : vReturn = vBasicObject.ContextMenus(vArgs(
0), vArgs(
1))
789 Case
"Forms
" : vReturn = vBasicObject.Forms(vArgs(
0))
790 Case
"Styles
" : vReturn = vBasicObject.Styles(vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5))
791 Case
"Toolbars
" : vReturn = vBasicObject.Toolbars(vArgs(
0))
793 Case
"SFDocuments.Base
"
795 Case
"ContextMenus
" : vReturn = vBasicObject.ContextMenus(vArgs(
0), vArgs(
1))
796 Case
"FormDocuments
" : vReturn = vBasicObject.FormDocuments()
797 Case
"Forms
" : vReturn = vBasicObject.Forms(vArgs(
0), vArgs(
1))
798 Case
"Toolbars
" : vReturn = vBasicObject.Toolbars(vArgs(
0))
800 Case
"SFDocuments.Calc
"
802 Case
"Charts
" : vReturn = vBasicObject.Charts(vArgs(
0), vArgs(
1))
803 Case
"ContextMenus
" : vReturn = vBasicObject.ContextMenus(vArgs(
0), vArgs(
1))
804 Case
"Forms
" : vReturn = vBasicObject.Forms(vArgs(
0), vArgs(
1))
805 Case
"GetFormula
" : vReturn = vBasicObject.GetFormula(vArgs(
0))
806 Case
"GetValue
" : vReturn = vBasicObject.GetValue(vArgs(
0))
807 Case
"SetArray
" : vReturn = vBasicObject.SetArray(vArgs(
0), vArgs(
1))
808 Case
"SetFormula
" : vReturn = vBasicObject.SetFormula(vArgs(
0), vArgs(
1))
809 Case
"SetValue
" : vReturn = vBasicObject.SetValue(vArgs(
0), vArgs(
1))
810 Case
"Styles
" : vReturn = vBasicObject.Styles(vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5))
811 Case
"Toolbars
" : vReturn = vBasicObject.Toolbars(vArgs(
0))
813 Case
"SFDocuments.Form
"
815 Case
"Controls
" : vReturn = vBasicObject.Controls(vArgs(
0))
816 Case
"Subforms
" : vReturn = vBasicObject.Subforms(vArgs(
0))
818 Case
"SFDocuments.FormControl
"
819 If Script =
"Controls
" Then vReturn = vBasicObject.Controls(vArgs(
0))
820 Case
"SFDocuments.FormDocument
"
822 Case
"ContextMenus
" : vReturn = vBasicObject.ContextMenus(vArgs(
0), vArgs(
1))
823 Case
"Forms
" : vReturn = vBasicObject.Forms(vArgs(
0))
824 Case
"Toolbars
" : vReturn = vBasicObject.Toolbars(vArgs(
0))
826 Case
"SFDocuments.Writer
"
828 Case
"ContextMenus
" : vReturn = vBasicObject.ContextMenus(vArgs(
0), vArgs(
1))
829 Case
"Forms
" : vReturn = vBasicObject.Forms(vArgs(
0))
830 Case
"Styles
" : vReturn = vBasicObject.Styles(vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5))
831 Case
"Toolbars
" : vReturn = vBasicObject.Toolbars(vArgs(
0))
833 Case
"SFWidgets.Toolbar
"
835 Case
"ToolbarButtons
" : vReturn = vBasicObject.ToolbarButtons(vArgs(
0))
840 ' Specific methods in class modules may better not be executed with CallByName() because they do not return immediately
841 ElseIf bBasicClass And ((CallType And vbMethod) + (CallType And cstHardCode)) = vbMethod + cstHardCode Then
842 Select Case sServiceName
843 Case
"SFDialogs.Dialog
"
845 Case
"Execute
" : vReturn = vBasicObject.Execute(vArgs(
0))
849 ' Methods in all modules are invoked with CallByName
850 ElseIf ((CallType And vbMethod) = vbMethod) Then
851 Select Case UBound(vArgs)
852 ' Dirty alternatives to process usual and ParamArray cases
853 ' But, up to ... how many ?
854 ' - The OFFSETADDRESSERROR has
12 arguments
855 ' - The
".uno:DataSort
" command may have
14 property name-value pairs
856 Case -
1 : vReturn = CallByName(vBasicObject, Script, vbMethod)
857 Case
0 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0))
858 Case
1 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1))
859 Case
2 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2))
860 Case
3 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3))
861 Case
4 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4))
862 Case
5 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5))
863 Case
6 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6))
864 Case
7 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7))
865 Case
8 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
867 Case
9 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
868 , vArgs(
8), vArgs(
9))
869 Case
10 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
870 , vArgs(
8), vArgs(
9), vArgs(
10))
871 Case
11 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
872 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11))
873 Case
12,
13 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
874 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12))
875 Case
14,
15 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
876 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14))
877 Case
16,
17 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
878 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16))
879 Case
18,
19 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
880 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16), vArgs(
17), vArgs(
18))
881 Case
20,
21 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
882 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16), vArgs(
17), vArgs(
18) _
883 , vArgs(
19), vArgs(
20))
884 Case
22,
23 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
885 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16), vArgs(
17), vArgs(
18) _
886 , vArgs(
19), vArgs(
20), vArgs(
21), vArgs(
22))
887 Case
24,
25 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
888 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16), vArgs(
17), vArgs(
18) _
889 , vArgs(
19), vArgs(
20), vArgs(
21), vArgs(
22), vArgs(
23), vArgs(
24))
890 Case
26,
27 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
891 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16), vArgs(
17), vArgs(
18) _
892 , vArgs(
19), vArgs(
20), vArgs(
21), vArgs(
22), vArgs(
23), vArgs(
24), vArgs(
25), vArgs(
26))
893 Case
>=
28 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(
0), vArgs(
1), vArgs(
2), vArgs(
3), vArgs(
4), vArgs(
5), vArgs(
6), vArgs(
7) _
894 , vArgs(
8), vArgs(
9), vArgs(
10), vArgs(
11), vArgs(
12), vArgs(
13), vArgs(
14), vArgs(
15), vArgs(
16), vArgs(
17), vArgs(
18) _
895 , vArgs(
19), vArgs(
20), vArgs(
21), vArgs(
22), vArgs(
23), vArgs(
24), vArgs(
25), vArgs(
26), vArgs(
27), vArgs(
28))
899 ' Post processing
900 If (CallType And cstPost) = cstPost Then
901 If Script =
"Dispose
" Then
902 ' Special case: Dispose() must update the cache for class objects created in Python scripts
903 Set _SF_.PythonStorage(BasicObject) = Nothing
909 ' Format the returned array
910 vReturnArray = Array()
911 ' Distinguish: Basic object
916 If IsArray(vReturn) Then
917 ReDim vReturnArray(
0 To
2)
918 iDims = SF_Array.CountDims(vReturn)
919 ' Replace dates by UNO format
921 For i = LBound(vReturn) To UBound(vReturn)
922 If VarType(vReturn(i)) = V_DATE Then vReturn(i) = CDateToUnoDateTime(vReturn(i))
924 ElseIf iDims =
2 Then
925 For i = LBound(vReturn,
1) To UBound(vReturn,
1)
926 For j = LBound(vReturn,
2) To UBound(vReturn,
2)
927 If VarType(vReturn(i, j)) = V_DATE Then vReturn(i, j) = CDateToUnoDateTime(vReturn(i, j))
931 vReturnArray(
0) = vReturn
' 2D arrays are flattened by the script provider when returning to Python
932 vReturnArray(
1) = VarType(vReturn)
933 vReturnArray(
2) = iDims
934 ElseIf VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
935 ' Uno or not Uno ?
937 If (CallType And cstUno) = cstUno Then
' UNO considered only when pre-announced in CallType
938 Set oObjDesc = SF_Utils._VarTypeObj(vReturn)
939 bUno = ( oObjDesc.iVarType = V_UNOOBJECT )
942 ReDim vReturnArray(
0 To
2)
943 Set vReturnArray(
0) = vReturn
945 ReDim vReturnArray(
0 To
5)
946 bDict = ( vReturn.ObjectType =
"DICTIONARY
" )
948 vReturnArray(
0) = vReturn.ConvertToPropertyValues()
950 vReturnArray(
0) = _SF_._AddToPythonSTorage(vReturn)
953 vReturnArray(
1) = V_OBJECT
955 Case bUno : vReturnArray(
2) = objUNO
956 Case bDict : vReturnArray(
2) = objDICT
957 Case bBasicClass : vReturnArray(
2) = objCLASS
958 Case Else : vReturnArray(
2) = objMODULE
961 vReturnArray(
3) = vReturn.ObjectType
962 vReturnArray(
4) = vReturn.ServiceName
963 vReturnArray(
5) =
""
964 If vReturn.ObjectType
<> "SF_CalcReference
" And Not bDict Then
' Calc references are implemented as a Type ... End Type data structure
965 If SF_Array.Contains(vReturn.Properties(),
"Name
", SortOrder :=
"ASC
") Then vReturnArray(
5) = vReturn.Name
968 Else
' Scalar or Nothing
969 ReDim vReturnArray(
0 To
1)
970 If VarType(vReturn) = V_DATE Then vReturnArray(
0) = CDateToUnoDateTime(vReturn) Else vReturnArray(
0) = vReturn
971 vReturnArray(
1) = VarType(vReturn)
974 ' Tests with non-modal dialogs and sleeping (time.sleep) Python processes show
975 ' a more fluid reactivity when next statement is present, at a minimal cost.
978 _PythonDispatcher = vReturnArray
981 _SF_.TriggeredByPython = False
' Reset normal state
985 End Function
' ScriptForge.SF_PythonHelper._PythonDispatcher
987 REM -----------------------------------------------------------------------------
988 Private Function _Repr() As String
989 ''' Convert the Basic instance to a readable string, typically for debugging purposes (DebugPrint ...)
990 ''' Args:
991 ''' Return:
992 ''' "[PythonHelper]
"
994 _Repr =
"[PythonHelper]
"
996 End Function
' ScriptForge.SF_PythonHelper._Repr
998 REM ================================================= END OF SCRIPTFORGE.SF_PythonHelper