file-online-preview/office-plugin/windows-office/share/basic/SFDocuments/SF_Document.xba

1010 lines
44 KiB
Java
Raw Normal View History

2021-06-23 02:26:22 +00:00
<?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_Document" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
REM === The SFDocuments library is one of the associated libraries. ===
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_Document
&apos;&apos;&apos; ===========
&apos;&apos;&apos;
&apos;&apos;&apos; The SFDocuments library gathers a number of methods and properties making easy
&apos;&apos;&apos; the management and several manipulations of LibreOffice documents
&apos;&apos;&apos;
&apos;&apos;&apos; Some methods are generic for all types of documents: they are combined in the
&apos;&apos;&apos; current SF_Document module
&apos;&apos;&apos; - saving, closing documents
&apos;&apos;&apos; - accessing their standard or custom properties
&apos;&apos;&apos; Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Writer, ...
&apos;&apos;&apos;
&apos;&apos;&apos; To workaround the absence of class inheritance in LibreOffice Basic, some redundancy is necessary
&apos;&apos;&apos; Each subclass MUST implement also the generic methods and properties, even if they only call
&apos;&apos;&apos; the parent methods and properties implemented below
&apos;&apos;&apos; They should also duplicate some generic private members as a subset of their own set of members
&apos;&apos;&apos;
&apos;&apos;&apos; The current module is closely related to the &quot;UI&quot; and &quot;FileSystem&quot; services
&apos;&apos;&apos; of the ScriptForge library
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation examples:
&apos;&apos;&apos; 1) From the UI service
&apos;&apos;&apos; Dim ui As Object, oDoc As Object
&apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
&apos;&apos;&apos; Set oDoc = ui.GetDocument(&quot;Untitled 1&quot;)
&apos;&apos;&apos; &apos; or Set oDoc = ui.CreateDocument(&quot;Calc&quot;, ...)
&apos;&apos;&apos; &apos; or Set oDoc = ui.OpenDocument(&quot;C:\Me\MyFile.odt&quot;)
&apos;&apos;&apos; 2) Directly if the document is already opened
&apos;&apos;&apos; Dim oDoc As Object
&apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.Document&quot;, &quot;Untitled 1&quot;) &apos; Default = ActiveWindow
&apos;&apos;&apos; &apos; The substring &quot;SFDocuments.&quot; in the service name is optional
&apos;&apos;&apos;
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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
Private Const DOCUMENTDEADERROR = &quot;DOCUMENTDEADERROR&quot;
Private Const DOCUMENTSAVEERROR = &quot;DOCUMENTSAVEERROR&quot;
Private Const DOCUMENTSAVEASERROR = &quot;DOCUMENTSAVEASERROR&quot;
Private Const DOCUMENTREADONLYERROR = &quot;DOCUMENTREADONLYERROR&quot;
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be DOCUMENT
Private ServiceName As String
&apos; Window description
Private _Component As Object &apos; com.sun.star.lang.XComponent
Private _Frame As Object &apos; com.sun.star.comp.framework.Frame
Private _WindowName As String &apos; Object Name
Private _WindowTitle As String &apos; Only mean to identify new documents
Private _WindowFileName As String &apos; URL of file name
Private _DocumentType As String &apos; Writer, Calc, ...
&apos; Properties (work variables - real properties could have been set manually by user)
Private _DocumentProperties As Object &apos; Dictionary of document properties
Private _CustomProperties As Object &apos; Dictionary of custom properties
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;DOCUMENT&quot;
ServiceName = &quot;SFDocuments.Document&quot;
Set _Component = Nothing
Set _Frame = Nothing
_WindowName = &quot;&quot;
_WindowTitle = &quot;&quot;
_WindowFileName = &quot;&quot;
_DocumentType = &quot;&quot;
Set _DocumentProperties = Nothing
Set _CustomProperties = Nothing
End Sub &apos; SFDocuments.SF_Document Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; SFDocuments.SF_Document Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; SFDocuments.SF_Document Explicit Destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get CustomProperties() As Variant
&apos;&apos;&apos; Returns a dictionary of all custom properties of the document
CustomProperties = _PropertyGet(&quot;CustomProperties&quot;)
End Property &apos; SFDocuments.SF_Document.CustomProperties
REM -----------------------------------------------------------------------------
Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
&apos;&apos;&apos; Sets the updatable custom properties
&apos;&apos;&apos; The argument is a dictionary
Dim vPropertyValues As Variant &apos; Array of com.sun.star.beans.PropertyValue
Dim vCustomProperties As Variant &apos; Alias of argument
Dim oUserdefinedProperties As Object &apos; Custom properties object
Dim vOldPropertyValues As Variant &apos; Array of (to remove) existing user defined properties
Dim oProperty As Object &apos; Single com.sun.star.beans.PropertyValues
Dim sProperty As String &apos; Property name
Dim vKeys As Variant &apos; Array of dictionary keys
Dim vItems As Variant &apos; Array of dictionary items
Dim vValue As Variant &apos; Value to store in property
Dim iAttribute As Integer &apos; com.sun.star.beans.PropertyAttribute.REMOVEABLE
Dim i As Long
Const cstThisSub = &quot;SFDocuments.Document.setCustomProperties&quot;
Const cstSubArgs = &quot;CustomProperties&quot;
On Local Error GoTo Catch
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive(True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(pvCustomProperties, &quot;CustomProperties&quot;, ScriptForge.V_OBJECT, , , &quot;DICTIONARY&quot;) Then GoTo Finally
End If
Try:
Set oUserDefinedProperties = _Component.getDocumentProperties().UserDefinedProperties
Set vCustomProperties = pvCustomProperties &apos; To avoid &quot;Object variable not set&quot; error
With vCustomProperties
&apos; All existing custom properties must first be removed to avoid type conflicts
vOldPropertyValues = oUserDefinedProperties.getPropertyValues
For Each oProperty In vOldPropertyValues
sProperty = oProperty.Name
oUserDefinedProperties.removeProperty(sProperty)
Next oProperty
&apos; Insert new properties one by one after type adjustment (dates, arrays, numbers)
vKeys = .Keys
vItems = .Items
iAttribute = com.sun.star.beans.PropertyAttribute.REMOVEABLE
For i = 0 To UBound(vKeys)
If VarType(vItems(i)) = V_DATE Then
vValue = ScriptForge.SF_Utils._CDateToUnoDate(vItems(i))
ElseIf IsArray(vItems(i)) Then
vValue = Null
ElseIf ScriptForge.SF_Utils._VarTypeExt(vItems(i)) = ScriptForge.V_NUMERIC Then
vValue = CreateUnoValue(&quot;double&quot;, vItems(i))
Else
vValue = vItems(i)
End If
oUserDefinedProperties.addProperty(vKeys(i), iAttribute, vValue)
Next i
&apos; Declare the document as changed
_Component.setModified(True)
End With
&apos; Reload custom properties in current object instance
_PropertyGet(&quot;CustomProperties&quot;)
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Property
Catch:
GoTo Finally
End Property &apos; SFDocuments.SF_Document.CustomProperties
REM -----------------------------------------------------------------------------
Property Get Description() As Variant
&apos;&apos;&apos; Returns the updatable document property Description
Description = _PropertyGet(&quot;Description&quot;)
End Property &apos; SFDocuments.SF_Document.Description
REM -----------------------------------------------------------------------------
Property Let Description(Optional ByVal pvDescription As Variant)
&apos;&apos;&apos; Sets the updatable document property Description
&apos;&apos;&apos; If multilined, separate lines by &quot;\n&quot; escape sequence or by hard breaks
Dim sDescription As String &apos; Alias of pvDescription
Const cstThisSub = &quot;SFDocuments.Document.setDescription&quot;
Const cstSubArgs = &quot;Description&quot;
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive(True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(pvDescription, &quot;Description&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Update in UNO component object and in current instance
sDescription = Replace(pvDescription, &quot;\n&quot;, ScriptForge.SF_String.sfNEWLINE)
_Component.DocumentProperties.Description = sDescription
If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Description&quot;, sdescription)
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Property
End Property &apos; SFDocuments.SF_Document.Description
REM -----------------------------------------------------------------------------
Property Get DocumentProperties() As Variant
&apos;&apos;&apos; Returns a dictionary of all standard document properties, custom properties are excluded
DocumentProperties = _PropertyGet(&quot;DocumentProperties&quot;)
End Property &apos; SFDocuments.SF_Document.DocumentProperties
REM -----------------------------------------------------------------------------
Property Get DocumentType() As String
&apos;&apos;&apos; Returns &quot;Base&quot;, &quot;Calc&quot;, &quot;Draw&quot;, ... or &quot;Writer&quot;
DocumentType = _PropertyGet(&quot;DocumentType&quot;)
End Property &apos; SFDocuments.SF_Document.DocumentType
REM -----------------------------------------------------------------------------
Property Get IsBase() As Boolean
IsBase = _PropertyGet(&quot;IsBase&quot;)
End Property &apos; SFDocuments.SF_Document.IsBase
REM -----------------------------------------------------------------------------
Property Get IsCalc() As Boolean
IsCalc = _PropertyGet(&quot;IsCalc&quot;)
End Property &apos; SFDocuments.SF_Document.IsCalc
REM -----------------------------------------------------------------------------
Property Get IsDraw() As Boolean
IsDraw = _PropertyGet(&quot;IsDraw&quot;)
End Property &apos; SFDocuments.SF_Document.IsDraw
REM -----------------------------------------------------------------------------
Property Get IsImpress() As Boolean
IsImpress = _PropertyGet(&quot;IsImpress&quot;)
End Property &apos; SFDocuments.SF_Document.IsImpress
REM -----------------------------------------------------------------------------
Property Get IsMath() As Boolean
IsMath = _PropertyGet(&quot;IsMath&quot;)
End Property &apos; SFDocuments.SF_Document.IsMath
REM -----------------------------------------------------------------------------
Property Get IsWriter() As Boolean
IsWriter = _PropertyGet(&quot;IsWriter&quot;)
End Property &apos; SFDocuments.SF_Document.IsWriter
REM -----------------------------------------------------------------------------
Property Get Keywords() As Variant
&apos;&apos;&apos; Returns the updatable document property Keywords
Keywords = _PropertyGet(&quot;Keywords&quot;)
End Property &apos; SFDocuments.SF_Document.Keywords
REM -----------------------------------------------------------------------------
Property Let Keywords(Optional ByVal pvKeywords As Variant)
&apos;&apos;&apos; Sets the updatable document property Keywords
Dim vKeywords As Variant &apos; Alias of pvKeywords
Const cstThisSub = &quot;SFDocuments.Document.setKeywords&quot;
Const cstSubArgs = &quot;Keywords&quot;
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive(True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(pvKeywords, &quot;Keywords&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Update in UNO component object and in current instance
vKeywords = ScriptForge.SF_Array.TrimArray(Split(pvKeywords, &quot;,&quot;))
_Component.DocumentProperties.Keywords = vKeywords
If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Keywords&quot;, Join(vKeywords, &quot;, &quot;))
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Property
End Property &apos; SFDocuments.SF_Document.Keywords
REM -----------------------------------------------------------------------------
Property Get Readonly() As Boolean
&apos;&apos;&apos; Returns True if the document must not be modified
Readonly = _PropertyGet(&quot;Readonly&quot;)
End Property &apos; SFDocuments.SF_Document.Readonly
REM -----------------------------------------------------------------------------
Property Get Subject() As Variant
&apos;&apos;&apos; Returns the updatable document property Subject
Subject = _PropertyGet(&quot;Subject&quot;)
End Property &apos; SFDocuments.SF_Document.Subject
REM -----------------------------------------------------------------------------
Property Let Subject(Optional ByVal pvSubject As Variant)
&apos;&apos;&apos; Sets the updatable document property Subject
Const cstThisSub = &quot;SFDocuments.Document.setSubject&quot;
Const cstSubArgs = &quot;Subject&quot;
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive(True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(pvSubject, &quot;Subject&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Update in UNO component object and in current instance
_Component.DocumentProperties.Subject = pvSubject
If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Subject&quot;, pvSubject)
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Property
End Property &apos; SFDocuments.SF_Document.Subject
REM -----------------------------------------------------------------------------
Property Get Title() As Variant
&apos;&apos;&apos; Returns the updatable document property Title
Title = _PropertyGet(&quot;Title&quot;)
End Property &apos; SFDocuments.SF_Document.Title
REM -----------------------------------------------------------------------------
Property Let Title(Optional ByVal pvTitle As Variant)
&apos;&apos;&apos; Sets the updatable document property Title
Const cstThisSub = &quot;SFDocuments.Document.setTitle&quot;
Const cstSubArgs = &quot;Title&quot;
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive(True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(pvTitle, &quot;Title&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Update in UNO component object and in current instance
_Component.DocumentProperties.Title = pvTitle
If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Title&quot;, pvTitle)
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Property
End Property &apos; SFDocuments.SF_Document.Title
REM -----------------------------------------------------------------------------
Property Get XComponent() As Variant
&apos;&apos;&apos; Returns the com.sun.star.lang.XComponent UNO object representing the document
XComponent = _PropertyGet(&quot;XComponent&quot;)
End Property &apos; SFDocuments.SF_Document.XComponent
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function Activate() As Boolean
&apos;&apos;&apos; Make the current document active
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if the document could be activated
&apos;&apos;&apos; Otherwise, there is no change in the actual user interface
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oDoc.Activate()
Dim bActivate As Boolean &apos; Return value
Dim oContainer As Object &apos; com.sun.star.awt.XWindow
Const cstThisSub = &quot;SFDocuments.Document.Activate&quot;
Const cstSubArgs = &quot;&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bActivate = False
Check:
ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsStillAlive() Then GoTo Finally
Try:
Set oContainer = _Frame.ContainerWindow
With oContainer
If .isVisible() = False Then .setVisible(True)
.IsMinimized = False
.setFocus()
.toFront() &apos; Force window change in Linux
Wait 1 &apos; Bypass desynchro issue in Linux
End With
bActivate = True
Finally:
Activate = bActivate
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Document.Activate
REM -----------------------------------------------------------------------------
Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
&apos;&apos;&apos; Close the document. Does nothing if the document is already closed
&apos;&apos;&apos; regardless of how the document was closed, manually or by program
&apos;&apos;&apos; Args:
&apos;&apos;&apos; SaveAsk: If True (default), the user is invited to confirm or not the writing of the changes on disk
&apos;&apos;&apos; No effect if the document was not modified
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; False if the user declined to close
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; If oDoc.CloseDocument() Then
&apos;&apos;&apos; &apos; ...
Dim bClosed As Boolean &apos; return value
Dim oDispatch &apos; com.sun.star.frame.DispatchHelper
Const cstThisSub = &quot;SFDocuments.Document.CloseDocument&quot;
Const cstSubArgs = &quot;[SaveAsk=True]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bClosed = False
Check:
If IsMissing(SaveAsk) Or IsEmpty(SaveAsk) Then SaveAsk = True
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, V_BOOLEAN) Then GoTo Finally
End If
Try:
If SaveAsk And _Component.IsModified Then &apos; Execute closure with the File/Close menu command
Activate()
RunCommand(&quot;CloseDoc&quot;)
bClosed = _IsStillAlive(, False) &apos; Do not raise error
Else
_Frame.close(True)
_Frame.dispose()
bClosed = True
End If
Finally:
If bClosed Then Dispose()
CloseDocument = bClosed
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Document.CloseDocument
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; If the property does not exist, returns Null
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; see the exceptions of the individual properties
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myModel.GetProperty(&quot;MyProperty&quot;)
Const cstThisSub = &quot;SFDocuments.Document.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Document.GetProperty
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Model service as an array
Methods = Array( _
&quot;Activate&quot; _
, &quot;CloseDocument&quot; _
, &quot;RunCommand&quot; _
, &quot;Save&quot; _
, &quot;SaveAs&quot; _
, &quot;SaveCopyAs&quot; _
)
End Function &apos; SFDocuments.SF_Document.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;CustomProperties&quot; _
, &quot;Description&quot; _
, &quot;DocumentProperties&quot; _
, &quot;DocumentType&quot; _
, &quot;IsBase&quot; _
, &quot;IsCalc&quot; _
, &quot;IsDraw &quot; _
, &quot;IsImpress&quot; _
, &quot;IsMath&quot; _
, &quot;IsWriter&quot; _
, &quot;Keywords&quot; _
, &quot;Readonly&quot; _
, &quot;Subject&quot; _
, &quot;Title&quot; _
, &quot;XComponent&quot; _
)
End Function &apos; SFDocuments.SF_Document.Properties
REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
&apos;&apos;&apos; Run on the document the given menu command. The command is executed without arguments
&apos;&apos;&apos; A few typical commands:
&apos;&apos;&apos; Save, SaveAs, ExportToPDF, SetDocumentProperties, Undo, Copy, Paste, ...
&apos;&apos;&apos; Dozens can be found in the directory $install/share/config/soffice.cfg/modules
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Command: Case-sensitive. The command itself is not checked.
&apos;&apos;&apos; If nothing happens, then the command is probably wrong
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oDoc.RunCommand(&quot;About&quot;)
Dim oDispatch &apos; com.sun.star.frame.DispatchHelper
Const cstThisSub = &quot;SFDocuments.Document.RunCommand&quot;
Const cstSubArgs = &quot;Command&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Finally
End If
Try:
Set oDispatch = ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
oDispatch.executeDispatch(_Frame, &quot;.uno:&quot; &amp; Command, &quot;&quot;, 0, Array())
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; SFDocuments.SF_Document.RunCommand
REM -----------------------------------------------------------------------------
Public Function Save() As Boolean
&apos;&apos;&apos; Store the document to the file location from which it was loaded
&apos;&apos;&apos; Ignored if the document was not modified
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; False if the document could not be saved
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DOCUMENTSAVEERROR The file has been opened readonly or was opened as new and was not yet saved
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; If Not oDoc.Save() Then
&apos;&apos;&apos; &apos; ...
Dim bSaved As Boolean &apos; return value
Const cstThisSub = &quot;SFDocuments.Document.Save&quot;
Const cstSubArgs = &quot;&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bSaved = False
Check:
ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsStillAlive() Then GoTo Finally
bSaved = False
Try:
With _Component
If .isReadonly() Or Not .hasLocation() Then GoTo CatchReadonly
If .IsModified() Then
.store()
bSaved = True
End If
End With
Finally:
Save = bSaved
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchReadonly:
ScriptForge.SF_Exception.RaiseFatal(DOCUMENTSAVEERROR, &quot;FileName&quot;, _FileIdent())
GoTo Finally
End Function &apos; SFDocuments.SF_Document.Save
REM -----------------------------------------------------------------------------
Public Function SaveAs(Optional ByVal FileName As Variant _
, Optional ByVal Overwrite As Variant _
, Optional ByVal Password As Variant _
, Optional ByVal FilterName As Variant _
, Optional ByVal FilterOptions As Variant _
) As Boolean
&apos;&apos;&apos; Store the document to the given file location
&apos;&apos;&apos; The new location becomes the new file name on which simple Save method calls will be applied
&apos;&apos;&apos; Args:
&apos;&apos;&apos; FileName: Identifies the file where to save. It must follow the SF_FileSystem.FileNaming notation
&apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
&apos;&apos;&apos; Password: Use to protect the document
&apos;&apos;&apos; FilterName: the name of a filter that should be used for saving the document
&apos;&apos;&apos; If present, the filter must exist
&apos;&apos;&apos; FilterOptions: an optional string of options associated with the filter
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; False if the document could not be saved
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DOCUMENTSAVEASERROR The destination has its readonly attribute set or overwriting rejected
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oDoc.SaveAs(&quot;C:\Me\Copy2.odt&quot;, Overwrite := True)
Dim bSaved As Boolean &apos; return value
Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
Dim sFile As String &apos; Alias of FileName
Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
Dim FSO As Object &apos; SF_FileSystem
Const cstThisSub = &quot;SFDocuments.Document.SaveAs&quot;
Const cstSubArgs = &quot;FileName, [Overwrite=False], [Password=&quot;&quot;&quot;&quot;], [FilterName=&quot;&quot;&quot;&quot;], [FilterOptions=&quot;&quot;&quot;&quot;]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
bSaved = False
Check:
If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
If IsMissing(FilterName) Or IsEmpty(FilterName) Then FilterName = &quot;&quot;
If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = &quot;&quot;
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterName, &quot;FilterName&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterOptions, &quot;FilterOptions&quot;, V_STRING) Then GoTo Finally
End If
&apos; Check that the filter exists
If Len(FilterName) &gt; 0 Then
Set oFilterFactory = ScriptForge.SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
If Not oFilterFactory.hasByName(FilterName) Then GoTo CatchError
End If
&apos; Check destination file overwriting
Set FSO = CreateScriptService(&quot;FileSystem&quot;)
sFile = FSO._ConvertToUrl(FileName)
If FSO.FileExists(FileName) Then
If Overwrite = False Then GoTo CatchError
Set oSfa = ScriptForge.SF_Utils._GetUNOService(&quot;FileAccess&quot;)
If oSfa.isReadonly(sFile) Then GoTo CatchError
End If
Try:
&apos; Setup arguments
If Len(Password) + Len(FilterName) = 0 Then
vProperties = Array()
Else
vProperties = Array( _
ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, FilterName) _
, ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterOptions&quot;, FilterOptions) _
)
If Len(Password) &gt; 0 Then &apos; Password is to add only if &lt;&gt; &quot;&quot; !?
vProperties = ScriptForge.SF_Array.Append(vproperties _
, ScriptForge.SF_Utils._MakePropertyValue(&quot;Password&quot;, Password))
End If
End If
_Component.StoreAsURL(sFile, vProperties)
&apos; Remind the new file name
_WindowFileName = sFile
_WindowName = FSO.GetName(FileName)
bSaved = True
Finally:
SaveAs = bSaved
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchError:
ScriptForge.SF_Exception.RaiseFatal(DOCUMENTSAVEASERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite _
, &quot;FilterName&quot;, FilterName)
GoTo Finally
End Function &apos; SFDocuments.SF_Document.SaveAs
REM -----------------------------------------------------------------------------
Public Function SaveCopyAs(Optional ByVal FileName As Variant _
, Optional ByVal Overwrite As Variant _
, Optional ByVal Password As Variant _
, Optional ByVal FilterName As Variant _
, Optional ByVal FilterOptions As Variant _
) As Boolean
&apos;&apos;&apos; Store a copy or export the document to the given file location
&apos;&apos;&apos; The actual location is unchanged
&apos;&apos;&apos; Args:
&apos;&apos;&apos; FileName: Identifies the file where to save. It must follow the SF_FileSystem.FileNaming notation
&apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
&apos;&apos;&apos; Password: Use to protect the document
&apos;&apos;&apos; FilterName: the name of a filter that should be used for saving the document
&apos;&apos;&apos; If present, the filter must exist
&apos;&apos;&apos; FilterOptions: an optional string of options associated with the filter
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; False if the document could not be saved
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DOCUMENTSAVEASERROR The destination has its readonly attribute set or overwriting rejected
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; oDoc.SaveCopyAs(&quot;C:\Me\Copy2.odt&quot;, Overwrite := True)
Dim bSaved As Boolean &apos; return value
Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
Dim sFile As String &apos; Alias of FileName
Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
Dim FSO As Object &apos; SF_FileSystem
Const cstThisSub = &quot;SFDocuments.Document.SaveCopyAs&quot;
Const cstSubArgs = &quot;FileName, [Overwrite=False], [Password=&quot;&quot;&quot;&quot;], [FilterName=&quot;&quot;&quot;&quot;], [FilterOptions=&quot;&quot;&quot;&quot;]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
bSaved = False
Check:
If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
If IsMissing(FilterName) Or IsEmpty(FilterName) Then FilterName = &quot;&quot;
If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = &quot;&quot;
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterName, &quot;FilterName&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterOptions, &quot;FilterOptions&quot;, V_STRING) Then GoTo Finally
End If
&apos; Check that the filter exists
If Len(FilterName) &gt; 0 Then
Set oFilterFactory = ScriptForge.SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
If Not oFilterFactory.hasByName(FilterName) Then GoTo CatchError
End If
&apos; Check destination file overwriting
Set FSO = CreateScriptService(&quot;FileSystem&quot;)
sFile = FSO._ConvertToUrl(FileName)
If FSO.FileExists(FileName) Then
If Overwrite = False Then GoTo CatchError
Set oSfa = ScriptForge.SF_Utils._GetUNOService(&quot;FileAccess&quot;)
If oSfa.isReadonly(sFile) Then GoTo CatchError
End If
Try:
&apos; Setup arguments
If Len(Password) + Len(FilterName) = 0 Then
vProperties = Array()
Else
vProperties = Array( _
ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, FilterName) _
, ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterOptions&quot;, FilterOptions) _
)
If Len(Password) &gt; 0 Then &apos; Password is to add only if &lt;&gt; &quot;&quot; !?
vProperties = ScriptForge.SF_Array.Append(vproperties _
, ScriptForge.SF_Utils._MakePropertyValue(&quot;Password&quot;, Password))
End If
End If
_Component.StoreToURL(sFile, vProperties)
bSaved = True
Finally:
SaveCopyAs = bSaved
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchError:
ScriptForge.SF_Exception.RaiseFatal(DOCUMENTSAVEASERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite _
, &quot;FilterName&quot;, FilterName)
GoTo Finally
End Function &apos; SFDocuments.SF_Document.SaveCopyAs
REM -----------------------------------------------------------------------------
Private Function SetProperty(Optional ByVal psProperty As String _
, Optional ByVal pvValue As Variant _
) As Boolean
&apos;&apos;&apos; Set the new value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
&apos;&apos;&apos; pvValue: the new value of the given property
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful
Dim bSet As Boolean &apos; Return value
Static oSession As Object &apos; Alias of SF_Session
Dim cstThisSub As String
Const cstSubArgs = &quot;Value&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bSet = False
cstThisSub = &quot;SFDocuments.Document.set&quot; &amp; psProperty
If IsMissing(pvValue) Then pvValue = Empty
&apos;ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Validation done in Property Lets
If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
bSet = True
Select Case UCase(psProperty)
Case UCase(&quot;CustomProperties&quot;)
CustomProperties = pvValue
Case UCase(&quot;Description&quot;)
Description = pvValue
Case UCase(&quot;Keywords&quot;)
Keywords = pvValue
Case UCase(&quot;Subject&quot;)
Subject = pvValue
Case UCase(&quot;Title&quot;)
Title = pvValue
Case Else
bSet = False
End Select
Finally:
SetProperty = bSet
&apos;ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; SFDocuments.SF_Document.SetProperty
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _FileIdent() As String
&apos;&apos;&apos; Returns a file identification from the information that is currently available
&apos;&apos;&apos; Useful e.g. for display in error messages
_FileIdent = Iif(Len(_WindowFileName) &gt; 0, SF_FileSystem._ConvertFromUrl(_WindowFileName), _WindowTitle)
End Function &apos; SFDocuments.SF_Document._FileIdent
REM -----------------------------------------------------------------------------
Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
, Optional ByVal pbError As Boolean _
) As Boolean
&apos;&apos;&apos; Returns True if the document has not been closed manually or incidentally since the last use
&apos;&apos;&apos; If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pbForUpdate: if True (default = False), check additionally if document is open for editing
&apos;&apos;&apos; pbError: if True (default), raise a fatal error
Dim bAlive As Boolean &apos; Return value
Dim sFileName As String &apos; File identification used to display error message
On Local Error GoTo Catch &apos; Anticipate DisposedException errors or alike
If IsMissing(pbForUpdate) Then pbForUpdate = False
If IsMissing(pbError) Then pbError = True
Try:
&apos; Check existence of document
bAlive = Not IsNull(_Frame)
If bAlive Then bAlive = Not IsNull(_Component)
If bAlive Then bAlive = Not IsNull(_Component.CurrentController)
&apos; Check document is not read only
If bAlive And pbForUpdate Then
If _Component.isreadonly() Then GoTo CatchReadonly
End If
Finally:
_IsStillAlive = bAlive
Exit Function
Catch:
bAlive = False
On Error GoTo 0
sFileName = _FileIdent()
Dispose()
If pbError Then ScriptForge.SF_Exception.RaiseFatal(DOCUMENTDEADERROR, sFileName)
GoTo Finally
CatchReadonly:
bAlive = False
If pbError Then ScriptForge.SF_Exception.RaiseFatal(DOCUMENTREADONLYERROR, &quot;Document&quot;, _FileIdent())
GoTo Finally
End Function &apos; SFDocuments.SF_Document._IsStillAlive
REM -----------------------------------------------------------------------------
Private Sub _LoadDocumentProperties()
&apos;&apos;&apos; Create dictionary with document properties as entries/ Custom properties are excluded
&apos;&apos;&apos; Document is presumed still alive
&apos;&apos;&apos; Special values:
&apos;&apos;&apos; Only valid dates are taken
&apos;&apos;&apos; Statistics are exploded in subitems. Subitems are specific to document type
&apos;&apos;&apos; Keywords are joined
&apos;&apos;&apos; Language is aligned on L10N convention la-CO
Dim oProperties As Object &apos; Document properties
Dim vNamedValue As Variant &apos; com.sun.star.beans.NamedValue
If IsNull(_DocumentProperties) Then
Set oProperties = _Component.getDocumentProperties
Set _DocumentProperties = CreateScriptService(&quot;Dictionary&quot;)
With _DocumentProperties
.Add(&quot;Author&quot;, oProperties.Author)
.Add(&quot;AutoloadSecs&quot;, oProperties.AutoloadSecs)
.Add(&quot;AutoloadURL&quot;, oProperties.AutoloadURL)
If oProperties.CreationDate.Year &gt; 0 Then .Add(&quot;CreationDate&quot;, CDateFromUnoDateTime(oProperties.CreationDate))
.Add(&quot;DefaultTarget&quot;, oProperties.DefaultTarget)
.Add(&quot;Description&quot;, oProperties.Description) &apos; The description can be multiline
&apos; DocumentStatistics : number and names of statistics depend on document type
For Each vNamedValue In oProperties.DocumentStatistics
.Add(vNamedValue.Name, vNamedValue.Value)
Next vNamedValue
.Add(&quot;EditingDuration&quot;, oProperties.EditingDuration)
.Add(&quot;Generator&quot;, oProperties.Generator)
.Add(&quot;Keywords&quot;, Join(oProperties.Keywords, &quot;, &quot;))
.Add(&quot;Language&quot;, oProperties.Language.Language &amp; Iif(Len(oProperties.Language.Country) &gt; 0, &quot;-&quot; &amp; oProperties.Language.Country, &quot;&quot;))
If oProperties.ModificationDate.Year &gt; 0 Then .Add(&quot;ModificationDate&quot;, CDateFromUnoDateTime(oProperties.ModificationDate))
If oProperties.PrintDate.Year &gt; 0 Then .Add(&quot;PrintDate&quot;, CDateFromUnoDateTime(oProperties.PrintDate))
.Add(&quot;PrintedBy&quot;, oProperties.PrintedBy)
.Add(&quot;Subject&quot;, oProperties.Subject)
If oProperties.TemplateDate.Year &gt; 0 Then .Add(&quot;TemplateDate&quot;, CDateFromUnoDateTime(oProperties.TemplateDate))
.Add(&quot;TemplateName&quot;, oProperties.TemplateName)
.Add(&quot;TemplateURL&quot;, oProperties.TemplateURL)
.Add(&quot;Title&quot;, oProperties.Title)
End With
End If
End Sub &apos; SFDocuments.SF_Document._LoadDocumentProperties
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim oProperties As Object &apos; Document or Custom properties
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;
_PropertyGet = False
Select Case _DocumentType
Case &quot;Calc&quot; : cstThisSub = &quot;SFDocuments.SF_&quot; &amp; _DocumentType &amp; &quot;.get&quot; &amp; psProperty
Case Else : cstThisSub = &quot;SFDocuments.SF_Document.get&quot; &amp; psProperty
End Select
ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsStillAlive() Then GoTo Finally
Select Case psProperty
Case &quot;CustomProperties&quot;
_CustomProperties = CreateScriptService(&quot;Dictionary&quot;) &apos; Always reload as updates could have been done manually by user
_CustomProperties.ImportFromPropertyValues(_Component.getDocumentProperties().UserDefinedProperties.getPropertyValues)
_PropertyGet = _CustomProperties
Case &quot;Description&quot;
_PropertyGet = _Component.DocumentProperties.Description
Case &quot;DocumentProperties&quot;
_LoadDocumentProperties() &apos; Always reload as updates could have been done manually by user
Set _PropertyGet = _DocumentProperties
Case &quot;DocumentType&quot;
_PropertyGet = _DocumentType
Case &quot;IsBase&quot;, &quot;IsCalc&quot;, &quot;IsDraw&quot;, &quot;IsImpress&quot;, &quot;IsMath&quot;, &quot;IsWriter&quot;
_PropertyGet = ( Mid(psProperty, 3) = _DocumentType )
Case &quot;Keywords&quot;
_PropertyGet = Join(_Component.DocumentProperties.Keywords, &quot;, &quot;)
Case &quot;Readonly&quot;
_PropertyGet = _Component.isReadonly()
Case &quot;Subject&quot;
_PropertyGet = _Component.DocumentProperties.Subject
Case &quot;Title&quot;
_PropertyGet = _Component.DocumentProperties.Title
Case &quot;XComponent&quot;
Set _PropertyGet = _Component
Case Else
_PropertyGet = Null
End Select
Finally:
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; SFDocuments.SF_Document._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the SF_Document instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[DOCUMENT]: Type - File&quot;
_Repr = &quot;[Document]: &quot; &amp; _DocumentType &amp; &quot; - &quot; &amp; _FileIdent()
End Function &apos; SFDocuments.SF_Document._Repr
REM ============================================ END OF SFDOCUMENTS.SF_DOCUMENT
</script:module>