Files
odfstudio/wizards/source/scriptforge/SF_Timer.xba
T
Jean-Pierre Ledure 61c6321c76 ScriptForge Timer uses Basic Now function
The durations in the Timer service
are measured with a precision of
the millisecond.

Thanks to tdf#161469 the Basic Now()
function provides sub-seconds precision
since LO 25.2.

Hence the use of the Calc NOW() function
is replaced in the Basic code by the
more immediately available Basic Now()
equivalent.

No impact on existing user scripts.
Documentation is unchanged.

Change-Id: Ia3b0f07918d9b9a9e96f62aaa5ce3862a2b48579
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194070
Tested-by: Jenkins
Reviewed-by: Jean-Pierre Ledure <jp@ledure.be>
2025-11-16 17:14:07 +01:00

466 lines
17 KiB
XML

<?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_Timer" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
REM === Full documentation is available on https://help.libreoffice.org/ ===
REM =======================================================================================================================
Option Compatible
Option ClassModule
Option Explicit
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos; SF_Timer
&apos;&apos;&apos; ========
&apos;&apos;&apos; Class for management of scripts execution performance
&apos;&apos;&apos; A Timer measures durations. It can be suspended, resumed, restarted
&apos;&apos;&apos; Duration properties are expressed in seconds with a precision of 3 decimal digits
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation example:
&apos;&apos;&apos; Dim myTimer As Variant
&apos;&apos;&apos; myTimer = CreateScriptService(&quot;Timer&quot;)
&apos;&apos;&apos; myTimer = CreateScriptService(&quot;Timer&quot;, True) &apos; =&gt; To start timer immediately
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_timer.html?DbPAR=BASIC
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
REM ================================================================== EXCEPTIONS
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be &quot;TIMER&quot;
Private ServiceName As String
Private _TimerStatus As Integer &apos; inactive, started, suspended or stopped
Private _StartTime As Double &apos; Moment when timer started, restarted
Private _EndTime As Double &apos; Moment when timer stopped
Private _SuspendTime As Double &apos; Moment when timer suspended
Private _SuspendDuration As Double &apos; Duration of suspended status as a difference of times
REM ============================================================ MODULE CONSTANTS
Private Const STATUSINACTIVE = 0
Private Const STATUSSTARTED = 1
Private Const STATUSSUSPENDED = 2
Private Const STATUSSTOPPED = 3
Private Const DSECOND As Double = 1 / (24 * 60 * 60) &apos; Duration of 1 second as compared to 1.0 = 1 day
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;TIMER&quot;
ServiceName = &quot;ScriptForge.Timer&quot;
_TimerStatus = STATUSINACTIVE
_StartTime = 0
_EndTime = 0
_SuspendTime = 0
_SuspendDuration = 0
End Sub &apos; ScriptForge.SF_Timer Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_Timer Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Timer Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Public Function Duration() As Double
&apos;&apos;&apos; Returns the actual (out of suspensions) time elapsed since start or between start and stop
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Double expressing the duration in seconds
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.Duration returns 1.234 (1 sec, 234 ms)
Duration = _PropertyGet(&quot;Duration&quot;)
End Function &apos; ScriptForge.SF_Timer.Duration
REM -----------------------------------------------------------------------------
Property Get IsStarted() As Boolean
&apos;&apos;&apos; Returns True if timer is started or suspended
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.IsStarted
IsStarted = _PropertyGet(&quot;IsStarted&quot;)
End Property &apos; ScriptForge.SF_Timer.IsStarted
REM -----------------------------------------------------------------------------
Property Get IsSuspended() As Boolean
&apos;&apos;&apos; Returns True if timer is started and suspended
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.IsSuspended
IsSuspended = _PropertyGet(&quot;IsSuspended&quot;)
End Property &apos; ScriptForge.SF_Timer.IsSuspended
REM -----------------------------------------------------------------------------
Public Function SuspendDuration() As Double
&apos;&apos;&apos; Returns the actual time elapsed while suspended since start or between start and stop
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Double expressing the duration in seconds
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.SuspendDuration returns 1.234 (1 sec, 234 ms)
SuspendDuration = _PropertyGet(&quot;SuspendDuration&quot;)
End Function &apos; ScriptForge.SF_Timer.SuspendDuration
REM -----------------------------------------------------------------------------
Public Function TotalDuration() As Double
&apos;&apos;&apos; Returns the actual time elapsed (including suspensions) since start or between start and stop
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Double expressing the duration in seconds
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.TotalDuration returns 1.234 (1 sec, 234 ms)
TotalDuration = _PropertyGet(&quot;TotalDuration&quot;)
End Function &apos; ScriptForge.SF_Timer.TotalDuration
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function Continue() As Boolean
&apos;&apos;&apos; Halt suspension of a running timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is not suspended
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Continue()
Const cstThisSub = &quot;Timer.Continue&quot;
Const cstSubArgs = &quot;&quot;
Check:
Continue = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSSUSPENDED Then
_TimerStatus = STATUSSTARTED
_SuspendDuration = _SuspendDuration + _Now() - _SuspendTime
_SuspendTime = 0
Continue = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Continue
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.GetProperty(&quot;Duration&quot;)
Const cstThisSub = &quot;Timer.GetProperty&quot;
Const cstSubArgs = &quot;PropertyName&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Timer.Properties
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list or methods of the Timer class as an array
Methods = Array( _
&quot;Continue&quot; _
, &quot;Restart&quot; _
, &quot;Start&quot; _
, &quot;Suspend&quot; _
, &quot;Terminate&quot; _
)
End Function &apos; ScriptForge.SF_Timer.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Timer class as an array
Properties = Array( _
&quot;Duration&quot; _
, &quot;IsStarted&quot; _
, &quot;IsSuspended&quot; _
, &quot;SuspendDuration&quot; _
, &quot;TotalDuration&quot; _
)
End Function &apos; ScriptForge.SF_Timer.Properties
REM -----------------------------------------------------------------------------
Public Function Restart() As Boolean
&apos;&apos;&apos; Terminate the timer and restart a new clean timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is inactive
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Restart()
Const cstThisSub = &quot;Timer.Restart&quot;
Const cstSubArgs = &quot;&quot;
Check:
Restart = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus &lt;&gt; STATUSINACTIVE Then
If _TimerStatus &lt;&gt; STATUSSTOPPED Then Terminate()
Start()
Restart = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Restart
REM -----------------------------------------------------------------------------
Public Function SetProperty(Optional ByVal PropertyName As Variant _
, Optional ByRef Value As Variant _
) As Boolean
&apos;&apos;&apos; Set a new value to the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Value: its new value
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;Timer.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
SetProperty = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
Select Case UCase(PropertyName)
Case Else
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Timer.SetProperty
REM -----------------------------------------------------------------------------
Public Function Start() As Boolean
&apos;&apos;&apos; Start a new clean timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is already started
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Start()
Const cstThisSub = &quot;Timer.Start&quot;
Const cstSubArgs = &quot;&quot;
Check:
Start = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSINACTIVE Or _TimerStatus = STATUSSTOPPED Then
_TimerStatus = STATUSSTARTED
_StartTime = _Now()
_EndTime = 0
_SuspendTime = 0
_SuspendDuration = 0
Start = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Start
REM -----------------------------------------------------------------------------
Public Function Suspend() As Boolean
&apos;&apos;&apos; Suspend a running timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is not started or already suspended
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Suspend()
Const cstThisSub = &quot;Timer.Suspend&quot;
Const cstSubArgs = &quot;&quot;
Check:
Suspend = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSSTARTED Then
_TimerStatus = STATUSSUSPENDED
_SuspendTime = _Now()
Suspend = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Suspend
REM -----------------------------------------------------------------------------
Public Function Terminate() As Boolean
&apos;&apos;&apos; Terminate a running timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is neither started nor suspended
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Terminate()
Const cstThisSub = &quot;Timer.Terminate&quot;
Const cstSubArgs = &quot;&quot;
Check:
Terminate = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED Then
If _TimerSTatus = STATUSSUSPENDED Then Continue()
_TimerStatus = STATUSSTOPPED
_EndTime = _Now()
Terminate = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Terminate
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _Now() As Double
&apos;&apos;&apos; Returns the current date and time with a required precision of at least the millisecond.
&apos;&apos;&apos; Uses the Basic NOW() (i.o. Calc&apos;s) function as it provides the required precision since LO 25.2 (tdf#161469).
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual time as a number
&apos;&apos;&apos; The integer part represents the date, the decimal part represents the time
_Now = CDbl(Now())
End Function &apos; ScriptForge.SF_Timer._Now
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String)
&apos;&apos;&apos; Return the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim dDuration As Double &apos; Computed duration
Dim cstThisSub As String
Dim cstSubArgs As String
cstThisSub = &quot;Timer.get&quot; &amp; psProperty
cstSubArgs = &quot;&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case UCase(psProperty)
Case UCase(&quot;Duration&quot;)
Select Case _TimerStatus
Case STATUSINACTIVE : dDuration = 0.0
Case STATUSSTARTED
dDuration = _Now() - _StartTime - _SuspendDuration
Case STATUSSUSPENDED
dDuration = _SuspendTime - _StartTime - _SuspendDuration
Case STATUSSTOPPED
dDuration = _EndTime - _StartTime - _SuspendDuration
End Select
_PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
Case UCase(&quot;IsStarted&quot;)
_PropertyGet = CBool( _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED )
Case UCase(&quot;IsSuspended&quot;)
_PropertyGet = CBool( _TimerStatus = STATUSSUSPENDED )
Case UCase(&quot;SuspendDuration&quot;)
Select Case _TimerStatus
Case STATUSINACTIVE : dDuration = 0.0
Case STATUSSTARTED, STATUSSTOPPED
dDuration = _SuspendDuration
Case STATUSSUSPENDED
dDuration = _Now() - _SuspendTime + _SuspendDuration
End Select
_PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
Case UCase(&quot;TotalDuration&quot;)
Select Case _TimerStatus
Case STATUSINACTIVE : dDuration = 0.0
Case STATUSSTARTED, STATUSSUSPENDED
dDuration = _Now() - _StartTime
Case STATUSSTOPPED
dDuration = _EndTime - _StartTime
End Select
_PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the Timer instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[Timer] Duration:xxx.yyy
Const cstTimer = &quot;[Timer] Duration: &quot;
Const cstMaxLength = 50 &apos; Maximum length for items
_Repr = cstTimer &amp; Replace(SF_Utils._Repr(Duration), &quot;.&quot;, &quot;&quot;&quot;&quot;)
End Function &apos; ScriptForge.SF_Timer._Repr
REM ============================================ END OF SCRIPTFORGE.SF_TIMER
</script:module>