tdf#150880: Add support for WRAPROWS function
[LibreOffice.git] / wizards / source / sfdocuments / SF_Calc.xba
blob7bd5e4e8d2517ec7e89104a5143c6e504ce053a7
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_Calc" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
4 REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
5 REM === The SFDocuments library is one of the associated libraries. ===
6 REM === Full documentation is available on https://help.libreoffice.org/ ===
7 REM =======================================================================================================================
9 Option Compatible
10 Option ClassModule
12 Option Explicit
14 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
15 &apos;&apos;&apos; SF_Calc
16 &apos;&apos;&apos; =======
17 &apos;&apos;&apos;
18 &apos;&apos;&apos; The SFDocuments library gathers a number of methods and properties making easy
19 &apos;&apos;&apos; managing and manipulating LibreOffice documents
20 &apos;&apos;&apos;
21 &apos;&apos;&apos; Some methods are generic for all types of documents: they are combined in the SF_Document module.
22 &apos;&apos;&apos; Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Base, ...
23 &apos;&apos;&apos;
24 &apos;&apos;&apos; To workaround the absence of class inheritance in LibreOffice Basic, some redundancy is necessary
25 &apos;&apos;&apos; Each subclass MUST implement also the generic methods and properties, even if they only call
26 &apos;&apos;&apos; the parent methods and properties.
27 &apos;&apos;&apos; They should also duplicate some generic private members as a subset of their own set of members
28 &apos;&apos;&apos;
29 &apos;&apos;&apos; The SF_Calc module is focused on :
30 &apos;&apos;&apos; - management (copy, insert, move, ...) of sheets within a Calc document
31 &apos;&apos;&apos; - exchange of data between Basic data structures and Calc ranges of values
32 &apos;&apos;&apos; - copying and importing massive amounts of data
33 &apos;&apos;&apos;
34 &apos;&apos;&apos; The current module is closely related to the &quot;UI&quot; service of the ScriptForge library
35 &apos;&apos;&apos;
36 &apos;&apos;&apos; Service invocation examples:
37 &apos;&apos;&apos; 1) From the UI service
38 &apos;&apos;&apos; Dim ui As Object, oDoc As Object
39 &apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
40 &apos;&apos;&apos; Set oDoc = ui.CreateDocument(&quot;Calc&quot;, ...)
41 &apos;&apos;&apos; &apos; or Set oDoc = ui.OpenDocument(&quot;C:\Me\MyFile.ods&quot;)
42 &apos;&apos;&apos; 2) Directly if the document is already opened
43 &apos;&apos;&apos; Dim oDoc As Object
44 &apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.Calc&quot;, &quot;Untitled 1&quot;) &apos; Default = ActiveWindow
45 &apos;&apos;&apos; &apos; or Set oDoc = CreateScriptService(&quot;SFDocuments.Calc&quot;, &quot;Untitled 1&quot;) &apos; Untitled 1 is presumed a Calc document
46 &apos;&apos;&apos; &apos; The substring &quot;SFDocuments.&quot; in the service name is optional
47 &apos;&apos;&apos;
48 &apos;&apos;&apos; Definitions:
49 &apos;&apos;&apos;
50 &apos;&apos;&apos; Many methods require a &quot;Sheet&quot; or a &quot;Range&quot; as argument. (NB: a single cell is considered as a special case of a Range)
51 &apos;&apos;&apos; Usually, within a specific Calc instance, sheets and ranges are given as a string: &quot;SheetX&quot; and &quot;D2:F6&quot;
52 &apos;&apos;&apos; Multiple ranges are not supported in this context.
53 &apos;&apos;&apos; Additionally, the .Sheet and .Range methods return a reference that may be used
54 &apos;&apos;&apos; as argument of a method called from another instance of the Calc service
55 &apos;&apos;&apos; Example:
56 &apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\FileA.ods&quot;, Hidden := True, ReadOnly := True)
57 &apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\FileB.ods&quot;)
58 &apos;&apos;&apos; oDocB.CopyToRange(oDocA.Range(&quot;SheetX.D4:F8&quot;), &quot;D2:F6&quot;) &apos; CopyToRange(source, target)
59 &apos;&apos;&apos;
60 &apos;&apos;&apos; Sheet: the sheet name as a string or an object produced by .Sheet()
61 &apos;&apos;&apos; &quot;~&quot; = current sheet
62 &apos;&apos;&apos; Range: a string designating a set of contiguous cells located in a sheet of the current instance
63 &apos;&apos;&apos; &quot;~&quot; = current selection (if multiple selections, its 1st component)
64 &apos;&apos;&apos; or an object produced by .Range()
65 &apos;&apos;&apos; The sheet name is optional (default = active sheet). Surrounding quotes and $ signs are optional
66 &apos;&apos;&apos; ~.~, ~ The current selection in the active sheet
67 &apos;&apos;&apos; $&apos;SheetX&apos;.D2 or $D$2 A single cell
68 &apos;&apos;&apos; $SheetX.D2:F6, D2:D10 Multiple cells
69 &apos;&apos;&apos; $&apos;SheetX&apos;.A:A or 3:5 All cells in the same column or row up to the last active cell
70 &apos;&apos;&apos; SheetX.* All cells up to the last active cell
71 &apos;&apos;&apos; myRange A range name at spreadsheet level
72 &apos;&apos;&apos; ~.yourRange, SheetX.someRange A range name at sheet level
73 &apos;&apos;&apos; myDoc.Range(&quot;SheetX.D2:F6&quot;)
74 &apos;&apos;&apos; A range within the sheet SheetX in file associated with the myDoc Calc instance
75 &apos;&apos;&apos;
76 &apos;&apos;&apos; Several methods may receive a &quot;FilterFormula&quot; as argument.
77 &apos;&apos;&apos; A FilterFormula may be associated with a FilterScope: &quot;row&quot;, &quot;column&quot; or &quot;cell&quot;.
78 &apos;&apos;&apos; These arguments determine on which rows/columns/cells of a range the method should be applied
79 &apos;&apos;&apos; Examples:
80 &apos;&apos;&apos; oDoc.ClearAll(&quot;A1:J10&quot;, FilterFormula := &quot;=(A1&lt;=0)&quot;, FilterScope := &quot;CELL&quot;) &apos; Clear all negative values
81 &apos;&apos;&apos; oDoc.ClearAll(&quot;SheetX.A1:J10&quot;, &quot;=SUM(SheetX.A1:A10)&gt;100&quot;, &quot;COLUMN&quot;) &apos; Clear all columns whose sum is greater than 500
82 &apos;&apos;&apos;
83 &apos;&apos;&apos; FilterFormula: a Calc formula that returns TRUE or FALSE
84 &apos;&apos;&apos; the formula is expressed in terms of
85 &apos;&apos;&apos; - the top-left cell of the range when FilterScope = &quot;CELL&quot;
86 &apos;&apos;&apos; - the topmost row of the range when FilterScope = &quot;ROW&quot;
87 &apos;&apos;&apos; - the leftmost column of the range when FilterScope = &quot;COLUMN&quot;
88 &apos;&apos;&apos; relative and absolute references will be interpreted correctly
89 &apos;&apos;&apos; FilterScope: the way the formula is applied, once by row, by column, or by individual cell
90 &apos;&apos;&apos;
91 &apos;&apos;&apos; Detailed user documentation:
92 &apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_calc.html?DbPAR=BASIC
93 &apos;&apos;&apos;
94 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
96 REM ================================================================== EXCEPTIONS
98 Private Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot;
99 Private Const BASEDOCUMENTOPENERROR = &quot;BASEDOCUMENTOPENERROR&quot;
100 Private Const CALCADDRESSERROR = &quot;CALCADDRESSERROR&quot;
101 Private Const DUPLICATESHEETERROR = &quot;DUPLICATESHEETERROR&quot;
102 Private Const OFFSETADDRESSERROR = &quot;OFFSETADDRESSERROR&quot;
103 Private Const CALCFORMNOTFOUNDERROR = &quot;CALCFORMNOTFOUNDERROR&quot;
104 Private Const DUPLICATECHARTERROR = &quot;DUPLICATECHARTERROR&quot;
105 Private Const RANGEEXPORTERROR = &quot;RANGEEXPORTERROR&quot;
107 REM ============================================================= PRIVATE MEMBERS
109 Private [Me] As Object
110 Private [_Super] As Object &apos; Document superclass, which the current instance is a subclass of
111 Private ObjectType As String &apos; Must be CALC
112 Private ServiceName As String
114 &apos; Window component
115 Private _Component As Object &apos; com.sun.star.lang.XComponent
117 Type _Address
118 ObjectType As String &apos; Must be &quot;SF_CalcReference&quot;
119 ServiceName As String &apos; Must be &quot;SFDocuments.CalcReference&quot;
120 RawAddress As String
121 Component As Object &apos; com.sun.star.lang.XComponent
122 SheetName As String
123 SheetIndex As Integer
124 RangeName As String
125 Height As Long
126 Width As Long
127 XSpreadSheet As Object &apos; com.sun.star.sheet.XSpreadsheet
128 XCellRange As Object &apos; com.sun.star.table.XCellRange
129 End Type
131 Private _LastParsedAddress As Object &apos; _Address type - parsed ranges are cached
133 REM ============================================================ MODULE CONSTANTS
135 Private Const cstSHEET = 1
136 Private Const cstRANGE = 2
138 Private Const MAXCOLS = 2^14 &apos; Max number of columns in a sheet
139 Private Const MAXROWS = 2^20 &apos; Max number of rows in a sheet
141 Private Const CALCREFERENCE = &quot;SF_CalcReference&quot; &apos; Object type of _Address
142 Private Const SERVICEREFERENCE = &quot;SFDocuments.CalcReference&quot;
143 &apos; Service name of _Address (used in Python)
145 Private Const ISCALCFORM = 2 &apos; Form is stored in a Calc document
147 Private Const cstSPECIALCHARS = &quot; `~!@#$%^&amp;()-_=+{}|;,&lt;.&gt;&quot;&quot;&quot;
148 &apos; Presence of a special character forces surrounding the sheet name with single quotes in absolute addresses
151 REM ====================================================== CONSTRUCTOR/DESTRUCTOR
153 REM -----------------------------------------------------------------------------
154 Private Sub Class_Initialize()
155 Set [Me] = Nothing
156 Set [_Super] = Nothing
157 ObjectType = &quot;CALC&quot;
158 ServiceName = &quot;SFDocuments.Calc&quot;
159 Set _Component = Nothing
160 Set _LastParsedAddress = Nothing
161 End Sub &apos; SFDocuments.SF_Calc Constructor
163 REM -----------------------------------------------------------------------------
164 Private Sub Class_Terminate()
165 Call Class_Initialize()
166 End Sub &apos; SFDocuments.SF_Calc Destructor
168 REM -----------------------------------------------------------------------------
169 Public Function Dispose() As Variant
170 If Not IsNull([_Super]) Then Set [_Super] = [_Super].Dispose()
171 Call Class_Terminate()
172 Set Dispose = Nothing
173 End Function &apos; SFDocuments.SF_Calc Explicit Destructor
175 REM ================================================================== PROPERTIES
177 REM -----------------------------------------------------------------------------
178 Property Get CurrentSelection() As Variant
179 &apos;&apos;&apos; Returns as a string the currently selected range or as an array the list of the currently selected ranges
180 CurrentSelection = _PropertyGet(&quot;CurrentSelection&quot;)
181 End Property &apos; SFDocuments.SF_Calc.CurrentSelection (get)
183 REM -----------------------------------------------------------------------------
184 Property Let CurrentSelection(Optional ByVal pvSelection As Variant)
185 &apos;&apos;&apos; Set the selection to a single or a multiple range
186 &apos;&apos;&apos; The argument is a string or an array of strings
188 Dim sRange As String &apos; A single selection
189 Dim oCellRanges As Object &apos; com.sun.star.sheet.SheetCellRanges
190 Dim vRangeAddresses As Variant &apos; Array of com.sun.star.table.CellRangeAddress
191 Dim i As Long
192 Const cstThisSub = &quot;SFDocuments.Calc.setCurrentSelection&quot;
193 Const cstSubArgs = &quot;Selection&quot;
195 On Local Error GoTo Catch
197 Check:
198 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
199 If Not _IsStillAlive(True) Then GoTo Finally
200 If IsArray(pvSelection) Then
201 If Not ScriptForge.SF_Utils._ValidateArray(pvSelection, &quot;pvSelection&quot;, 1, V_STRING, True) Then GoTo Finally
202 Else
203 If Not ScriptForge.SF_Utils._Validate(pvSelection, &quot;pvSelection&quot;, V_STRING) Then GoTo Finally
204 End If
205 End If
207 Try:
208 If IsArray(pvSelection) Then
209 Set oCellRanges = _Component.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
210 vRangeAddresses = Array()
211 ReDim vRangeAddresses(0 To UBound(pvSelection))
212 For i = 0 To UBound(pvSelection)
213 vRangeAddresses(i) = Range(pvSelection(i)).XCellRange.RangeAddress
214 Next i
215 oCellRanges.addRangeAddresses(vRangeAddresses, False)
216 _Component.CurrentController.select(oCellRanges)
217 Else
218 _Component.CurrentController.select(_ParseAddress(pvSelection).XCellRange)
219 End If
221 Finally:
222 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
223 Exit Property
224 Catch:
225 GoTo Finally
226 End Property &apos; SFDocuments.SF_Calc.CurrentSelection (let)
228 REM -----------------------------------------------------------------------------
229 Property Get FirstCell(Optional ByVal RangeName As Variant) As String
230 &apos;&apos;&apos; Returns the First used cell in a given range or sheet
231 &apos;&apos;&apos; When the argument is a sheet it will always return the &quot;sheet.$A$1&quot; cell
232 FirstCell = _PropertyGet(&quot;FirstCell&quot;, RangeName)
233 End Property &apos; SFDocuments.SF_Calc.FirstCell
235 REM -----------------------------------------------------------------------------
236 Property Get FirstColumn(Optional ByVal RangeName As Variant) As Long
237 &apos;&apos;&apos; Returns the leftmost column in a given sheet or range
238 &apos;&apos;&apos; When the argument is a sheet it will always return 1
239 FirstColumn = _PropertyGet(&quot;FirstColumn&quot;, RangeName)
240 End Property &apos; SFDocuments.SF_Calc.FirstColumn
242 REM -----------------------------------------------------------------------------
243 Property Get FirstRow(Optional ByVal RangeName As Variant) As Long
244 &apos;&apos;&apos; Returns the First used column in a given range
245 &apos;&apos;&apos; When the argument is a sheet it will always return 1
246 FirstRow = _PropertyGet(&quot;FirstRow&quot;, RangeName)
247 End Property &apos; SFDocuments.SF_Calc.FirstRow
249 REM -----------------------------------------------------------------------------
250 Property Get Height(Optional ByVal RangeName As Variant) As Long
251 &apos;&apos;&apos; Returns the height in # of rows of the given range
252 Height = _PropertyGet(&quot;Height&quot;, RangeName)
253 End Property &apos; SFDocuments.SF_Calc.Height
255 REM -----------------------------------------------------------------------------
256 Property Get LastCell(Optional ByVal RangeName As Variant) As String
257 &apos;&apos;&apos; Returns the last used cell in a given sheet or range
258 LastCell = _PropertyGet(&quot;LastCell&quot;, RangeName)
259 End Property &apos; SFDocuments.SF_Calc.LastCell
261 REM -----------------------------------------------------------------------------
262 Property Get LastColumn(Optional ByVal RangeName As Variant) As Long
263 &apos;&apos;&apos; Returns the last used column in a given sheet
264 LastColumn = _PropertyGet(&quot;LastColumn&quot;, RangeName)
265 End Property &apos; SFDocuments.SF_Calc.LastColumn
267 REM -----------------------------------------------------------------------------
268 Property Get LastRow(Optional ByVal RangeName As Variant) As Long
269 &apos;&apos;&apos; Returns the last used column in a given sheet
270 LastRow = _PropertyGet(&quot;LastRow&quot;, RangeName)
271 End Property &apos; SFDocuments.SF_Calc.LastRow
273 REM -----------------------------------------------------------------------------
274 Property Get Range(Optional ByVal RangeName As Variant) As Variant
275 &apos;&apos;&apos; Returns a (internal) range object
276 Range = _PropertyGet(&quot;Range&quot;, RangeName)
277 End Property &apos; SFDocuments.SF_Calc.Range
279 REM -----------------------------------------------------------------------------
280 Property Get Region(Optional ByVal RangeName As Variant) As String
281 &apos;&apos;&apos; Returns the smallest area as a range string that contains the given range
282 &apos;&apos;&apos; and which is completely surrounded with empty cells
283 Region = _PropertyGet(&quot;Region&quot;, RangeName)
284 End Property &apos; SFDocuments.SF_Calc.Region
286 REM -----------------------------------------------------------------------------
287 Property Get Sheet(Optional ByVal SheetName As Variant) As Variant
288 &apos;&apos;&apos; Returns a (internal) sheet object
289 Sheet = _PropertyGet(&quot;Sheet&quot;, SheetName)
290 End Property &apos; SFDocuments.SF_Calc.Sheet
292 REM -----------------------------------------------------------------------------
293 Property Get SheetName(Optional ByVal RangeName As Variant) As String
294 &apos;&apos;&apos; Returns the sheet name part of a range
295 SheetName = _PropertyGet(&quot;SheetName&quot;, RangeName)
296 End Property &apos; SFDocuments.SF_Calc.SheetName
298 REM -----------------------------------------------------------------------------
299 Property Get Sheets() As Variant
300 &apos;&apos;&apos; Returns an array listing the existing sheet names
301 Sheets = _PropertyGet(&quot;Sheets&quot;)
302 End Property &apos; SFDocuments.SF_Calc.Sheets
304 REM -----------------------------------------------------------------------------
305 Property Get Width(Optional ByVal RangeName As Variant) As Long
306 &apos;&apos;&apos; Returns the width in # of columns of the given range
307 Width = _PropertyGet(&quot;Width&quot;, RangeName)
308 End Property &apos; SFDocuments.SF_Calc.Width
310 REM -----------------------------------------------------------------------------
311 Property Get XCellRange(Optional ByVal RangeName As Variant) As Variant
312 &apos;&apos;&apos; Returns a UNO object of type com.sun.star.Table.CellRange
313 XCellRange = _PropertyGet(&quot;XCellRange&quot;, RangeName)
314 End Property &apos; SFDocuments.SF_Calc.XCellRange
316 REM -----------------------------------------------------------------------------
317 Property Get XRectangle(Optional ByVal RangeName As Variant) As Variant
318 &apos;&apos;&apos; Returns a UNO structure of type com.sun.star.awt.Rectangle
319 &apos;&apos;&apos; describing the area in pixels on the screen where the range is located.
320 &apos;&apos;&apos; Useful in the context of running mouse events and widgets like popup menus
321 XRectangle = _PropertyGet(&quot;XRectangle&quot;, RangeName)
322 End Property &apos; SFDocuments.SF_Calc.XRectangle
324 REM -----------------------------------------------------------------------------
325 Property Get XSheetCellCursor(Optional ByVal RangeName As Variant) As Variant
326 &apos;&apos;&apos; Returns a UNO object of type com.sun.star.sheet.XSheetCellCursor
327 &apos;&apos; After having moved the cursor (gotoNext(), ...) the resulting range can be got
328 &apos;&apos;&apos; back as a string with the cursor.AbsoluteName UNO property.
329 XSheetCellCursor = _PropertyGet(&quot;XSheetCellCursor&quot;, RangeName)
330 End Property &apos; SFDocuments.SF_Calc.XSheetCellCursor
332 REM -----------------------------------------------------------------------------
333 Property Get XSpreadsheet(Optional ByVal SheetName As Variant) As Variant
334 &apos;&apos;&apos; Returns a UNO object of type com.sun.star.sheet.XSpreadsheet
335 XSpreadsheet = _PropertyGet(&quot;XSpreadsheet&quot;, SheetName)
336 End Property &apos; SFDocuments.SF_Calc.XSpreadsheet
338 REM ===================================================================== METHODS
340 REM -----------------------------------------------------------------------------
341 Public Function A1Style(Optional ByVal Row1 As Variant _
342 , Optional ByVal Column1 As Variant _
343 , Optional ByVal Row2 As Variant _
344 , Optional ByVal Column2 As Variant _
345 , Optional ByVal SheetName As Variant _
346 ) As String
347 &apos;&apos;&apos; Returns a range expressed in A1-style as defined by its coordinates
348 &apos;&apos;&apos; If only one pair of coordinates is given, the range will embrace only a single cell
349 &apos;&apos;&apos; Args:
350 &apos;&apos;&apos; Row1 : the row number of the first coordinate
351 &apos;&apos;&apos; Column1 : the column number of the first coordinates
352 &apos;&apos;&apos; Row2 : the row number of the second coordinate
353 &apos;&apos;&apos; Column2 : the column number of the second coordinates
354 &apos;&apos;&apos; SheetName: Default = the current sheet. If present, the sheet must exist.
355 &apos;&apos;&apos; Returns:
356 &apos;&apos;&apos; A range as a string
357 &apos;&apos;&apos; Exceptions:
358 &apos;&apos;&apos; Examples:
359 &apos;&apos;&apos; range = oDoc.A1Style(5, 2, 10, 4, &quot;SheetX&quot;) &apos; &quot;&apos;$SheetX&apos;.$E$2:$J$4&quot;
361 Dim sA1Style As String &apos; Return value
362 Dim vSheetName As Variant &apos; Alias of SheetName - necessary see [Bug 145279]
363 Dim lTemp As Long &apos; To switch 2 values
364 Dim i As Long
366 Const cstThisSub = &quot;SFDocuments.Calc.A1Style&quot;
367 Const cstSubArgs = &quot;Row1, Column1, [Row2], [Column2], [SheetName]=&quot;&quot;&quot;&quot;&quot;
369 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
370 sA1Style = &quot;&quot;
372 Check:
373 If IsMissing(Row2) Or IsEmpty(Row2) Then Row2 = 0
374 If IsMissing(Column2) Or IsEmpty(Column2) Then Column2 = 0
375 If IsMissing(SheetName) Or IsEmpty(SheetName) Then SheetName = &quot;&quot;
376 vSheetName = SheetName
378 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
379 If Not _IsStillAlive() Then GoTo Finally
380 If Not ScriptForge.SF_Utils._Validate(Row1, &quot;Row1&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
381 If Not ScriptForge.SF_Utils._Validate(Column1, &quot;Column1&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
382 If Not ScriptForge.SF_Utils._Validate(Row2, &quot;Row2&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
383 If Not ScriptForge.SF_Utils._Validate(Column2, &quot;Column2&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
384 If Not _ValidateSheet(vSheetName, &quot;SheetName&quot;, , True, True, , , True) Then GoTo Finally
385 End If
387 If Row1 &gt; MAXROWS Then Row1 = MAXROWS
388 If Row2 &gt; MAXROWS Then Row2 = MAXROWS
389 If Column1 &gt; MAXCOLS Then Column1 = MAXCOLS
390 If Column2 &gt; MAXCOLS Then Column2 = MAXCOLS
391 If Row1 &lt;= 0 Or Column1 &lt;= 0 Then GoTo Catch
392 If Row2 = Row1 And Column2 = Column1 Then &apos; Single cell
393 Row2 = 0
394 Column2 = 0
395 End If
397 If Row2 &gt; 0 And Row2 &lt; Row1 Then
398 lTemp = Row2 : Row2 = Row1 : Row1 = lTemp
399 End If
400 If Column2 &gt; 0 And Column2 &lt; Column1 Then
401 lTemp = Column2 : Column2 = Column1 : Column1 = lTemp
402 End If
404 Try:
405 &apos; Surround the sheet name with single quotes when required by the presence of special characters
406 If Len(vSheetName) &gt; 0 Then vSheetName = &quot;$&quot; &amp; _QuoteSheetName(vSheetName) &amp; &quot;.&quot;
407 &apos; Define the new range string
408 sA1Style = vSheetName _
409 &amp; &quot;$&quot; &amp; _GetColumnName(Column1) &amp; &quot;$&quot; &amp; CLng(Row1) _
410 &amp; Iif(Row2 &gt; 0 And Column2 &gt; 0, &quot;:$&quot; &amp; _GetColumnName(Column2) &amp; &quot;$&quot; &amp; CLng(Row2), &quot;&quot;)
412 Finally:
413 A1Style = sA1Style
414 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
415 Exit Function
416 Catch:
417 GoTo Finally
418 End Function &apos; SFDocuments.SF_Calc.A1Style
420 REM -----------------------------------------------------------------------------
421 Public Function Activate(Optional ByVal SheetName As Variant) As Boolean
422 &apos;&apos;&apos; Make the current document or the given sheet active
423 &apos;&apos;&apos; Args:
424 &apos;&apos;&apos; SheetName: Default = the Calc document as a whole
425 &apos;&apos;&apos; Returns:
426 &apos;&apos;&apos; True if the document or the sheet could be made active
427 &apos;&apos;&apos; Otherwise, there is no change in the actual user interface
428 &apos;&apos;&apos; Examples:
429 &apos;&apos;&apos; oDoc.Activate(&quot;SheetX&quot;)
431 Dim bActive As Boolean &apos; Return value
432 Dim oSheet As Object &apos; Reference to sheet
433 Const cstThisSub = &quot;SFDocuments.Calc.Activate&quot;
434 Const cstSubArgs = &quot;[SheetName]&quot;
436 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
437 bActive = False
439 Check:
440 If IsMissing(SheetName) Or IsEmpty(SheetName) Then SheetName = &quot;&quot;
441 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
442 If Not _IsStillAlive() Then GoTo Finally
443 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , , True) Then GoTo Finally
444 End If
446 Try:
447 &apos; Sheet activation, to do only when meaningful, precedes document activation
448 If Len(SheetName) &gt; 0 Then
449 With _Component
450 Set oSheet = .getSheets.getByName(SheetName)
451 Set .CurrentController.ActiveSheet = oSheet
452 End With
453 End If
454 bActive = [_Super].Activate()
456 Finally:
457 Activate = bActive
458 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
459 Exit Function
460 Catch:
461 GoTo Finally
462 End Function &apos; SFDocuments.SF_Calc.Activate
464 REM -----------------------------------------------------------------------------
465 Public Function Charts(Optional ByVal SheetName As Variant _
466 , Optional ByVal ChartName As Variant _
467 ) As Variant
468 &apos;&apos;&apos; Return either the list of charts present in the given sheet or a chart object
469 &apos;&apos;&apos; Args:
470 &apos;&apos;&apos; SheetName: The name of an existing sheet
471 &apos;&apos;&apos; ChartName: The user-defined name of the targeted chart or the zero-length string
472 &apos;&apos;&apos; Returns:
473 &apos;&apos;&apos; When ChartName = &quot;&quot;, return the list of the charts present in the sheet,
474 &apos;&apos;&apos; otherwise, return a new chart service instance
475 &apos;&apos;&apos; Examples:
476 &apos;&apos;&apos; Dim oChart As Object
477 &apos;&apos;&apos; Set oChart = oDoc.Charts(&quot;SheetX&quot;, &quot;myChart&quot;)
479 Dim vCharts As Variant &apos; Return value when array of chart names
480 Dim oChart As Object &apos; Return value when new chart instance
481 Dim oSheet As Object &apos; Alias of SheetName as reference
482 Dim oDrawPage As Object &apos; com.sun.star.drawing.XDrawPage
483 Dim oNextShape As Object &apos; com.sun.star.drawing.XShape
484 Dim sChartName As String &apos; Some chart name
485 Dim lCount As Long &apos; Counter for charts among all drawing objects
486 Dim i As Long
487 Const cstChartShape = &quot;com.sun.star.drawing.OLE2Shape&quot;
489 Const cstThisSub = &quot;SFDocuments.Calc.Charts&quot;
490 Const cstSubArgs = &quot;SheetName, [ChartName=&quot;&quot;&quot;&quot;]&quot;
492 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
493 vCharts = Array()
495 Check:
496 If IsMissing(ChartName) Or IsEmpty(ChartName) Then ChartName = &quot;&quot;
497 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
498 If Not _IsStillAlive(True) Then GoTo Finally
499 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
500 If Not ScriptForge.SF_Utils._Validate(ChartName, &quot;ChartName&quot;, V_STRING) Then GoTo Finally
501 End If
503 Try:
504 &apos; Because the user can change it constantly, the list of valid charts has to be rebuilt at each time
505 &apos; Explore charts starting from the draw page
506 Set oSheet = _Component.getSheets.getByName(SheetName)
507 Set oDrawPage = oSheet.getDrawPage()
508 vCharts = Array()
509 Set oChart = Nothing
510 lCount = -1
511 For i = 0 To oDrawPage.Count - 1
512 Set oNextShape = oDrawPage.getByIndex(i)
513 if oNextShape.supportsService(cstChartShape) Then &apos; Ignore other shapes
514 sChartName = oNextShape.Name &apos; User-defined name
515 If Len(sChartName) = 0 Then sChartName = oNextShape.PersistName &apos; Internal name
516 &apos; Is chart found ?
517 If Len(ChartName) &gt; 0 Then
518 If ChartName = sChartName Then
519 Set oChart = New SF_Chart
520 With oChart
521 Set .[Me] = oChart
522 Set .[_Parent] = [Me]
523 ._SheetName = SheetName
524 ._DrawIndex = i
525 ._ChartName = ChartName
526 ._PersistentName = oNextShape.PersistName
527 Set ._Shape = oNextShape
528 Set ._Chart = oSheet.getCharts().getByName(._PersistentName)
529 Set ._ChartObject = ._Chart.EmbeddedObject
530 Set ._Diagram = ._ChartObject.Diagram
531 End With
532 Exit For
533 End If
534 End If
535 &apos; Build stack of chart names
536 lCount = lCount + 1
537 If UBound(vCharts) &lt; 0 Then
538 vCharts = Array(sChartName)
539 Else
540 ReDim Preserve vCharts(0 To UBound(vCharts) + 1)
541 vCharts(lCount) = sChartName
542 End If
543 End If
544 Next i
546 &apos; Raise error when chart not found
547 If Len(ChartName) &gt; 0 And IsNull(oChart) Then
548 If Not ScriptForge.SF_Utils._Validate(ChartName, &quot;ChartName&quot;, V_STRING, vCharts, True) Then GoTo Finally
549 End If
551 Finally:
552 If Len(ChartName) = 0 Then Charts = vCharts Else Set Charts = oChart
553 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
554 Exit Function
555 Catch:
556 GoTo Finally
557 End Function &apos; SFDocuments.SF_Calc.Charts
559 REM -----------------------------------------------------------------------------
560 Public Sub ClearAll(Optional ByVal Range As Variant _
561 , Optional FilterFormula As Variant _
562 , Optional FilterScope As Variant _
564 &apos;&apos;&apos; Clear entirely the given range
565 &apos;&apos;&apos; Args:
566 &apos;&apos;&apos; Range : the cell or the range as a string that should be cleared
567 &apos;&apos;&apos; FilterFormula: a Calc formula to select among the given Range
568 &apos;&apos;&apos; When left empty, all the cells of the range are cleared
569 &apos;&apos;&apos; FilterScope: &quot;CELL&quot; (default value), &quot;ROW&quot; or &quot;COLUMN&quot;
570 &apos;&apos;&apos; When FilterFormula is present, FilterScope is mandatory
571 &apos;&apos;&apos; Examples:
572 &apos;&apos;&apos; oDoc.ClearAll(&quot;SheetX&quot;) &apos; Clears the used area of the sheet
573 &apos;&apos;&apos; oDoc.ClearAll(&quot;A1:J20&quot;, &quot;=($A1=0)&quot;, &quot;ROW&quot;) &apos; Clears all rows when 1st cell is zero
575 _ClearRange(&quot;All&quot;, Range, FilterFormula, FilterScope)
577 End Sub &apos; SFDocuments.SF_Calc.ClearAll
579 REM -----------------------------------------------------------------------------
580 Public Sub ClearFormats(Optional ByVal Range As Variant _
581 , Optional FilterFormula As Variant _
582 , Optional FilterScope As Variant _
584 &apos;&apos;&apos; Clear all the formatting elements of the given range
585 &apos;&apos;&apos; Args:
586 &apos;&apos;&apos; Range : the cell or the range as a string that should be cleared
587 &apos;&apos;&apos; FilterFormula: a Calc formula to select among the given Range
588 &apos;&apos;&apos; When left empty, all the cells of the range are cleared
589 &apos;&apos;&apos; FilterScope: &quot;CELL&quot; (default value), &quot;ROW&quot; or &quot;COLUMN&quot;
590 &apos;&apos;&apos; When FilterFormula is present, FilterScope is mandatory
591 &apos;&apos;&apos; Examples:
592 &apos;&apos;&apos; oDoc.ClearFormats(&quot;SheetX.*&quot;) &apos; Clears the used area of the sheet
593 &apos;&apos;&apos; oDoc.ClearFormats(&quot;A1:J20&quot;, &quot;=(MOD(A1;0)=0)&quot;, &quot;CELL&quot;) &apos; Clears all even cells
595 _ClearRange(&quot;Formats&quot;, Range, FilterFormula, FilterScope)
597 End Sub &apos; SFDocuments.SF_Calc.ClearFormats
599 REM -----------------------------------------------------------------------------
600 Public Sub ClearValues(Optional ByVal Range As Variant _
601 , Optional FilterFormula As Variant _
602 , Optional FilterScope As Variant _
604 &apos;&apos;&apos; Clear values and formulas in the given range
605 &apos;&apos;&apos; Args:
606 &apos;&apos;&apos; Range : the cell or the range as a string that should be cleared
607 &apos;&apos;&apos; FilterFormula: a Calc formula to select among the given Range
608 &apos;&apos;&apos; When left empty, all the cells of the range are cleared
609 &apos;&apos;&apos; FilterScope: &quot;CELL&quot; (default value), &quot;ROW&quot; or &quot;COLUMN&quot;
610 &apos;&apos;&apos; When FilterFormula is present, FilterScope is mandatory
611 &apos;&apos;&apos; Examples:
612 &apos;&apos;&apos; oDoc.ClearValues(&quot;SheetX.*&quot;) &apos; Clears the used area of the sheet
613 &apos;&apos;&apos; oDoc.ClearValues(&quot;A2:A20&quot;, &quot;=(A2=A1)&quot;, &quot;CELL&quot;) &apos; Clears all duplicate cells
615 _ClearRange(&quot;Values&quot;, Range, FilterFormula, FilterScope)
617 End Sub &apos; SFDocuments.SF_Calc.ClearValues
619 REM -----------------------------------------------------------------------------
620 Public Function CompactLeft(Optional ByVal Range As Variant _
621 , Optional ByVal WholeColumn As Variant _
622 , Optional ByVal FilterFormula As Variant _
623 ) As String
624 &apos;&apos;&apos; Delete the columns of a specified range matching a filter expressed as a formula
625 &apos;&apos;&apos; applied on each column.
626 &apos;&apos;&apos; The deleted cells can span whole columns or be limited to the height of the range
627 &apos;&apos;&apos; The execution of the method has no effect on the current selection
628 &apos;&apos;&apos; Args:
629 &apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
630 &apos;&apos;&apos; WholeColumn: when True (default = False), erase whole columns
631 &apos;&apos;&apos; FilterFormula: the formula to be applied on each column.
632 &apos;&apos;&apos; The column is erased when the formula results in True,
633 &apos;&apos;&apos; The formula shall probably involve one or more cells of the first column of the range.
634 &apos;&apos;&apos; By default, a column is erased when all the cells of the column are empty,
635 &apos;&apos;&apos; i.e. suppose the range is &quot;A1:J200&quot; (height = 200) the default value becomes
636 &apos;&apos;&apos; &quot;=(COUNTBLANK(A1:A200)=200)&quot;
637 &apos;&apos;&apos; Returns:
638 &apos;&apos;&apos; A string representing the location of the initial range after compaction,
639 &apos;&apos;&apos; or the zero-length string if the whole range has been deleted
640 &apos;&apos;&apos; Examples:
641 &apos;&apos;&apos; newrange = oDoc.CompactLeft(&quot;SheetX.G1:L10&quot;) &apos; All empty columns of the range are suppressed
642 &apos;&apos;&apos; newrange = oDoc.CompactLeft(&quot;SheetX.G1:L10&quot;, WholeColumn := True, FilterFormula := &quot;=(G$7=&quot;&quot;X&quot;&quot;)&quot;)
643 &apos;&apos;&apos; &apos; The columns having a &quot;X&quot; in row 7 are completely suppressed
645 Dim sCompact As String &apos; Return value
646 Dim oCompact As Object &apos; Return value as an _Address type
647 Dim lCountDeleted As Long &apos; Count the deleted columns
648 Dim vCompactRanges As Variant &apos; Array of ranges to be compacted based on the formula
649 Dim oSourceAddress As Object &apos; Alias of Range as _Address
650 Dim oPartialRange As Object &apos; Contiguous columns to be deleted
651 Dim sShiftRange As String &apos; Contiguous columns to be shifted
652 Dim i As Long
654 Const cstThisSub = &quot;SFDocuments.Calc.CompactLeft&quot;
655 Const cstSubArgs = &quot;Range, [WholeColumn=False], [FilterFormula=&quot;&quot;&quot;&quot;]&quot;
657 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
658 sCompact = &quot;&quot;
660 Check:
661 If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = False
662 If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then FilterFormula = &quot;&quot;
663 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
664 If Not _IsStillAlive(True) Then GoTo Finally
665 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
666 If Not ScriptForge.SF_Utils._Validate(WholeColumn, &quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
667 If Not ScriptForge.SF_Utils._Validate(FilterFormula, &quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
668 End If
670 Try:
671 Set oSourceAddress = _ParseAddress(Range)
672 lCountDeleted = 0
674 With oSourceAddress
676 &apos; Set the default formula =&gt; all cells are blank
677 If FilterFormula = &quot;&quot; Then FilterFormula = Printf(&quot;=(COUNTBLANK(%C1%R1:%C1%R2)-&quot; &amp; .Height &amp; &quot;=0)&quot;, Range)
679 &apos; Identify the ranges to compact based on the given formula
680 vCompactRanges = _ComputeFilter(oSourceAddress, FilterFormula, &quot;COLUMN&quot;)
682 &apos; Iterate through the ranges from bottom to top and shift them up
683 For i = UBound(vCompactRanges) To 0 Step -1
684 Set oPartialRange = vCompactRanges(i)
685 ShiftLeft(oPartialRange.RangeName, WholeColumn)
686 lCountDeleted = lCountDeleted + oPartialRange.Width
687 Next i
689 &apos; Compute the final range position
690 If lCountDeleted &gt; 0 Then
691 sCompact = Offset(Range, 0, 0, 0, .Width - lCountDeleted)
692 &apos; Push to the right the cells that migrated leftwards irrelevantly
693 If Not WholeColumn Then
694 sShiftRange = Offset(sCompact, 0, .Width - lCountDeleted, , lCountDeleted)
695 ShiftRight(sShiftRange, WholeColumn := False)
696 End If
697 &apos; Conventionally, if all columns are deleted, the returned range is the zero-length string
698 If .Width = lCountDeleted Then sCompact = &quot;&quot;
699 Else &apos; Initial range is left unchanged
700 sCompact = .RangeName
701 End If
703 End With
705 Finally:
706 CompactLeft = sCompact
707 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
708 Exit Function
709 Catch:
710 &apos; When error, return the original range
711 If Not IsNull(oSourceAddress) Then sCompact = oSourceAddress.RangeName
712 GoTo Finally
713 End Function &apos; SFDocuments.SF_Calc.CompactLeft
715 REM -----------------------------------------------------------------------------
716 Public Function CompactUp(Optional ByVal Range As Variant _
717 , Optional ByVal WholeRow As Variant _
718 , Optional ByVal FilterFormula As Variant _
719 ) As String
720 &apos;&apos;&apos; Delete the rows of a specified range matching a filter expressed as a formula
721 &apos;&apos;&apos; applied on each row.
722 &apos;&apos;&apos; The deleted cells can span whole rows or be limited to the width of the range
723 &apos;&apos;&apos; The execution of the method has no effect on the current selection
724 &apos;&apos;&apos; Args:
725 &apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
726 &apos;&apos;&apos; WholeRow: when True (default = False), erase whole rows
727 &apos;&apos;&apos; FilterFormula: the formula to be applied on each row.
728 &apos;&apos;&apos; The row is erased when the formula results in True,
729 &apos;&apos;&apos; The formula shall probably involve one or more cells of the first row of the range.
730 &apos;&apos;&apos; By default, a row is erased when all the cells of the row are empty,
731 &apos;&apos;&apos; i.e. suppose the range is &quot;A1:J200&quot; (width = 10) the default value becomes
732 &apos;&apos;&apos; &quot;=(COUNTBLANK(A1:J1)=10)&quot;
733 &apos;&apos;&apos; Returns:
734 &apos;&apos;&apos; A string representing the location of the initial range after compaction,
735 &apos;&apos;&apos; or the zero-length string if the whole range has been deleted
736 &apos;&apos;&apos; Examples:
737 &apos;&apos;&apos; newrange = oDoc.CompactUp(&quot;SheetX.G1:L10&quot;) &apos; All empty rows of the range are suppressed
738 &apos;&apos;&apos; newrange = oDoc.CompactUp(&quot;SheetX.G1:L10&quot;, WholeRow := True, FilterFormula := &quot;=(G1=&quot;&quot;X&quot;&quot;)&quot;)
739 &apos;&apos;&apos; &apos; The rows having a &quot;X&quot; in column G are completely suppressed
741 Dim sCompact As String &apos; Return value
742 Dim lCountDeleted As Long &apos; Count the deleted rows
743 Dim vCompactRanges As Variant &apos; Array of ranges to be compacted based on the formula
744 Dim oSourceAddress As Object &apos; Alias of Range as _Address
745 Dim oPartialRange As Object &apos; Contiguous rows to be deleted
746 Dim sShiftRange As String &apos; Contiguous rows to be shifted
747 Dim i As Long
749 Const cstThisSub = &quot;SFDocuments.Calc.CompactUp&quot;
750 Const cstSubArgs = &quot;Range, [WholeRow=False], [FilterFormula=&quot;&quot;&quot;&quot;]&quot;
752 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
753 sCompact = &quot;&quot;
755 Check:
756 If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
757 If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then FilterFormula = &quot;&quot;
758 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
759 If Not _IsStillAlive(True) Then GoTo Finally
760 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
761 If Not ScriptForge.SF_Utils._Validate(WholeRow, &quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
762 If Not ScriptForge.SF_Utils._Validate(FilterFormula, &quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
763 End If
765 Try:
766 Set oSourceAddress = _ParseAddress(Range)
767 lCountDeleted = 0
769 With oSourceAddress
771 &apos; Set the default formula =&gt; all cells are blank
772 If FilterFormula = &quot;&quot; Then FilterFormula = Printf(&quot;=(COUNTBLANK(%C1%R1:%C2%R1)-&quot; &amp; .Width &amp; &quot;=0)&quot;, Range)
774 &apos; Identify the ranges to compact based on the given formula
775 vCompactRanges = _ComputeFilter(oSourceAddress, FilterFormula, &quot;ROW&quot;)
777 &apos; Iterate through the ranges from bottom to top and shift them up
778 For i = UBound(vCompactRanges) To 0 Step -1
779 Set oPartialRange = vCompactRanges(i)
780 ShiftUp(oPartialRange.RangeName, WholeRow)
781 lCountDeleted = lCountDeleted + oPartialRange.Height
782 Next i
784 &apos; Compute the final range position
785 If lCountDeleted &gt; 0 Then
786 sCompact = Offset(Range, 0, 0, .Height - lCountDeleted, 0)
787 &apos; Push downwards the cells that migrated upwards irrelevantly
788 If Not WholeRow Then
789 sShiftRange = Offset(sCompact, .Height - lCountDeleted, 0, lCountDeleted)
790 ShiftDown(sShiftRange, WholeRow := False)
791 End If
792 &apos; Conventionally, if all rows are deleted, the returned range is the zero-length string
793 If .Height = lCountDeleted Then sCompact = &quot;&quot;
794 Else &apos; Initial range is left unchanged
795 sCompact = .RangeName
796 End If
798 End With
800 Finally:
801 CompactUp = sCompact
802 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
803 Exit Function
804 Catch:
805 &apos; When error, return the original range
806 If Not IsNull(oSourceAddress) Then sCompact = oSourceAddress.RangeName
807 GoTo Finally
808 End Function &apos; SFDocuments.SF_Calc.CompactUp
810 REM -----------------------------------------------------------------------------
811 Public Function CopySheet(Optional ByVal SheetName As Variant _
812 , Optional ByVal NewName As Variant _
813 , Optional ByVal BeforeSheet As Variant _
814 ) As Boolean
815 &apos;&apos;&apos; Copy a specified sheet before an existing sheet or at the end of the list of sheets
816 &apos;&apos;&apos; The sheet to copy may be inside any open Calc document
817 &apos;&apos;&apos; Args:
818 &apos;&apos;&apos; SheetName: The name of the sheet to copy or its reference
819 &apos;&apos;&apos; NewName: Must not exist
820 &apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to insert
821 &apos;&apos;&apos; Returns:
822 &apos;&apos;&apos; True if the sheet could be copied successfully
823 &apos;&apos;&apos; Exceptions:
824 &apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
825 &apos;&apos;&apos; Examples:
826 &apos;&apos;&apos; oDoc.CopySheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
827 &apos;&apos;&apos; &apos; Copy within the same document
828 &apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\Temp\FileA.ods&quot;, Hidden := True, ReadOnly := True)
829 &apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\Temp\FileB.ods&quot;)
830 &apos;&apos;&apos; oDocB.CopySheet(oDocA.Sheet(&quot;SheetX&quot;), &quot;SheetY&quot;)
831 &apos;&apos;&apos; &apos; Copy from 1 file to another and put the new sheet at the end
833 Dim bCopy As Boolean &apos; Return value
834 Dim oSheets As Object &apos; com.sun.star.sheet.XSpreadsheets
835 Dim vSheets As Variant &apos; List of existing sheets
836 Dim lSheetIndex As Long &apos; Index of a sheet
837 Dim oSheet As Object &apos; Alias of SheetName as reference
838 Dim lRandom As Long &apos; Output of random number generator
839 Dim sRandom &apos; Random sheet name
840 Const cstThisSub = &quot;SFDocuments.Calc.CopySheet&quot;
841 Const cstSubArgs = &quot;SheetName, NewName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
843 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
844 bCopy = False
846 Check:
847 If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
848 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
849 If Not _IsStillAlive(True) Then GoTo Finally
850 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True, , , True) Then GoTo Finally
851 If Not _ValidateSheet(NewName, &quot;NewName&quot;, True) Then GoTo Finally
852 If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
853 End If
855 Try:
856 &apos; Determine the index of the sheet before which to insert the copy
857 Set oSheets = _Component.getSheets
858 vSheets = oSheets.getElementNames()
859 If VarType(BeforeSheet) = V_STRING Then
860 lSheetIndex = ScriptForge.SF_Array.IndexOf(vSheets, BeforeSheet)
861 Else
862 lSheetIndex = BeforeSheet - 1
863 If lSheetIndex &lt; 0 Then lSheetIndex = 0
864 If lSheetIndex &gt; UBound(vSheets) Then lSheetIndex = UBound(vSheets) + 1
865 End If
867 &apos; Copy sheet inside the same document OR import from another document
868 If VarType(SheetName) = V_STRING Then
869 _Component.getSheets.copyByName(SheetName, NewName, lSheetIndex)
870 Else
871 Set oSheet = SheetName
872 With oSheet
873 &apos; If a sheet with same name as input exists in the target sheet, rename it first with a random name
874 sRandom = &quot;&quot;
875 If ScriptForge.SF_Array.Contains(vSheets, .SheetName) Then
876 lRandom = ScriptForge.SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN.NV&quot;, 1, 9999999)
877 sRandom = &quot;SF_&quot; &amp; Right(&quot;0000000&quot; &amp; lRandom, 7)
878 oSheets.getByName(.SheetName).setName(sRandom)
879 End If
880 &apos; Import i.o. Copy
881 oSheets.importSheet(oSheet.Component, .SheetName, lSheetIndex)
882 &apos; Rename to new sheet name
883 oSheets.getByName(.SheetName).setName(NewName)
884 &apos; Reset random name
885 If Len(sRandom) &gt; 0 Then oSheets.getByName(sRandom).setName(.SheetName)
886 End With
887 End If
888 bCopy = True
890 Finally:
891 CopySheet = bCopy
892 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
893 Exit Function
894 Catch:
895 GoTo Finally
896 CatchDuplicate:
897 ScriptForge.SF_Exception.RaiseFatal(DUPLICATESHEETERROR, &quot;NewName&quot;, NewName, &quot;Document&quot;, [_Super]._FileIdent())
898 GoTo Finally
899 End Function &apos; SFDocuments.SF_Calc.CopySheet
901 REM -----------------------------------------------------------------------------
902 Public Function CopySheetFromFile(Optional ByVal FileName As Variant _
903 , Optional ByVal SheetName As Variant _
904 , Optional ByVal NewName As Variant _
905 , Optional ByVal BeforeSheet As Variant _
906 ) As Boolean
907 &apos;&apos;&apos; Copy a specified sheet before an existing sheet or at the end of the list of sheets
908 &apos;&apos;&apos; The sheet to copy is located inside any closed Calc document
909 &apos;&apos;&apos; Args:
910 &apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
911 &apos;&apos;&apos; The file must not be protected with a password
912 &apos;&apos;&apos; SheetName: The name of the sheet to copy
913 &apos;&apos;&apos; NewName: Must not exist
914 &apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to insert
915 &apos;&apos;&apos; Returns:
916 &apos;&apos;&apos; True if the sheet could be created
917 &apos;&apos;&apos; The created sheet is blank when the input file is not a Calc file
918 &apos;&apos;&apos; The created sheet contains an error message when the input sheet was not found
919 &apos;&apos;&apos; Exceptions:
920 &apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
921 &apos;&apos;&apos; UNKNOWNFILEERROR The input file is unknown
922 &apos;&apos;&apos; Examples:
923 &apos;&apos;&apos; oDoc.CopySheetFromFile(&quot;C:\MyFile.ods&quot;, &quot;SheetX&quot;, &quot;SheetY&quot;, 3)
925 Dim bCopy As Boolean &apos; Return value
926 Dim oSheet As Object &apos; com.sun.star.sheet.XSpreadsheet
927 Dim sFileName As String &apos; URL alias of FileName
928 Dim FSO As Object &apos; SF_FileSystem
929 Const cstThisSub = &quot;SFDocuments.Calc.CopySheetFromFile&quot;
930 Const cstSubArgs = &quot;FileName, SheetName, NewName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
932 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
933 bCopy = False
935 Check:
936 If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
937 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
938 If Not _IsStillAlive(True) Then GoTo Finally
939 If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
940 If Not ScriptForge.SF_Utils._Validate(SheetName, &quot;SheetName&quot;, V_STRING) Then GoTo Finally
941 If Not _ValidateSheet(NewName, &quot;NewName&quot;, True) Then GoTo Finally
942 If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
943 End If
945 Try:
946 Set FSO = ScriptForge.SF_FileSystem
947 &apos; Does the input file exist ?
948 If Not FSO.FileExists(FileName) Then GoTo CatchNotExists
949 sFileName = FSO._ConvertToUrl(FileName)
951 &apos; Insert a blank new sheet and import sheet from file via link setting and deletion
952 If Not InsertSheet(Newname, BeforeSheet) Then GoTo Finally
953 Set oSheet = _Component.getSheets.getByName(NewName)
954 With oSheet
955 .link(sFileName,SheetName, &quot;&quot;, &quot;&quot;, com.sun.star.sheet.SheetLinkMode.NORMAL)
956 .LinkMode = com.sun.star.sheet.SheetLinkMode.NONE
957 .LinkURL = &quot;&quot;
958 End With
959 bCopy = True
961 Finally:
962 CopySheetFromFile = bCopy
963 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
964 Exit Function
965 Catch:
966 GoTo Finally
967 CatchNotExists:
968 ScriptForge.SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
969 GoTo Finally
970 End Function &apos; SFDocuments.SF_Calc.CopySheetFromFile
972 REM -----------------------------------------------------------------------------
973 Public Function CopyToCell(Optional ByVal SourceRange As Variant _
974 , Optional ByVal DestinationCell As Variant _
975 ) As String
976 &apos;&apos;&apos; Copy a specified source range to a destination range or cell
977 &apos;&apos;&apos; The source range may belong to another open document
978 &apos;&apos;&apos; The method imitates the behaviour of a Copy/Paste from a range to a single cell
979 &apos;&apos;&apos; Args:
980 &apos;&apos;&apos; SourceRange: the source range as a string if it belongs to the same document
981 &apos;&apos;&apos; or as a reference if it belongs to another open Calc document
982 &apos;&apos;&apos; DestinationCell: the destination of the copied range of cells, as a string
983 &apos;&apos;&apos; If given as a range of cells, the destination will be reduced to its top-left cell
984 &apos;&apos;&apos; Returns:
985 &apos;&apos;&apos; A string representing the modified range of cells
986 &apos;&apos;&apos; The modified area depends only on the size of the source area
987 &apos;&apos;&apos; Examples:
988 &apos;&apos;&apos; oDoc.CopyToCell(&quot;SheetX.A1:F10&quot;, &quot;SheetY.C5&quot;)
989 &apos;&apos;&apos; &apos; Copy within the same document
990 &apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\Temp\FileA.ods&quot;, Hidden := True, ReadOnly := True)
991 &apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\Temp\FileB.ods&quot;)
992 &apos;&apos;&apos; oDocB.CopyToCell(oDocA.Range(&quot;SheetX.A1:F10&quot;), &quot;SheetY.C5&quot;)
993 &apos;&apos;&apos; &apos; Copy from 1 file to another
995 Dim sCopy As String &apos; Return value
996 Dim oSource As Object &apos; Alias of SourceRange to avoid &quot;Object variable not set&quot; run-time error
997 Dim oSourceAddress As Object &apos; com.sun.star.table.CellRangeAddress
998 Dim oDestRange As Object &apos; Destination as a range
999 Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
1000 Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
1001 Dim oSelect As Object &apos; Current selection in source
1002 Dim oClipboard As Object &apos; com.sun.star.datatransfer.XTransferable
1004 Const cstThisSub = &quot;SFDocuments.Calc.CopyToCell&quot;
1005 Const cstSubArgs = &quot;SourceRange, DestinationCell&quot;
1007 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1008 sCopy = &quot;&quot;
1010 Check:
1011 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1012 If Not _IsStillAlive(True) Then GoTo Finally
1013 If Not ScriptForge.SF_Utils._Validate(SourceRange, &quot;SourceRange&quot;, Array(V_STRING, ScriptForge.V_OBJECT), , , CALCREFERENCE) Then GoTo Finally
1014 If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
1015 End If
1017 Try:
1018 If VarType(SourceRange) = V_STRING Then &apos; Same document - Use UNO copyRange method
1019 Set oSourceAddress = _ParseAddress(SourceRange).XCellRange.RangeAddress
1020 Set oDestRange = _ParseAddress(DestinationCell)
1021 Set oDestAddress = oDestRange.XCellRange.RangeAddress
1022 Set oDestCell = New com.sun.star.table.CellAddress
1023 With oDestAddress
1024 oDestCell.Sheet = .Sheet
1025 oDestCell.Column = .StartColumn
1026 oDestCell.Row = .StartRow
1027 End With
1028 oDestRange.XSpreadsheet.copyRange(oDestCell, oSourceAddress)
1029 Else &apos; Use clipboard to copy - current selection in Source should be preserved
1030 Set oSource = SourceRange
1031 With oSource
1032 &apos; Keep current selection in source document
1033 Set oSelect = .Component.CurrentController.getSelection()
1034 &apos; Select, copy the source range and paste in the top-left cell of the destination
1035 .Component.CurrentController.select(.XCellRange)
1036 Set oClipboard = .Component.CurrentController.getTransferable()
1037 _Component.CurrentController.select(_Offset(DestinationCell, 0, 0, 1, 1).XCellRange)
1038 _Component.CurrentController.insertTransferable(oClipBoard)
1039 &apos; Restore previous selection in Source
1040 _RestoreSelections(.Component, oSelect)
1041 Set oSourceAddress = .XCellRange.RangeAddress
1042 End With
1043 End If
1045 With oSourceAddress
1046 sCopy = _Offset(DestinationCell, 0, 0, .EndRow - .StartRow + 1, .EndColumn - .StartColumn + 1).RangeName
1047 End With
1049 Finally:
1050 CopyToCell = sCopy
1051 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1052 Exit Function
1053 Catch:
1054 GoTo Finally
1055 End Function &apos; SFDocuments.SF_Calc.CopyToCell
1057 REM -----------------------------------------------------------------------------
1058 Public Function CopyToRange(Optional ByVal SourceRange As Variant _
1059 , Optional ByVal DestinationRange As Variant _
1060 ) As String
1061 &apos;&apos;&apos; Copy downwards and/or rightwards a specified source range to a destination range
1062 &apos;&apos;&apos; The source range may belong to another open document
1063 &apos;&apos;&apos; The method imitates the behaviour of a Copy/Paste from a range to a larger range
1064 &apos;&apos;&apos; If the height (resp. width) of the destination area is &gt; 1 row (resp. column)
1065 &apos;&apos;&apos; then the height (resp. width) of the source must be &lt;= the height (resp. width)
1066 &apos;&apos;&apos; of the destination. Otherwise nothing happens
1067 &apos;&apos;&apos; If the height (resp.width) of the destination is = 1 then the destination
1068 &apos;&apos;&apos; is expanded downwards (resp. rightwards) up to the height (resp. width)
1069 &apos;&apos;&apos; of the source range
1070 &apos;&apos;&apos; Args:
1071 &apos;&apos;&apos; SourceRange: the source range as a string if it belongs to the same document
1072 &apos;&apos;&apos; or as a reference if it belongs to another open Calc document
1073 &apos;&apos;&apos; DestinationRange: the destination of the copied range of cells, as a string
1074 &apos;&apos;&apos; Returns:
1075 &apos;&apos;&apos; A string representing the modified range of cells
1076 &apos;&apos;&apos; Examples:
1077 &apos;&apos;&apos; oDoc.CopyToRange(&quot;SheetX.A1:F10&quot;, &quot;SheetY.C5:J5&quot;)
1078 &apos;&apos;&apos; &apos; Copy within the same document
1079 &apos;&apos;&apos; &apos; Returned range: $SheetY.$C$5:$J$14
1080 &apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\Temp\FileA.ods&quot;, Hidden := True, ReadOnly := True)
1081 &apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\Temp\FileB.ods&quot;)
1082 &apos;&apos;&apos; oDocB.CopyToRange(oDocA.Range(&quot;SheetX.A1:F10&quot;), &quot;SheetY.C5:J5&quot;)
1083 &apos;&apos;&apos; &apos; Copy from 1 file to another
1085 Dim sCopy As String &apos; Return value
1086 Dim oSource As Object &apos; Alias of SourceRange to avoid &quot;Object variable not set&quot; run-time error
1087 Dim oDestRange As Object &apos; Destination as a range
1088 Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
1089 Dim oSelect As Object &apos; Current selection in source
1090 Dim oClipboard As Object &apos; com.sun.star.datatransfer.XTransferable
1091 Dim bSameDocument As Boolean &apos; True when source in same document as destination
1092 Dim lHeight As Long &apos; Height of destination
1093 Dim lWidth As Long &apos; Width of destination
1095 Const cstThisSub = &quot;SFDocuments.Calc.CopyToRange&quot;
1096 Const cstSubArgs = &quot;SourceRange, DestinationRange&quot;
1098 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1099 sCopy = &quot;&quot;
1101 Check:
1102 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1103 If Not _IsStillAlive(True) Then GoTo Finally
1104 If Not ScriptForge.SF_Utils._Validate(SourceRange, &quot;SourceRange&quot;, Array(V_STRING, ScriptForge.V_OBJECT), , , CALCREFERENCE) Then GoTo Finally
1105 If Not ScriptForge.SF_Utils._Validate(DestinationRange, &quot;DestinationRange&quot;, V_STRING) Then GoTo Finally
1106 End If
1108 Try:
1109 &apos; Copy done via clipboard
1111 &apos; Check Height/Width destination = 1 or &gt; Height/Width of source
1112 bSameDocument = ( VarType(SourceRange) = V_STRING )
1113 If bSameDocument Then Set oSource = _ParseAddress(SourceRange) Else Set oSource = SourceRange
1114 Set oDestRange = _ParseAddress(DestinationRange)
1115 With oDestRange
1116 lHeight = .Height
1117 lWidth = .Width
1118 If lHeight = 1 Then
1119 lHeight = oSource.Height &apos; Future height
1120 ElseIf lHeight &lt; oSource.Height Then
1121 GoTo Finally
1122 End If
1123 If lWidth = 1 Then
1124 lWidth = oSource.Width &apos; Future width
1125 ElseIf lWidth &lt; oSource.Width Then
1126 GoTo Finally
1127 End If
1128 End With
1130 With oSource
1131 &apos; Store actual selection in source
1132 Set oSelect = .Component.CurrentController.getSelection()
1133 &apos; Select, copy the source range and paste in the destination
1134 .Component.CurrentController.select(.XCellRange)
1135 Set oClipboard = .Component.CurrentController.getTransferable()
1136 _Component.CurrentController.select(oDestRange.XCellRange)
1137 _Component.CurrentController.insertTransferable(oClipBoard)
1138 &apos; Restore selection in source
1139 _RestoreSelections(.Component, oSelect)
1140 End With
1142 sCopy = _Offset(oDestRange, 0, 0, lHeight, lWidth).RangeName
1144 Finally:
1145 CopyToRange = sCopy
1146 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1147 Exit Function
1148 Catch:
1149 GoTo Finally
1150 End Function &apos; SFDocuments.SF_Calc.CopyToRange
1152 REM -----------------------------------------------------------------------------
1153 Public Function CreateChart(Optional ByVal ChartName As Variant _
1154 , Optional ByVal SheetName As Variant _
1155 , Optional ByVal Range As Variant _
1156 , Optional ColumnHeader As Variant _
1157 , Optional RowHeader As Variant _
1158 ) As Variant
1159 &apos;&apos;&apos; Return a new chart instance initialized with default values
1160 &apos;&apos;&apos; Args:
1161 &apos;&apos;&apos; ChartName: The user-defined name of the new chart
1162 &apos;&apos;&apos; SheetName: The name of an existing sheet
1163 &apos;&apos;&apos; Range: the cell or the range as a string that should be drawn
1164 &apos;&apos;&apos; ColumnHeader: when True, the topmost row of the range will be used to set labels for the category axis or the legend.
1165 &apos;&apos;&apos; Default = False
1166 &apos;&apos;&apos; RowHeader: when True, the leftmost column of the range will be used to set labels for the category axis or the legend.
1167 &apos;&apos;&apos; Default = False
1168 &apos;&apos;&apos; Returns:
1169 &apos;&apos;&apos; A new chart service instance
1170 &apos;&apos;&apos; Exceptions:
1171 &apos;&apos;&apos; DUPLICATECHARTERROR A chart with the same name exists already in the given sheet
1172 &apos;&apos;&apos; Examples:
1173 &apos;&apos;&apos; Dim oChart As Object
1174 &apos;&apos;&apos; Set oChart = oDoc.CreateChart(&quot;myChart&quot;, &quot;SheetX&quot;, &quot;A1:C8&quot;, ColumnHeader := True)
1176 Dim oChart As Object &apos; Return value
1177 Dim vCharts As Variant &apos; List of pre-existing charts
1178 Dim oSheet As Object &apos; Alias of SheetName as reference
1179 Dim oRange As Object &apos; Alias of Range
1180 Dim oRectangle as new com.sun.star.awt.Rectangle &apos; Simple shape
1182 Const cstThisSub = &quot;SFDocuments.Calc.CreateChart&quot;
1183 Const cstSubArgs = &quot;ChartName, SheetName, Range, [ColumnHeader=False], [RowHeader=False]&quot;
1185 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1186 Set oChart = Nothing
1188 Check:
1189 If IsMissing(RowHeader) Or IsEmpty(RowHeader) Then Rowheader = False
1190 If IsMissing(ColumnHeader) Or IsEmpty(ColumnHeader) Then ColumnHeader = False
1191 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1192 If Not _IsStillAlive(True) Then GoTo Finally
1193 If Not ScriptForge.SF_Utils._Validate(ChartName, &quot;ChartName&quot;, V_STRING) Then GoTo Finally
1194 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
1195 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
1196 If Not ScriptForge.SF_Utils._Validate(ColumnHeader, &quot;ColumnHeader&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1197 If Not ScriptForge.SF_Utils._Validate(RowHeader, &quot;RowHeader&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1198 End If
1200 vCharts = Charts(SheetName)
1201 If ScriptForge.SF_Array.Contains(vCharts, ChartName, CaseSensitive := True) Then GoTo CatchDuplicate
1203 Try:
1204 &apos; The rectangular shape receives arbitrary values. User can Resize() it later
1205 With oRectangle
1206 .X = 0 : .Y = 0
1207 .Width = 8000 : .Height = 6000
1208 End With
1209 &apos; Initialize sheet and range
1210 Set oSheet = _Component.getSheets.getByName(SheetName)
1211 Set oRange = _ParseAddress(Range)
1212 &apos; Create the chart and get ihe corresponding chart instance
1213 oSheet.getCharts.addNewByName(ChartName, oRectangle, Array(oRange.XCellRange.RangeAddress), ColumnHeader, RowHeader)
1214 Set oChart = Charts(SheetName, ChartName)
1215 oChart._Shape.Name = ChartName &apos; Both user-defined and internal names match ChartName
1216 oChart._Diagram.Wall.FillColor = RGB(255, 255, 255) &apos; Align on background color set by the user interface by default
1218 Finally:
1219 Set CreateChart = oChart
1220 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1221 Exit Function
1222 Catch:
1223 GoTo Finally
1224 CatchDuplicate:
1225 ScriptForge.SF_Exception.RaiseFatal(DUPLICATECHARTERROR, &quot;ChartName&quot;, ChartName, &quot;SheetName&quot;, SheetName, &quot;Document&quot;, [_Super]._FileIdent())
1226 GoTo Finally
1227 End Function &apos; SFDocuments.SF_Calc.CreateChart
1229 REM -----------------------------------------------------------------------------
1230 Public Function CreatePivotTable(Optional ByVal PivotTableName As Variant _
1231 , Optional ByVal SourceRange As Variant _
1232 , Optional ByVal TargetCell As Variant _
1233 , Optional ByRef DataFields As Variant _
1234 , Optional ByRef RowFields As Variant _
1235 , Optional ByRef ColumnFields As Variant _
1236 , Optional ByVal FilterButton As Variant _
1237 , Optional ByVal RowTotals As Variant _
1238 , Optional ByVal ColumnTotals As Variant _
1239 ) As String
1240 &apos;&apos;&apos; Create a new pivot table with the properties defined by the arguments.
1241 &apos;&apos;&apos; If a pivot table with the same name exists already in the targeted sheet, it will be erased without warning.
1242 &apos;&apos;&apos; Args:
1243 &apos;&apos;&apos; PivotTableName: The user-defined name of the new pivottable
1244 &apos;&apos;&apos; SourceRange: The range as a string containing the raw data.
1245 &apos;&apos;&apos; The first row of the range is presumed to contain the field names of the new pivot table
1246 &apos;&apos;&apos; TargetCell: the top left cell or the range as a string where to locate the pivot table.
1247 &apos;&apos;&apos; Only the top left cell of the range will be considered.
1248 &apos;&apos;&apos; DataFields: A single string or an array of field name + function to apply, formatted like:
1249 &apos;&apos;&apos; Array(&quot;FieldName[;Function]&quot;, ...)
1250 &apos;&apos;&apos; The allowed functions are: Sum, Count, Average, Max, Min, Product, CountNums, StDev, StDevP, Var, VarP and Median.
1251 &apos;&apos;&apos; The default function is: When the values are all numerical, Sum is used, otherwise Count
1252 &apos;&apos;&apos; RowFields: A single string or an array of the field names heading the pivot table rows
1253 &apos;&apos;&apos; ColumnFields: A single string or an array of the field names heading the pivot table columns
1254 &apos;&apos;&apos; FilterButton: When True (default), display a &quot;Filter&quot; button above the pivot table
1255 &apos;&apos;&apos; RowTotals: When True (default), display a separate column for row totals
1256 &apos;&apos;&apos; ColumnTotals: When True (default), display a separate row for column totals
1257 &apos;&apos;&apos; Returns:
1258 &apos;&apos;&apos; Return the range where the new pivot table is deployed.
1259 &apos;&apos;&apos; Examples:
1260 &apos;&apos;&apos; Dim vData As Variant, oDoc As Object, sTable As String, sPivot As String
1261 &apos;&apos;&apos; vData = Array(Array(&quot;Item&quot;, &quot;State&quot;, &quot;Team&quot;, &quot;2002&quot;, &quot;2003&quot;, &quot;2004&quot;), _
1262 &apos;&apos;&apos; Array(&quot;Books&quot;, &quot;Michigan&quot;, &quot;Jean&quot;, 14788, 30222, 23490), _
1263 &apos;&apos;&apos; Array(&quot;Candy&quot;, &quot;Michigan&quot;, &quot;Jean&quot;, 26388, 15641, 32849), _
1264 &apos;&apos;&apos; Array(&quot;Pens&quot;, &quot;Michigan&quot;, &quot;Jean&quot;, 16569, 32675, 25396), _
1265 &apos;&apos;&apos; Array(&quot;Books&quot;, &quot;Michigan&quot;, &quot;Volker&quot;, 21961, 21242, 29009), _
1266 &apos;&apos;&apos; Array(&quot;Candy&quot;, &quot;Michigan&quot;, &quot;Volker&quot;, 26142, 22407, 32841))
1267 &apos;&apos;&apos; Set oDoc = ui.CreateDocument(&quot;Calc&quot;)
1268 &apos;&apos;&apos; sTable = oDoc.SetArray(&quot;A1&quot;, vData)
1269 &apos;&apos;&apos; sPivot = oDoc.CreatePivotTable(&quot;PT1&quot;, sTable, &quot;H1&quot;, Array(&quot;2002&quot;, &quot;2003;count&quot;, &quot;2004;average&quot;), &quot;Item&quot;, Array(&quot;State&quot;, &quot;Team&quot;), False)
1271 Dim sPivotTable As String &apos; Return value
1272 Dim vData As Variant &apos; Alias of DataFields
1273 Dim vRows As Variant &apos; Alias of RowFields
1274 Dim vColumns As Variant &apos; Alias of ColumnFields
1275 Dim oSourceAddress As Object &apos; Source as an _Address
1276 Dim oTargetAddress As Object &apos; Target as an _Address
1277 Dim vHeaders As Variant &apos; Array of header fields in the source range
1278 Dim oPivotTables As Object &apos; com.sun.star.sheet.XDataPilotTables
1279 Dim oDescriptor As Object &apos; com.sun.star.sheet.DataPilotDescriptor
1280 Dim oFields As Object &apos; ScDataPilotFieldsObj - Collection of fields
1281 Dim oField As Object &apos; ScDataPilotFieldsObj - A single field
1282 Dim sField As String &apos; A single field name
1283 Dim sData As String &apos; A single data field name + function
1284 Dim vDataField As Variant &apos; A single vData element, split on semicolon
1285 Dim sFunction As String &apos; Function to apply on a data field (string)
1286 Dim iFunction As Integer &apos; Equivalent of sFunction as com.sun.star.sheet.GeneralFunction2 constant
1287 Dim oOutputRange As Object &apos; com.sun.star.table.CellRangeAddress
1288 Dim i As Integer
1290 Const cstThisSub = &quot;SFDocuments.Calc.CreatePivotTable&quot;
1291 Const cstSubArgs = &quot;PivotTableName, SourceRange, TargetCell, DataFields, [RowFields], [ColumnFields]&quot; _
1292 &amp; &quot;, [FilterButton=True], [RowTotals=True], [ColumnTotals=True]&quot;
1294 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1295 sPivotTable = &quot;&quot;
1297 Check:
1298 If IsMissing(RowFields) Or IsEmpty(RowFields) Then RowFields = Array()
1299 If IsMissing(ColumnFields) Or IsEmpty(ColumnFields) Then ColumnFields = Array()
1300 If IsMissing(FilterButton) Or IsEmpty(FilterButton) Then FilterButton = True
1301 If IsMissing(RowTotals) Or IsEmpty(RowTotals) Then RowTotals = True
1302 If IsMissing(ColumnTotals) Or IsEmpty(ColumnTotals) Then ColumnTotals = True
1303 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1304 If Not _IsStillAlive(True) Then GoTo Finally
1305 If Not ScriptForge.SF_Utils._Validate(PivotTableName, &quot;PivotTableName&quot;, V_STRING) Then GoTo Finally
1306 If Not ScriptForge.SF_Utils._Validate(SourceRange, &quot;SourceRange&quot;, V_STRING) Then GoTo Finally
1307 If Not ScriptForge.SF_Utils._Validate(TargetCell, &quot;TargetCell&quot;, V_STRING) Then GoTo Finally
1308 If IsArray(DataFields) Then
1309 If Not ScriptForge.SF_Utils._ValidateArray(DataFields, &quot;DataFields&quot;, 1, V_STRING, True) Then GoTo Finally
1310 Else
1311 If Not ScriptForge.SF_Utils._Validate(DataFields, &quot;DataFields&quot;, V_STRING) Then GoTo Finally
1312 End If
1313 If IsArray(RowFields) Then
1314 If Not ScriptForge.SF_Utils._ValidateArray(RowFields, &quot;RowFields&quot;, 1, V_STRING, True) Then GoTo Finally
1315 Else
1316 If Not ScriptForge.SF_Utils._Validate(RowFields, &quot;RowFields&quot;, V_STRING) Then GoTo Finally
1317 End If
1318 If IsArray(ColumnFields) Then
1319 If Not ScriptForge.SF_Utils._ValidateArray(ColumnFields, &quot;ColumnFields&quot;, 1, V_STRING, True) Then GoTo Finally
1320 Else
1321 If Not ScriptForge.SF_Utils._Validate(ColumnFields, &quot;ColumnFields&quot;, V_STRING) Then GoTo Finally
1322 End If
1323 If Not ScriptForge.SF_Utils._Validate(FilterButton, &quot;FilterButton&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1324 If Not ScriptForge.SF_Utils._Validate(RowTotals, &quot;RowTotals&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1325 If Not ScriptForge.SF_Utils._Validate(ColumnTotals, &quot;ColumnTotals&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1326 End If
1327 &apos; Next statements must be outside previous If-block to force their execution even in case of internal call
1328 If IsArray(DataFields) Then vData = DataFields Else vData = Array(DataFields)
1329 If IsArray(RowFields) Then vRows = RowFields Else vRows = Array(RowFields)
1330 If IsArray(ColumnFields) Then vColumns = ColumnFields Else vColumns = Array(ColumnFields)
1332 Try:
1334 Set oSourceAddress = _ParseAddress(SourceRange)
1335 vHeaders = GetValue(Offset(SourceRange, 0, 0, 1)) &apos; Content of the first row of the source
1336 Set oTargetAddress = _Offset(TargetCell, 0, 0, 1, 1) &apos; Retain the top left cell only
1337 Set oPivotTables = oTargetAddress.XSpreadsheet.getDataPilotTables()
1339 &apos; Initialize new pivot table
1340 Set oDescriptor = oPivotTables.createDataPilotDescriptor()
1341 oDescriptor.setSourceRange(oSourceAddress.XCellRange.RangeAddress)
1342 Set oFields = oDescriptor.getDataPilotFields()
1344 &apos; Set row fields
1345 For i = 0 To UBound(vRows)
1346 sField = vRows(i)
1347 If Len(sField) &gt; 0 Then
1348 If Not ScriptForge.SF_Utils._Validate(sField, &quot;RowFields&quot;, V_STRING, vHeaders, True) Then GoTo Finally
1349 Set oField = oFields.getByName(sField)
1350 oField.Orientation = com.sun.star.sheet.DataPilotFieldOrientation.ROW
1351 End If
1352 Next i
1354 &apos; Set column fields
1355 For i = 0 To UBound(vColumns)
1356 sField = vColumns(i)
1357 If Len(sField) &gt; 0 Then
1358 If Not ScriptForge.SF_Utils._Validate(sField, &quot;ColumnFields&quot;, V_STRING, vHeaders, True) Then GoTo Finally
1359 Set oField = oFields.getByName(sField)
1360 oField.Orientation = com.sun.star.sheet.DataPilotFieldOrientation.COLUMN
1361 End If
1362 Next i
1364 &apos; Set data fields
1365 For i = 0 To UBound(vData)
1366 sData = vData(i)
1367 &apos; Minimal parsing
1368 If Right(sData, 1) = &quot;;&quot; Then sData = Left(sData, Len(sData) - 1)
1369 vDataField = Split(sData, &quot;;&quot;)
1370 sField = vDataField(0)
1371 If UBound(vDataField) &gt; 0 Then sFunction = vDataField(1) Else sFunction = &quot;&quot;
1372 &apos; Define field properties
1373 If Len(sField) &gt; 0 Then
1374 If Not ScriptForge.SF_Utils._Validate(sField, &quot;DataFields&quot;, V_STRING, vHeaders, True) Then GoTo Finally
1375 Set oField = oFields.getByName(sField)
1376 oField.Orientation = com.sun.star.sheet.DataPilotFieldOrientation.DATA
1377 &apos; Associate the correct function
1378 With com.sun.star.sheet.GeneralFunction2
1379 Select Case UCase(sFunction)
1380 Case &quot;&quot; : iFunction = .AUTO
1381 Case &quot;SUM&quot; : iFunction = .SUM
1382 Case &quot;COUNT&quot; : iFunction = .COUNT
1383 Case &quot;AVERAGE&quot; : iFunction = .AVERAGE
1384 Case &quot;MAX&quot; : iFunction = .MAX
1385 Case &quot;MIN&quot; : iFunction = .MIN
1386 Case &quot;PRODUCT&quot; : iFunction = .PRODUCT
1387 Case &quot;COUNTNUMS&quot;: iFunction = .COUNTNUMS
1388 Case &quot;STDEV&quot; : iFunction = .STDEV
1389 Case &quot;STDEVP&quot; : iFunction = .STDEVP
1390 Case &quot;VAR&quot; : iFunction = .VAR
1391 Case &quot;VARP&quot; : iFunction = .VARP
1392 Case &quot;MEDIAN&quot; : iFunction = .MEDIAN
1393 Case Else
1394 If Not ScriptForge.SF_Utils._Validate(sFunction, &quot;DataFields/Function&quot;, V_STRING _
1395 , Array(&quot;Sum&quot;, &quot;Count&quot;, &quot;Average&quot;, &quot;Max&quot;, &quot;Min&quot;, &quot;Product&quot;, &quot;CountNums&quot; _
1396 , &quot;StDev&quot;, &quot;StDevP&quot;, &quot;Var&quot;, &quot;VarP&quot;, &quot;Median&quot;) _
1397 ) Then GoTo Finally
1398 End Select
1399 End With
1400 oField.Function2 = iFunction
1401 End If
1402 Next i
1404 &apos; Remove any pivot table with same name
1405 If oPivotTables.hasByName(PivotTableName) Then oPivotTables.removeByName(PivotTableName)
1407 &apos; Finalize the new pivot table
1408 oDescriptor.ShowFilterButton = FilterButton
1409 oDescriptor.RowGrand = RowTotals
1410 oDescriptor.ColumnGrand = ColumnTotals
1411 oPivotTables.insertNewByName(PivotTableName, oTargetAddress.XCellRange.getCellByPosition(0, 0).CellAddress, oDescriptor)
1413 &apos; Determine the range of the new pivot table
1414 Set oOutputRange = oPivotTables.getByName(PivotTableName).OutputRange
1415 With oOutputRange
1416 sPivotTable = _Component.getSheets().getCellRangeByPosition(.StartColumn, .StartRow, .EndColumn, .EndRow, .Sheet).AbsoluteName
1417 End With
1419 Finally:
1420 CreatePivotTable = sPivotTable
1421 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1422 Exit Function
1423 Catch:
1424 GoTo Finally
1425 End Function &apos; SFDocuments.SF_Calc.CreatePivotTable
1427 REM -----------------------------------------------------------------------------
1428 Public Function DAvg(Optional ByVal Range As Variant) As Double
1429 &apos;&apos;&apos; Get the average of the numeric values stored in the given range
1430 &apos;&apos;&apos; Args:
1431 &apos;&apos;&apos; Range : the range as a string where to get the values from
1432 &apos;&apos;&apos; Returns:
1433 &apos;&apos;&apos; The average of the numeric values as a double
1434 &apos;&apos;&apos; Examples:
1435 &apos;&apos;&apos; Val = oDoc.DAvg(&quot;~.A1:A1000&quot;)
1437 Try:
1438 DAvg = _DFunction(&quot;DAvg&quot;, Range)
1440 Finally:
1441 Exit Function
1442 End Function &apos; SFDocuments.SF_Calc.DAvg
1444 REM -----------------------------------------------------------------------------
1445 Public Function DCount(Optional ByVal Range As Variant) As Long
1446 &apos;&apos;&apos; Get the number of numeric values stored in the given range
1447 &apos;&apos;&apos; Args:
1448 &apos;&apos;&apos; Range : the range as a string where to get the values from
1449 &apos;&apos;&apos; Returns:
1450 &apos;&apos;&apos; The number of numeric values as a Long
1451 &apos;&apos;&apos; Examples:
1452 &apos;&apos;&apos; Val = oDoc.DCount(&quot;~.A1:A1000&quot;)
1454 Try:
1455 DCount = _DFunction(&quot;DCount&quot;, Range)
1457 Finally:
1458 Exit Function
1459 End Function &apos; SFDocuments.SF_Calc.DCount
1461 REM -----------------------------------------------------------------------------
1462 Public Function DMax(Optional ByVal Range As Variant) As Double
1463 &apos;&apos;&apos; Get the greatest of the numeric values stored in the given range
1464 &apos;&apos;&apos; Args:
1465 &apos;&apos;&apos; Range : the range as a string where to get the values from
1466 &apos;&apos;&apos; Returns:
1467 &apos;&apos;&apos; The greatest of the numeric values as a double
1468 &apos;&apos;&apos; Examples:
1469 &apos;&apos;&apos; Val = oDoc.DMax(&quot;~.A1:A1000&quot;)
1471 Try:
1472 DMax = _DFunction(&quot;DMax&quot;, Range)
1474 Finally:
1475 Exit Function
1476 End Function &apos; SFDocuments.SF_Calc.DMax
1478 REM -----------------------------------------------------------------------------
1479 Public Function DMin(Optional ByVal Range As Variant) As Double
1480 &apos;&apos;&apos; Get the smallest of the numeric values stored in the given range
1481 &apos;&apos;&apos; Args:
1482 &apos;&apos;&apos; Range : the range as a string where to get the values from
1483 &apos;&apos;&apos; Returns:
1484 &apos;&apos;&apos; The smallest of the numeric values as a double
1485 &apos;&apos;&apos; Examples:
1486 &apos;&apos;&apos; Val = oDoc.DMin(&quot;~.A1:A1000&quot;)
1488 Try:
1489 DMin = _DFunction(&quot;DMin&quot;, Range)
1491 Finally:
1492 Exit Function
1493 End Function &apos; SFDocuments.SF_Calc.DMin
1495 REM -----------------------------------------------------------------------------
1496 Public Function DSum(Optional ByVal Range As Variant) As Double
1497 &apos;&apos;&apos; Get sum of the numeric values stored in the given range
1498 &apos;&apos;&apos; Args:
1499 &apos;&apos;&apos; Range : the range as a string where to get the values from
1500 &apos;&apos;&apos; Returns:
1501 &apos;&apos;&apos; The sum of the numeric values as a double
1502 &apos;&apos;&apos; Examples:
1503 &apos;&apos;&apos; Val = oDoc.DSum(&quot;~.A1:A1000&quot;)
1505 Try:
1506 DSum = _DFunction(&quot;DSum&quot;, Range)
1508 Finally:
1509 Exit Function
1510 End Function &apos; SFDocuments.SF_Calc.DSum
1512 REM -----------------------------------------------------------------------------
1513 Public Function ExportRangeToFile(Optional ByVal Range As Variant _
1514 , Optional ByVal FileName As Variant _
1515 , Optional ByVal ImageType As Variant _
1516 , Optional ByVal Overwrite As Variant _
1517 ) As Boolean
1518 &apos;&apos;&apos; Store the given range as an image to the given file location
1519 &apos;&apos;&apos; Actual selections are not impacted
1520 &apos;&apos;&apos; Inspired by https://stackoverflow.com/questions/30509532/how-to-export-cell-range-to-pdf-file
1521 &apos;&apos;&apos; Args:
1522 &apos;&apos;&apos; Range: sheet name or cell range to be exported, as a string
1523 &apos;&apos;&apos; FileName: Identifies the file where to save. It must follow the SF_FileSystem.FileNaming notation
1524 &apos;&apos;&apos; ImageType: the name of the targeted media type
1525 &apos;&apos;&apos; Allowed values: jpeg, pdf (default) and png
1526 &apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
1527 &apos;&apos;&apos; Returns:
1528 &apos;&apos;&apos; False if the document could not be saved
1529 &apos;&apos;&apos; Exceptions:
1530 &apos;&apos;&apos; RANGEEXPORTERROR The destination has its readonly attribute set or overwriting rejected
1531 &apos;&apos;&apos; Examples:
1532 &apos;&apos;&apos; oDoc.ExportRangeToFile(&apos;SheetX.B2:J15&quot;, &quot;C:\Me\Range2.png&quot;, ImageType := &quot;png&quot;, Overwrite := True)
1534 Dim bSaved As Boolean &apos; return value
1535 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1536 Dim sFile As String &apos; Alias of FileName
1537 Dim vStoreArguments As Variant &apos; Array of com.sun.star.beans.PropertyValue
1538 Dim vFilterData As Variant &apos; Array of com.sun.star.beans.PropertyValue
1539 Dim FSO As Object &apos; SF_FileSystem
1540 Dim vImageTypes As Variant &apos; Array of permitted image types
1541 Dim vFilters As Variant &apos; Array of corresponding filters in the same order as vImageTypes
1542 Dim sFilter As String &apos; The filter to apply
1543 Dim oSelect As Object &apos; Currently selected range(s)
1544 Dim oAddress As Object &apos; Alias of Range
1546 Const cstImageTypes = &quot;jpeg,pdf,png&quot;
1547 Const cstFilters = &quot;calc_jpg_Export,calc_pdf_Export,calc_png_Export&quot;
1549 Const cstThisSub = &quot;SFDocuments.Calc.ExportRangeToFile&quot;
1550 Const cstSubArgs = &quot;Range, FileName, [ImageType=&quot;&quot;pdf&quot;&quot;|&quot;&quot;jpeg&quot;&quot;|&quot;&quot;png&quot;&quot;], [Overwrite=False]&quot;
1552 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
1553 bSaved = False
1555 Check:
1556 If IsMissing(ImageType) Or IsEmpty(ImageType) Then ImageType = &quot;pdf&quot;
1557 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
1559 vImageTypes = Split(cstImageTypes, &quot;,&quot;)
1560 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1561 If Not _IsStillAlive() Then GoTo Finally
1562 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
1563 If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1564 If Not ScriptForge.SF_Utils._Validate(ImageType, &quot;ImageType&quot;, V_STRING, vImageTypes) Then GoTo Finally
1565 If Not ScriptForge.SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1566 End If
1568 &apos; Check destination file overwriting
1569 Set FSO = CreateScriptService(&quot;FileSystem&quot;)
1570 sFile = FSO._ConvertToUrl(FileName)
1571 If FSO.FileExists(FileName) Then
1572 If Overwrite = False Then GoTo CatchError
1573 Set oSfa = ScriptForge.SF_Utils._GetUNOService(&quot;FileAccess&quot;)
1574 If oSfa.isReadonly(sFile) Then GoTo CatchError
1575 End If
1577 Try:
1578 &apos; Setup arguments
1579 vFilters = Split(cstFilters, &quot;,&quot;)
1580 sFilter = vFilters(ScriptForge.SF_Array.IndexOf(vImageTypes, ImageType, CaseSensitive := False))
1581 Set oAddress = _ParseAddress(Range)
1583 &apos; The filter arguments differ between
1584 &apos; 1) pdf : store range in Selection property value
1585 &apos; 2) png, jpeg : save current selection, select range, restore initial selection
1586 If LCase(ImageType) = &quot;pdf&quot; Then
1587 vFilterData = Array(ScriptForge.SF_Utils._MakePropertyValue(&quot;Selection&quot;, oAddress.XCellRange) )
1588 vStoreArguments = Array( _
1589 ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, sFilter) _
1590 , ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterData&quot;, vFilterData) _
1592 Else &apos; png, jpeg
1593 &apos; Save the current selection(s)
1594 Set oSelect = _Component.CurrentController.getSelection()
1595 _Component.CurrentController.select(oAddress.XCellRange)
1596 vStoreArguments = Array( _
1597 ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, sFilter) _
1598 , ScriptForge.SF_Utils._MakePropertyValue(&quot;SelectionOnly&quot;, True) _
1600 End If
1602 &apos; Apply the filter and export
1603 _Component.storeToUrl(sFile, vStoreArguments)
1604 If LCase(ImageType) &lt;&gt; &quot;pdf&quot; Then _RestoreSelections(_Component, oSelect)
1606 bSaved = True
1608 Finally:
1609 ExportRangeToFile = bSaved
1610 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1611 Exit Function
1612 Catch:
1613 GoTo Finally
1614 CatchError:
1615 ScriptForge.SF_Exception.RaiseFatal(RANGEEXPORTERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite)
1616 GoTo Finally
1617 End Function &apos; SFDocuments.SF_Chart.ExportRangeToFile
1619 REM -----------------------------------------------------------------------------
1620 Public Function Forms(Optional ByVal SheetName As Variant _
1621 , Optional ByVal Form As Variant _
1622 ) As Variant
1623 &apos;&apos;&apos; Return either
1624 &apos;&apos;&apos; - the list of the Forms contained in the given sheet
1625 &apos;&apos;&apos; - a SFDocuments.Form object based on its name or its index
1626 &apos;&apos;&apos; Args:
1627 &apos;&apos;&apos; SheetName: the name of the sheet containing the requested form or forms
1628 &apos;&apos;&apos; Form: a form stored in the document given by its name or its index
1629 &apos;&apos;&apos; When absent, the list of available forms is returned
1630 &apos;&apos;&apos; To get the first (unique ?) form stored in the form document, set Form = 0
1631 &apos;&apos;&apos; Exceptions:
1632 &apos;&apos;&apos; CALCFORMNOTFOUNDERROR Form not found
1633 &apos;&apos;&apos; Returns:
1634 &apos;&apos;&apos; A zero-based array of strings if Form is absent
1635 &apos;&apos;&apos; An instance of the SF_Form class if Form exists
1636 &apos;&apos;&apos; Example:
1637 &apos;&apos;&apos; Dim myForm As Object, myList As Variant
1638 &apos;&apos;&apos; myList = oDoc.Forms(&quot;ThisSheet&quot;)
1639 &apos;&apos;&apos; Set myForm = oDoc.Forms(&quot;ThisSheet&quot;, 0)
1641 Dim oForm As Object &apos; The new Form class instance
1642 Dim oMainForm As Object &apos; com.sun.star.comp.sdb.Content
1643 Dim oXForm As Object &apos; com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
1644 Dim vFormNames As Variant &apos; Array of form names
1645 Dim oForms As Object &apos; Forms collection
1646 Const cstDrawPage = -1 &apos; There is no DrawPages collection in Calc sheets
1648 Const cstThisSub = &quot;SFDocuments.Calc.Forms&quot;
1649 Const cstSubArgs = &quot;SheetName, [Form=&quot;&quot;&quot;&quot;]&quot;
1651 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1653 Check:
1654 If IsMissing(Form) Or IsEmpty(Form) Then Form = &quot;&quot;
1655 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1656 If Not _IsStillAlive() Then GoTo Finally
1657 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
1658 If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
1659 End If
1661 Try:
1662 &apos; Start from the Calc sheet and go down to forms
1663 Set oForms = _Component.getSheets.getByName(SheetName).DrawPage.Forms
1664 vFormNames = oForms.getElementNames()
1666 If Len(Form) = 0 Then &apos; Return the list of valid form names
1667 Forms = vFormNames
1668 Else
1669 If VarType(Form) = V_STRING Then &apos; Find the form by name
1670 If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, V_STRING, vFormNames, True) Then GoTo Finally
1671 Set oXForm = oForms.getByName(Form)
1672 Else &apos; Find the form by index
1673 If Form &lt; 0 Or Form &gt;= oForms.Count Then GoTo CatchNotFound
1674 Set oXForm = oForms.getByIndex(Form)
1675 End If
1676 &apos; Create the new Form class instance
1677 Set oForm = SF_Register._NewForm(oXForm)
1678 With oForm
1679 Set .[_Parent] = [Me]
1680 ._SheetName = SheetName
1681 ._FormType = ISCALCFORM
1682 Set ._Component = _Component
1683 ._Initialize()
1684 End With
1685 Set Forms = oForm
1686 End If
1688 Finally:
1689 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1690 Exit Function
1691 Catch:
1692 GoTo Finally
1693 CatchNotFound:
1694 ScriptForge.SF_Exception.RaiseFatal(CALCFORMNOTFOUNDERROR, Form, _FileIdent())
1695 End Function &apos; SFDocuments.SF_Calc.Forms
1697 REM -----------------------------------------------------------------------------
1698 Function GetColumnName(Optional ByVal ColumnNumber As Variant) As String
1699 &apos;&apos;&apos; Convert a column number (range 1, 2,..16384) into its letter counterpart (range &apos;A&apos;, &apos;B&apos;,..&apos;XFD&apos;).
1700 &apos;&apos;&apos; Args:
1701 &apos;&apos;&apos; ColumnNumber: the column number, must be in the interval 1 ... 16384
1702 &apos;&apos;&apos; Returns:
1703 &apos;&apos;&apos; a string representation of the column name, in range &apos;A&apos;..&apos;XFD&apos;
1704 &apos;&apos;&apos; If ColumnNumber is not in the allowed range, returns a zero-length string
1705 &apos;&apos;&apos; Example:
1706 &apos;&apos;&apos; MsgBox oDoc.GetColumnName(1022) &apos; &quot;AMH&quot;
1707 &apos;&apos;&apos; Adapted from a Python function by sundar nataraj
1708 &apos;&apos;&apos; http://stackoverflow.com/questions/23861680/convert-spreadsheet-number-to-column-letter
1710 Dim sCol As String &apos; Return value
1711 Const cstThisSub = &quot;SFDocuments.Calc.GetColumnName&quot;
1712 Const cstSubArgs = &quot;ColumnNumber&quot;
1714 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1715 sCol = &quot;&quot;
1717 Check:
1718 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1719 If Not SF_Utils._Validate(ColumnNumber, &quot;ColumnNumber&quot;, V_NUMERIC) Then GoTo Finally
1720 End If
1722 Try:
1723 If (ColumnNumber &gt; 0) And (ColumnNumber &lt;= MAXCOLS) Then sCol = _GetColumnName(ColumnNumber)
1725 Finally:
1726 GetColumnName = sCol
1727 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1728 Exit Function
1729 Catch:
1730 GoTo Finally
1731 End Function &apos; SFDocuments.SF_Calc.GetColumnName
1733 REM -----------------------------------------------------------------------------
1734 Public Function GetFormula(Optional ByVal Range As Variant) As Variant
1735 &apos;&apos;&apos; Get the formula(e) stored in the given range of cells
1736 &apos;&apos;&apos; Args:
1737 &apos;&apos;&apos; Range : the range as a string where to get the formula from
1738 &apos;&apos;&apos; Returns:
1739 &apos;&apos;&apos; A scalar, a zero-based 1D array or a zero-based 2D array of strings
1740 &apos;&apos;&apos; Examples:
1741 &apos;&apos;&apos; Val = oDoc.GetFormula(&quot;~.A1:A1000&quot;)
1743 Dim vGet As Variant &apos; Return value
1744 Dim oAddress As Object &apos; Alias of Range
1745 Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
1746 Const cstThisSub = &quot;SFDocuments.Calc.GetFormula&quot;
1747 Const cstSubArgs = &quot;Range&quot;
1749 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1750 vGet = Empty
1752 Check:
1753 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1754 If Not _IsStillAlive() Then GoTo Finally
1755 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
1756 End If
1758 Try:
1759 &apos; Get the data
1760 Set oAddress = _ParseAddress(Range)
1761 vDataArray = oAddress.XCellRange.getFormulaArray()
1763 &apos; Convert the data array to scalar, vector or array
1764 vGet = ScriptForge.SF_Array.ConvertFromDataArray(vDataArray)
1766 Finally:
1767 GetFormula = vGet
1768 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1769 Exit Function
1770 Catch:
1771 GoTo Finally
1772 End Function &apos; SFDocuments.SF_Calc.GetFormula
1774 REM -----------------------------------------------------------------------------
1775 Public Function GetProperty(Optional ByVal PropertyName As Variant _
1776 , Optional ObjectName As Variant _
1777 ) As Variant
1778 &apos;&apos;&apos; Return the actual value of the given property
1779 &apos;&apos;&apos; Args:
1780 &apos;&apos;&apos; PropertyName: the name of the property as a string
1781 &apos;&apos;&apos; ObjectName: a sheet or range name
1782 &apos;&apos;&apos; Returns:
1783 &apos;&apos;&apos; The actual value of the property
1784 &apos;&apos;&apos; Exceptions:
1785 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
1787 Const cstThisSub = &quot;SFDocuments.Calc.GetProperty&quot;
1788 Const cstSubArgs = &quot;&quot;
1790 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1791 GetProperty = Null
1793 Check:
1794 If IsMissing(ObjectName) Or IsEMpty(ObjectName) Then ObjectName = &quot;&quot;
1795 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1796 If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
1797 If Not ScriptForge.SF_Utils._Validate(ObjectName, &quot;ObjectName&quot;, V_STRING) Then GoTo Catch
1798 End If
1800 Try:
1801 &apos; Superclass or subclass property ?
1802 If ScriptForge.SF_Array.Contains([_Super].Properties(), PropertyName) Then
1803 GetProperty = [_Super].GetProperty(PropertyName)
1804 ElseIf Len(ObjectName) = 0 Then
1805 GetProperty = _PropertyGet(PropertyName)
1806 Else
1807 GetProperty = _PropertyGet(PropertyName, ObjectName)
1808 End If
1810 Finally:
1811 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1812 Exit Function
1813 Catch:
1814 GoTo Finally
1815 End Function &apos; SFDocuments.SF_Calc.GetProperty
1817 REM -----------------------------------------------------------------------------
1818 Public Function GetValue(Optional ByVal Range As Variant) As Variant
1819 &apos;&apos;&apos; Get the value(s) stored in the given range of cells
1820 &apos;&apos;&apos; Args:
1821 &apos;&apos;&apos; Range : the range as a string where to get the value from
1822 &apos;&apos;&apos; Returns:
1823 &apos;&apos;&apos; A scalar, a zero-based 1D array or a zero-based 2D array of strings and doubles
1824 &apos;&apos;&apos; To convert doubles to dates, use the CDate builtin function
1825 &apos;&apos;&apos; Examples:
1826 &apos;&apos;&apos; Val = oDoc.GetValue(&quot;~.A1:A1000&quot;)
1828 Dim vGet As Variant &apos; Return value
1829 Dim oAddress As Object &apos; Alias of Range
1830 Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
1831 Const cstThisSub = &quot;SFDocuments.Calc.GetValue&quot;
1832 Const cstSubArgs = &quot;Range&quot;
1834 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1835 vGet = Empty
1837 Check:
1838 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1839 If Not _IsStillAlive() Then GoTo Finally
1840 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
1841 End If
1843 Try:
1844 &apos; Get the data
1845 Set oAddress = _ParseAddress(Range)
1846 vDataArray = oAddress.XCellRange.getDataArray()
1848 &apos; Convert the data array to scalar, vector or array
1849 vGet = ScriptForge.SF_Array.ConvertFromDataArray(vDataArray)
1851 Finally:
1852 GetValue = vGet
1853 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1854 Exit Function
1855 Catch:
1856 GoTo Finally
1857 End Function &apos; SFDocuments.SF_Calc.GetValue
1859 REM -----------------------------------------------------------------------------
1860 Public Function ImportFromCSVFile(Optional ByVal FileName As Variant _
1861 , Optional ByVal DestinationCell As Variant _
1862 , Optional ByVal FilterOptions As Variant _
1863 ) As String
1864 &apos;&apos;&apos; Import the content of a CSV-formatted text file starting from a given cell
1865 &apos;&apos;&apos; Beforehand the destination area will be cleared from any content and format
1866 &apos;&apos;&apos; Args:
1867 &apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
1868 &apos;&apos;&apos; DestinationCell: the destination of the copied range of cells, as a string
1869 &apos;&apos;&apos; If given as range, the destination will be reduced to its top-left cell
1870 &apos;&apos;&apos; FilterOptions: The arguments of the CSV input filter.
1871 &apos;&apos;&apos; Read https://wiki.documentfoundation.org/Documentation/DevGuide/Spreadsheet_Documents#Filter_Options_for_the_CSV_Filter
1872 &apos;&apos;&apos; Default: input file encoding is UTF8
1873 &apos;&apos;&apos; separator = comma, semi-colon or tabulation
1874 &apos;&apos;&apos; string delimiter = double quote
1875 &apos;&apos;&apos; all lines are included
1876 &apos;&apos;&apos; quoted strings are formatted as texts
1877 &apos;&apos;&apos; special numbers are detected
1878 &apos;&apos;&apos; all columns are presumed texts
1879 &apos;&apos;&apos; language = english/US =&gt; decimal separator is &quot;.&quot;, thousands separator = &quot;,&quot;
1880 &apos;&apos;&apos; Returns:
1881 &apos;&apos;&apos; A string representing the modified range of cells
1882 &apos;&apos;&apos; The modified area depends only on the content of the source file
1883 &apos;&apos;&apos; Exceptions:
1884 &apos;&apos;&apos; DOCUMENTOPENERROR The csv file could not be opened
1885 &apos;&apos;&apos; Examples:
1886 &apos;&apos;&apos; oDoc.ImportFromCSVFile(&quot;C:\Temp\myCsvFile.csv&quot;, &quot;SheetY.C5&quot;)
1888 Dim sImport As String &apos; Return value
1889 Dim oUI As Object &apos; UI service
1890 Dim oSource As Object &apos; New Calc document with csv loaded
1891 Dim oSelect As Object &apos; Current selection in destination
1893 Const cstFilter = &quot;Text - txt - csv (StarCalc)&quot;
1894 Const cstFilterOptions = &quot;9/44/59/MRG,34,76,1,,1033,true,true&quot;
1895 Const cstThisSub = &quot;SFDocuments.Calc.ImportFromCSVFile&quot;
1896 Const cstSubArgs = &quot;FileName, DestinationCell, [FilterOptions]=&quot;&quot;9/44/59/MRG,34,76,1,,1033,true,true&quot;&quot;&quot;
1898 &apos; If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1899 sImport = &quot;&quot;
1901 Check:
1902 If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = cstFilterOptions
1903 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1904 If Not _IsStillAlive(True) Then GoTo Finally
1905 If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1906 If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
1907 End If
1909 Try:
1910 &apos; Input file is loaded in an empty worksheet. Data are copied to destination cell
1911 Set oUI = CreateScriptService(&quot;UI&quot;)
1912 Set oSource = oUI.OpenDocument(FileName _
1913 , ReadOnly := True _
1914 , Hidden := True _
1915 , FilterName := cstFilter _
1916 , FilterOptions := FilterOptions _
1918 &apos; Remember current selection and restore it after copy
1919 Set oSelect = _Component.CurrentController.getSelection()
1920 sImport = CopyToCell(oSource.Range(&quot;*&quot;), DestinationCell)
1921 _RestoreSelections(_Component, oSelect)
1923 Finally:
1924 If Not IsNull(oSource) Then oSource.CloseDocument(False)
1925 ImportFromCSVFile = sImport
1926 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
1927 Exit Function
1928 Catch:
1929 GoTo Finally
1930 End Function &apos; SFDocuments.SF_Calc.ImportFromCSVFile
1932 REM -----------------------------------------------------------------------------
1933 Public Sub ImportFromDatabase(Optional ByVal FileName As Variant _
1934 , Optional ByVal RegistrationName As Variant _
1935 , Optional ByVal DestinationCell As Variant _
1936 , Optional ByVal SQLCommand As Variant _
1937 , Optional ByVal DirectSQL As Variant _
1939 &apos;&apos;&apos; Import the content of a database table, query or resultset, i.e. the result of a SELECT SQL command,
1940 &apos;&apos;&apos; starting from a given cell
1941 &apos;&apos;&apos; Beforehand the destination area will be cleared from any content and format
1942 &apos;&apos;&apos; The modified area depends only on the content of the source data
1943 &apos;&apos;&apos; Args:
1944 &apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
1945 &apos;&apos;&apos; RegistrationName: the name of a registered database
1946 &apos;&apos;&apos; It is ignored if FileName &lt;&gt; &quot;&quot;
1947 &apos;&apos;&apos; DestinationCell: the destination of the copied range of cells, as a string
1948 &apos;&apos;&apos; If given as a range of cells, the destination will be reduced to its top-left cell
1949 &apos;&apos;&apos; SQLCommand: either a table or query name (without square brackets)
1950 &apos;&apos;&apos; or a full SQL commands where table and fieldnames are preferably surrounded with square brackets
1951 &apos;&apos;&apos; Returns:
1952 &apos;&apos;&apos; Implemented as a Sub because the doImport UNO method does not return any error
1953 &apos;&apos;&apos; Exceptions:
1954 &apos;&apos;&apos; BASEDOCUMENTOPENERROR The database file could not be opened
1955 &apos;&apos;&apos; Examples:
1956 &apos;&apos;&apos; oDoc.ImportFromDatabase(&quot;C:\Temp\myDbFile.odb&quot;, , &quot;SheetY.C5&quot;, &quot;SELECT * FROM [Employees] ORDER BY [LastName]&quot;)
1958 Dim oDBContext As Object &apos; com.sun.star.sdb.DatabaseContext
1959 Dim oDatabase As Object &apos; SFDatabases.Database service
1960 Dim lCommandType As Long &apos; A com.sun.star.sheet.DataImportMode.xxx constant
1961 Dim oQuery As Object &apos; com.sun.star.ucb.XContent
1962 Dim bDirect As Boolean &apos; Alias of DirectSQL
1963 Dim oDestRange As Object &apos; Destination as a range
1964 Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
1965 Dim oDestCell As Object &apos; com.sun.star.table.XCell
1966 Dim oSelect As Object &apos; Current selection in destination
1967 Dim vImportOptions As Variant &apos; Array of PropertyValues
1969 Const cstThisSub = &quot;SFDocuments.Calc.ImportFromDatabase&quot;
1970 Const cstSubArgs = &quot;[FileName=&quot;&quot;&quot;&quot;], [RegistrationName=&quot;&quot;&quot;&quot;], DestinationCell, SQLCommand, [DirectSQL=False]&quot;
1972 &apos; If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1974 Check:
1976 If IsMissing(FileName) Or IsEmpty(FileName) Then FileName = &quot;&quot;
1977 If IsMissing(RegistrationName) Or IsEmpty(RegistrationName) Then RegistrationName = &quot;&quot;
1978 If IsMissing(DirectSQL) Or IsEmpty(DirectSQL) Then DirectSQL = False
1979 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1980 If Not _IsStillAlive(True) Then GoTo Finally
1981 If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, , True) Then GoTo Finally
1982 If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
1983 If Not ScriptForge.SF_Utils._Validate(SQLCommand, &quot;SQLCommand&quot;, V_STRING) Then GoTo Finally
1984 If Not ScriptForge.SF_Utils._Validate(DirectSQL, &quot;DirectSQL&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
1985 End If
1987 &apos; Check the existence of FileName
1988 If Len(FileName) = 0 Then &apos; FileName has precedence over RegistrationName
1989 If Len(RegistrationName) = 0 Then GoTo CatchError
1990 Set oDBContext = ScriptForge.SF_Utils._GetUNOService(&quot;DatabaseContext&quot;)
1991 If Not oDBContext.hasRegisteredDatabase(RegistrationName) Then GoTo CatchError
1992 FileName = ScriptForge.SF_FileSystem._ConvertFromUrl(oDBContext.getDatabaseLocation(RegistrationName))
1993 End If
1994 If Not ScriptForge.SF_FileSystem.FileExists(FileName) Then GoTo CatchError
1996 Try:
1997 &apos; Check command type
1998 Set oDatabase = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Database&quot;, FileName, , True) &apos; Read-only
1999 If IsNull(oDatabase) Then GoTo CatchError
2000 With oDatabase
2001 If ScriptForge.SF_Array.Contains(.Tables, SQLCommand) Then
2002 bDirect = True
2003 lCommandType = com.sun.star.sheet.DataImportMode.TABLE
2004 ElseIf ScriptForge.SF_Array.Contains(.Queries, SQLCommand) Then
2005 Set oQuery = .XConnection.Queries.getByName(SQLCommand)
2006 bDirect = Not oQuery.EscapeProcessing
2007 lCommandType = com.sun.star.sheet.DataImportMode.QUERY
2008 Else
2009 bDirect = DirectSQL
2010 lCommandType = com.sun.star.sheet.DataImportMode.SQL
2011 SQLCommand = ._ReplaceSquareBrackets(SQLCommand)
2012 End If
2013 .CloseDatabase()
2014 Set oDatabase = oDatabase.Dispose()
2015 End With
2017 &apos; Determine the destination cell as the top-left coordinates of the given range
2018 Set oDestRange = _ParseAddress(DestinationCell)
2019 Set oDestAddress = oDestRange.XCellRange.RangeAddress
2020 Set oDestCell = oDestRange.XSpreadsheet.getCellByPosition(oDestAddress.StartColumn, oDestAddress.StartRow)
2022 &apos; Remember current selection
2023 Set oSelect = _Component.CurrentController.getSelection()
2024 &apos; Import arguments
2025 vImportOptions = Array(_
2026 ScriptForge.SF_Utils._MakePropertyValue(&quot;DatabaseName&quot;, ScriptForge.SF_FileSystem._ConvertToUrl(FileName)) _
2027 , ScriptForge.SF_Utils._MakePropertyValue(&quot;SourceObject&quot;, SQLCommand) _
2028 , ScriptForge.SF_Utils._MakePropertyValue(&quot;SourceType&quot;, lCommandType) _
2029 , ScriptForge.SF_Utils._MakePropertyValue(&quot;IsNative&quot;, bDirect) _
2031 oDestCell.doImport(vImportOptions)
2032 &apos; Restore selection after import_
2033 _RestoreSelections(_Component, oSelect)
2035 Finally:
2036 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2037 Exit Sub
2038 Catch:
2039 GoTo Finally
2040 CatchError:
2041 SF_Exception.RaiseFatal(BASEDOCUMENTOPENERROR, &quot;FileName&quot;, FileName, &quot;RegistrationName&quot;, RegistrationName)
2042 GoTo Finally
2043 End Sub &apos; SFDocuments.SF_Calc.ImportFromDatabase
2045 REM -----------------------------------------------------------------------------
2046 Public Function InsertSheet(Optional ByVal SheetName As Variant _
2047 , Optional ByVal BeforeSheet As Variant _
2048 ) As Boolean
2049 &apos;&apos;&apos; Insert a new empty sheet before an existing sheet or at the end of the list of sheets
2050 &apos;&apos;&apos; Args:
2051 &apos;&apos;&apos; SheetName: The name of the new sheet
2052 &apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to insert
2053 &apos;&apos;&apos; Returns:
2054 &apos;&apos;&apos; True if the sheet could be inserted successfully
2055 &apos;&apos;&apos; Examples:
2056 &apos;&apos;&apos; oDoc.InsertSheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
2058 Dim bInsert As Boolean &apos; Return value
2059 Dim vSheets As Variant &apos; List of existing sheets
2060 Dim lSheetIndex As Long &apos; Index of a sheet
2061 Const cstThisSub = &quot;SFDocuments.Calc.InsertSheet&quot;
2062 Const cstSubArgs = &quot;SheetName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
2064 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2065 bInsert = False
2067 Check:
2068 If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
2069 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2070 If Not _IsStillAlive(True) Then GoTo Finally
2071 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, True) Then GoTo Finally
2072 If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
2073 End If
2074 vSheets = _Component.getSheets.getElementNames()
2076 Try:
2077 If VarType(BeforeSheet) = V_STRING Then
2078 lSheetIndex = ScriptForge.SF_Array.IndexOf(vSheets, BeforeSheet)
2079 Else
2080 lSheetIndex = BeforeSheet - 1
2081 If lSheetIndex &lt; 0 Then lSheetIndex = 0
2082 If lSheetIndex &gt; UBound(vSheets) Then lSheetIndex = UBound(vSheets) + 1
2083 End If
2084 _Component.getSheets.insertNewByName(SheetName, lSheetIndex)
2085 bInsert = True
2087 Finally:
2088 InsertSheet = binsert
2089 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2090 Exit Function
2091 Catch:
2092 GoTo Finally
2093 End Function &apos; SFDocuments.SF_Calc.InsertSheet
2095 REM -----------------------------------------------------------------------------
2096 Public Function Intersect(Optional ByVal Range1 As Variant _
2097 , Optional ByVal Range2 As Variant _
2098 ) As String
2099 &apos;&apos;&apos; Returns the cell range as a string that is common to the input ranges
2100 &apos;&apos;&apos; Args:
2101 &apos;&apos;&apos; Range1: a first range as a string
2102 &apos;&apos;&apos; Range2: a second range as a string
2103 &apos;&apos;&apos; Returns:
2104 &apos;&apos;&apos; The intersection, as a string, representing the range common to both input ranges,
2105 &apos;&apos;&apos; or a zero-length string when the intersection is empty.
2106 &apos;&apos;&apos; Example:
2107 &apos;&apos;&apos; calc.Intersect(&quot;J7:M11&quot;, &quot;$Sheet2.$L$10:$N$17&quot;)
2108 &apos;&apos;&apos; &apos; $Sheet2.$L$10:$M$11 when Sheet2 is the current sheet, otherwise the empty string
2110 Dim sIntersect As String &apos; Return value
2111 Dim oRangeAddress1 As Object &apos; SF_UI._Address type
2112 Dim oRangeAddress2 As Object &apos; SF_UI._Address type
2113 Dim oRange1 As Object &apos; com.sun.star.table.CellRangeAddress
2114 Dim oRange2 As Object &apos; com.sun.star.table.CellRangeAddress
2115 Dim lStartRow As Long &apos; Intersection starting row
2116 Dim lEndRow As Long &apos; Intersection ending row
2117 Dim lStartColumn As Long &apos; Intersection starting column
2118 Dim lEndColumn As Long &apos; Intersection ending column
2120 Const cstThisSub = &quot;SFDocuments.Calc.Intersect&quot;
2121 Const cstSubArgs = &quot;Range1, Range2&quot;
2123 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2124 sIntersect = &quot;&quot;
2126 Check:
2127 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2128 If Not _IsStillAlive(True) Then GoTo Finally
2129 If Not ScriptForge.SF_Utils._Validate(Range1, &quot;Range1&quot;, V_STRING) Then GoTo Finally
2130 If Not ScriptForge.SF_Utils._Validate(Range2, &quot;Range2&quot;, V_STRING) Then GoTo Finally
2131 End If
2133 Set oRangeAddress1 = _ParseAddress(Range1)
2134 Set oRange1 = oRangeAddress1.XCellRange.RangeAddress
2135 Set oRangeAddress2 = _ParseAddress(Range2)
2136 Set oRange2 = oRangeAddress2.XCellRange.RangeAddress
2138 If oRangeAddress1.SheetName &lt;&gt; oRangeAddress2.SheetName Then GoTo Finally
2140 Try:
2141 &apos; Find the top-left and bottom-right coordinates of the intersection
2142 lStartRow = Iif(oRange1.StartRow &gt; oRange2.StartRow, oRange1.StartRow, oRange2.StartRow) + 1
2143 lStartColumn = Iif(oRange1.StartColumn &gt; oRange2.StartColumn, oRange1.StartColumn, oRange2.StartColumn) + 1
2144 lEndRow = Iif(oRange1.EndRow &lt; oRange2.EndRow, oRange1.EndRow, oRange2.EndRow) + 1
2145 lEndColumn = Iif(oRange1.EndColumn &lt; oRange2.EndColumn, oRange1.EndColumn, oRange2.EndColumn) + 1
2147 &apos; Check that the 2 ranges overlap each other
2148 If lStartRow &lt;= lEndRow And lStartColumn &lt;= lEndColumn Then
2149 sIntersect = A1Style(lStartRow, lStartColumn, lEndRow, lEndColumn, oRangeAddress1.SheetName)
2150 End If
2152 Finally:
2153 Intersect = sIntersect
2154 &apos;ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2155 Exit Function
2156 Catch:
2157 GoTo Finally
2158 End Function &apos; SFDocuments.SF_Calc.Intersect
2160 REM -----------------------------------------------------------------------------
2161 Public Function Methods() As Variant
2162 &apos;&apos;&apos; Return the list of public methods of the Calc service as an array
2164 Methods = Array( _
2165 &quot;A1Style&quot; _
2166 , &quot;Charts&quot; _
2167 , &quot;ClearAll&quot; _
2168 , &quot;ClearFormats&quot; _
2169 , &quot;ClearValues&quot; _
2170 , &quot;CopySheet&quot; _
2171 , &quot;CopySheetFromFile&quot; _
2172 , &quot;CopyToCell&quot; _
2173 , &quot;CopyToRange&quot; _
2174 , &quot;CreateChart&quot; _
2175 , &quot;DAvg&quot; _
2176 , &quot;DCount&quot; _
2177 , &quot;DMax&quot; _
2178 , &quot;DMin&quot; _
2179 , &quot;DSum&quot; _
2180 , &quot;ExportRangeToFile&quot; _
2181 , &quot;GetColumnName&quot; _
2182 , &quot;GetFormula&quot; _
2183 , &quot;GetValue&quot; _
2184 , &quot;ImportFromCSVFile&quot; _
2185 , &quot;ImportFromDatabase&quot; _
2186 , &quot;InsertSheet&quot; _
2187 , &quot;Intersect&quot; _
2188 , &quot;MoveRange&quot; _
2189 , &quot;MoveSheet&quot; _
2190 , &quot;Offset&quot; _
2191 , &quot;OpenRangeSelector&quot; _
2192 , &quot;Printf&quot; _
2193 , &quot;PrintOut&quot; _
2194 , &quot;RemoveDuplicates&quot; _
2195 , &quot;RemoveSheet&quot; _
2196 , &quot;RenameSheet&quot; _
2197 , &quot;SetArray&quot; _
2198 , &quot;SetCellStyle&quot; _
2199 , &quot;SetFormula&quot; _
2200 , &quot;SetValue&quot; _
2201 , &quot;ShiftDown&quot; _
2202 , &quot;ShiftLeft&quot; _
2203 , &quot;ShiftRight&quot; _
2204 , &quot;ShiftUp&quot; _
2205 , &quot;SortRange&quot; _
2208 End Function &apos; SFDocuments.SF_Calc.Methods
2210 REM -----------------------------------------------------------------------------
2211 Public Function MoveRange(Optional ByVal Source As Variant _
2212 , Optional ByVal Destination As Variant _
2213 ) As String
2214 &apos;&apos;&apos; Move a specified source range to a destination range
2215 &apos;&apos;&apos; Args:
2216 &apos;&apos;&apos; Source: the source range of cells as a string
2217 &apos;&apos;&apos; Destination: the destination of the moved range of cells, as a string
2218 &apos;&apos;&apos; If given as a range of cells, the destination will be reduced to its top-left cell
2219 &apos;&apos;&apos; Returns:
2220 &apos;&apos;&apos; A string representing the modified range of cells
2221 &apos;&apos;&apos; The modified area depends only on the size of the source area
2222 &apos;&apos;&apos; Examples:
2223 &apos;&apos;&apos; oDoc.MoveRange(&quot;SheetX.A1:F10&quot;, &quot;SheetY.C5&quot;)
2225 Dim sMove As String &apos; Return value
2226 Dim oSource As Object &apos; Alias of Source to avoid &quot;Object variable not set&quot; run-time error
2227 Dim oSourceAddress As Object &apos; com.sun.star.table.CellRangeAddress
2228 Dim oDestRange As Object &apos; Destination as a range
2229 Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
2230 Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
2231 Dim oSelect As Object &apos; Current selection in source
2232 Dim oClipboard As Object &apos; com.sun.star.datatransfer.XTransferable
2233 Dim oCellRanges As Object &apos; com.sun.star.sheet.SheetCellRanges
2234 Dim vRangeAddresses As Variant &apos; Array of com.sun.star.table.CellRangeAddress
2235 Dim i As Long
2237 Const cstThisSub = &quot;SFDocuments.Calc.MoveRange&quot;
2238 Const cstSubArgs = &quot;Source, Destination&quot;
2240 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2241 sMove = &quot;&quot;
2243 Check:
2244 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2245 If Not _IsStillAlive(True) Then GoTo Finally
2246 If Not _Validate(Source, &quot;Source&quot;, V_STRING) Then GoTo Finally
2247 If Not _Validate(Destination, &quot;Destination&quot;, V_STRING) Then GoTo Finally
2248 End If
2250 Try:
2251 Set oSourceAddress = _ParseAddress(Source).XCellRange.RangeAddress
2252 Set oDestRange = _ParseAddress(Destination)
2253 Set oDestAddress = oDestRange.XCellRange.RangeAddress
2254 Set oDestCell = New com.sun.star.table.CellAddress
2255 With oDestAddress
2256 oDestCell.Sheet = .Sheet
2257 oDestCell.Column = .StartColumn
2258 oDestCell.Row = .StartRow
2259 End With
2260 oDestRange.XSpreadsheet.moveRange(oDestCell, oSourceAddress)
2262 With oSourceAddress
2263 sMove = _Offset(Destination, 0, 0, .EndRow - .StartRow + 1, .EndColumn - .StartColumn + 1).RangeName
2264 End With
2266 Finally:
2267 MoveRange = sMove
2268 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2269 Exit Function
2270 Catch:
2271 GoTo Finally
2272 End Function &apos; SFDocuments.SF_Calc.MoveRange
2274 REM -----------------------------------------------------------------------------
2275 Public Function MoveSheet(Optional ByVal SheetName As Variant _
2276 , Optional ByVal BeforeSheet As Variant _
2277 ) As Boolean
2278 &apos;&apos;&apos; Move a sheet before an existing sheet or at the end of the list of sheets
2279 &apos;&apos;&apos; Args:
2280 &apos;&apos;&apos; SheetName: The name of the sheet to move
2281 &apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to move the sheet
2282 &apos;&apos;&apos; Returns:
2283 &apos;&apos;&apos; True if the sheet could be moved successfully
2284 &apos;&apos;&apos; Examples:
2285 &apos;&apos;&apos; oDoc.MoveSheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
2287 Dim bMove As Boolean &apos; Return value
2288 Dim vSheets As Variant &apos; List of existing sheets
2289 Dim lSheetIndex As Long &apos; Index of a sheet
2290 Const cstThisSub = &quot;SFDocuments.Calc.MoveSheet&quot;
2291 Const cstSubArgs = &quot;SheetName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
2293 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2294 bMove = False
2296 Check:
2297 If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
2298 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2299 If Not _IsStillAlive(True) Then GoTo Finally
2300 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
2301 If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
2302 End If
2303 vSheets = _Component.getSheets.getElementNames()
2305 Try:
2306 If VarType(BeforeSheet) = V_STRING Then
2307 lSheetIndex = ScriptForge.SF_Array.IndexOf(vSheets, BeforeSheet)
2308 Else
2309 lSheetIndex = BeforeSheet - 1
2310 If lSheetIndex &lt; 0 Then lSheetIndex = 0
2311 If lSheetIndex &gt; UBound(vSheets) Then lSheetIndex = UBound(vSheets) + 1
2312 End If
2313 _Component.getSheets.MoveByName(SheetName, lSheetIndex)
2314 bMove = True
2316 Finally:
2317 MoveSheet = bMove
2318 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2319 Exit Function
2320 Catch:
2321 GoTo Finally
2322 End Function &apos; SFDocuments.SF_Calc.MoveSheet
2324 REM -----------------------------------------------------------------------------
2325 Public Function Offset(Optional ByRef Range As Variant _
2326 , Optional ByVal Rows As Variant _
2327 , Optional ByVal Columns As Variant _
2328 , Optional ByVal Height As Variant _
2329 , Optional ByVal Width As Variant _
2330 ) As String
2331 &apos;&apos;&apos; Returns a new range offset by a certain number of rows and columns from a given range
2332 &apos;&apos;&apos; Args:
2333 &apos;&apos;&apos; Range : the range, as a string, from which the function searches for the new range
2334 &apos;&apos;&apos; Rows : the number of rows by which the reference was corrected up (negative value) or down.
2335 &apos;&apos;&apos; Use 0 (default) to stay in the same row.
2336 &apos;&apos;&apos; Columns : the number of columns by which the reference was corrected to the left (negative value) or to the right.
2337 &apos;&apos;&apos; Use 0 (default) to stay in the same column
2338 &apos;&apos;&apos; Height : the vertical height for an area that starts at the new reference position.
2339 &apos;&apos;&apos; Default = no vertical resizing
2340 &apos;&apos;&apos; Width : the horizontal width for an area that starts at the new reference position.
2341 &apos;&apos;&apos; Default - no horizontal resizing
2342 &apos;&apos;&apos; Arguments Rows and Columns must not lead to zero or negative start row or column.
2343 &apos;&apos;&apos; Arguments Height and Width must not lead to zero or negative count of rows or columns.
2344 &apos;&apos;&apos; Returns:
2345 &apos;&apos;&apos; A new range as a string
2346 &apos;&apos;&apos; Exceptions:
2347 &apos;&apos;&apos; OFFSETADDRESSERROR The computed range of cells falls beyond the sheet boundaries
2348 &apos;&apos;&apos; Examples:
2349 &apos;&apos;&apos; oDoc.Offset(&quot;A1&quot;, 2, 2) &apos; &quot;&apos;SheetX&apos;.$C$3&quot; (A1 moved by two rows and two columns down)
2350 &apos;&apos;&apos; oDoc.Offset(&quot;A1&quot;, 2, 2, 5, 6) &apos; &quot;&apos;SheetX&apos;.$C$3:$H$7&quot;
2352 Dim sOffset As String &apos; Return value
2353 Dim oAddress As Object &apos; Alias of Range
2354 Const cstThisSub = &quot;SFDocuments.Calc.Offset&quot;
2355 Const cstSubArgs = &quot;Range, [Rows=0], [Columns=0], [Height], [Width]&quot;
2357 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2358 sOffset = &quot;&quot;
2360 Check:
2361 If IsMissing(Rows) Or IsEmpty(Rows) Then Rows = 0
2362 If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = 0
2363 If IsMissing(Height) Or IsEmpty(Height) Then Height = 0
2364 If IsMissing(Width) Or IsEmpty(Width) Then Width = 0
2365 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2366 If Not _IsStillAlive() Then GoTo Finally
2367 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
2368 If Not ScriptForge.SF_Utils._Validate(Rows, &quot;Rows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
2369 If Not ScriptForge.SF_Utils._Validate(Columns, &quot;Columns&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
2370 If Not ScriptForge.SF_Utils._Validate(Height, &quot;Height&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
2371 If Not ScriptForge.SF_Utils._Validate(Width, &quot;Width&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
2372 End If
2374 Try:
2375 &apos; Define the new range string
2376 Set oAddress = _Offset(Range, Rows, Columns, Height, Width)
2377 sOffset = oAddress.RangeName
2379 Finally:
2380 Offset = sOffset
2381 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2382 Exit Function
2383 Catch:
2384 GoTo Finally
2385 End Function &apos; SFDocuments.SF_Calc.Offset
2387 REM -----------------------------------------------------------------------------
2388 Public Function OpenRangeSelector(Optional ByVal Title As Variant _
2389 , Optional ByVal Selection As Variant _
2390 , Optional ByVal SingleCell As Variant _
2391 , Optional ByVal CloseAfterSelect As Variant _
2392 ) As String
2393 &apos;&apos;&apos; Activates the Calc document, opens a non-modal dialog with a text box,
2394 &apos;&apos;&apos; let the user make a selection in the current or another sheet and
2395 &apos;&apos;&apos; returns the selected area as a string.
2396 &apos;&apos;&apos; This method does not change the current selection.
2397 &apos;&apos;&apos; Args:
2398 &apos;&apos;&apos; Title: the title to display on the top of the dialog
2399 &apos;&apos;&apos; Selection: a default preselection as a String. When absent, the first element of the
2400 &apos;&apos;&apos; current selection is preselected.
2401 &apos;&apos;&apos; SingleCell: When True, only a single cell may be selected. Default = False
2402 &apos;&apos;&apos; CloseAfterSelect: When True (default-, the dialog is closed immediately after
2403 &apos;&apos;&apos; the selection. When False, the user may change his/her mind and must close
2404 &apos;&apos;&apos; the dialog manually.
2405 &apos;&apos;&apos; Returns:
2406 &apos;&apos;&apos; The selected range as a string, or the empty string when the user cancelled the request (close window button)
2407 &apos;&apos;&apos; Exceptions:
2408 &apos;&apos;&apos; Examples:
2409 &apos;&apos;&apos; Dim sSelect As String, vValues As Variant
2410 &apos;&apos;&apos; sSelect = oDoc.OpenRangeSelector(&quot;Select a range ...&quot;)
2411 &apos;&apos;&apos; If sSelect = &quot;&quot; Then Exit Function
2412 &apos;&apos;&apos; vValues = oDoc.GetValue(sSelect)
2414 Dim sSelector As String &apos; Return value
2415 Dim vPropertyValues As Variant &apos; Array of com.sun.star.beans.PropertyValue
2416 Dim oSelection As Object &apos; The current selection before opening the selector
2417 Dim oAddress As Object &apos; Preselected address as _Address
2419 Const cstThisSub = &quot;SFDocuments.Calc.OpenRangeSelector&quot;
2420 Const cstSubArgs = &quot;[Title=&quot;&quot;&quot;&quot;], [Selection=&quot;&quot;~&quot;&quot;], [SingleCell=False], [CloseAfterSelect=True]&quot;
2422 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2423 sSelector = &quot;&quot;
2425 Check:
2426 If IsMissing(Title) Or IsEmpty(Title) Then Title = &quot;&quot;
2427 If IsMissing(Selection) Or IsEmpty(Selection) Then Selection = &quot;~&quot;
2428 If IsMissing(SingleCell) Or IsEmpty(SingleCell) Then SingleCell = False
2429 If IsMissing(CloseAfterSelect) Or IsEmpty(CloseAfterSelect) Then CloseAfterSelect = True
2430 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2431 If Not _IsStillAlive() Then GoTo Finally
2432 If Not ScriptForge.SF_Utils._Validate(Title, &quot;Title&quot;, V_STRING) Then GoTo Finally
2433 If Not ScriptForge.SF_Utils._Validate(Selection, &quot;Selection&quot;, V_STRING) Then GoTo Finally
2434 If Not ScriptForge.SF_Utils._Validate(SingleCell, &quot;SingleCell&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
2435 If Not ScriptForge.SF_Utils._Validate(CloseAfterSelect, &quot;CloseAfterSelect&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
2436 End If
2438 Try:
2439 &apos; Save the current selections
2440 Set oSelection = _Component.CurrentController.getSelection()
2442 &apos; Process preselection and select its containing sheet
2443 Set oAddress = _ParseAddress(Selection)
2444 Activate(oAddress.SheetName)
2446 &apos; Build arguments array and execute the dialog box
2447 With ScriptForge.SF_Utils
2448 vPropertyValues = Array( _
2449 ._MakePropertyValue(&quot;Title&quot;, Title) _
2450 , ._MakePropertyValue(&quot;CloseOnMouseRelease&quot;, CloseAfterSelect) _
2451 , ._MakePropertyValue(&quot;InitialValue&quot;, oAddress.XCellRange.AbsoluteName) _
2452 , ._MakePropertyValue(&quot;SingleCellMode&quot;, SingleCell) _
2454 End With
2455 sSelector = SF_DocumentListener.RunRangeSelector(_Component, vPropertyValues)
2457 &apos; Restore the saved selections
2458 _RestoreSelections(_Component, oSelection)
2460 Finally:
2461 OpenRangeSelector = sSelector
2462 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2463 Exit Function
2464 Catch:
2465 GoTo Finally
2466 End Function &apos; SFDocuments.SF_Calc.OpenRangeSelector
2468 REM -----------------------------------------------------------------------------
2469 Public Function Printf(Optional ByVal InputStr As Variant _
2470 , Optional ByVal Range As Variant _
2471 , Optional ByVal TokenCharacter As Variant _
2472 ) As String
2473 &apos;&apos;&apos; Returns the input string after substitution of its tokens by
2474 &apos;&apos;&apos; their values in the given range
2475 &apos;&apos;&apos; This method is usually used in combination with SetFormula()
2476 &apos;&apos;&apos; The accepted tokens are:
2477 &apos;&apos;&apos; - %S The sheet name containing the range, including single quotes when necessary
2478 &apos;&apos;&apos; - %R1 The row number of the topleft part of the range
2479 &apos;&apos;&apos; - %C1 The column letter of the topleft part of the range
2480 &apos;&apos;&apos; - %R2 The row number of the bottomright part of the range
2481 &apos;&apos;&apos; - %C2 The column letter of the bottomright part of the range
2482 &apos;&apos;&apos; Args:
2483 &apos;&apos;&apos; InputStr: usually a Calc formula or a part of a formula, but may be any string
2484 &apos;&apos;&apos; Range: the range, as a string from which the values of the tokens are derived
2485 &apos;&apos;&apos; TokenCharacter: the character identifying tokens. Default = &quot;%&quot;.
2486 &apos;&apos;&apos; Double the TokenCharacter to not consider it as a token.
2487 &apos;&apos;&apos; Returns:
2488 &apos;&apos;&apos; The input string after substitution of the contained tokens
2489 &apos;&apos;&apos; Exceptions:
2490 &apos;&apos;&apos; Examples:
2491 &apos;&apos;&apos; Assume we have in A1:E10 a matrix of numbers. To obtain the sum by row in F1:F10 ...
2492 &apos;&apos;&apos; Dim range As String, formula As String
2493 &apos;&apos;&apos; range = &quot;$A$1:$E$10&quot;)
2494 &apos;&apos;&apos; formula = &quot;=SUM($%C1%R1:$%C2%R1)&quot; &apos; &quot;=SUM($A1:$E1)&quot;, note the relative references
2495 &apos;&apos;&apos; oDoc.SetFormula(&quot;$F$1:$F$10&quot;, formula)
2496 &apos;&apos;&apos; &apos;F1 will contain =Sum($A1:$E1)
2497 &apos;&apos;&apos; &apos;F2 =Sum($A2:$E2)
2498 &apos;&apos;&apos; &apos; ...
2500 Dim sPrintf As String &apos; Return value
2501 Dim vSubstitute As Variants &apos; Array of strings representing the token values
2502 Dim oAddress As Object &apos; A range as an _Address object
2503 Dim sSheetName As String &apos; The %S token value
2504 Dim sC1 As String &apos; The %C1 token value
2505 Dim sR1 As String &apos; The %R1 token value
2506 Dim sC2 As String &apos; The %C2 token value
2507 Dim sR2 As String &apos; The %R2 token value
2508 Dim i As Long
2509 Const cstPseudoToken = &quot;@#@&quot;
2511 Const cstThisSub = &quot;SFDocuments.Calc.Printf&quot;
2512 Const cstSubArgs = &quot;InputStr, Range, TokenCharacter=&quot;&quot;%&quot;&quot;&quot;
2514 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2515 sPrintf = &quot;&quot;
2517 Check:
2518 If IsMissing(TokenCharacter) Or IsEmpty(TokenCharacter) Then TokenCharacter = &quot;%&quot;
2519 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2520 If Not _IsStillAlive() Then GoTo Finally
2521 If Not ScriptForge.SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
2522 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
2523 If Not ScriptForge.SF_Utils._Validate(TokenCharacter, &quot;TokenCharacter&quot;, V_STRING) Then GoTo Finally
2524 End If
2526 Try:
2527 &apos; Define the token values
2528 Set oAddress = _ParseAddress(Range)
2529 With oAddress.XCellRange
2530 sC1 = _GetColumnName(.RangeAddress.StartColumn + 1)
2531 sR1 = CStr(.RangeAddress.StartRow + 1)
2532 sC2 = _GetColumnName(.RangeAddress.EndColumn + 1)
2533 sR2 = CStr(.RangeAddress.EndRow + 1)
2534 sSheetName = _QuoteSheetName(oAddress.XSpreadsheet.Name)
2535 End With
2537 &apos; Substitute tokens by their values
2538 sPrintf = ScriptForge.SF_String.ReplaceStr(InputStr _
2539 , Array(TokenCharacter &amp; TokenCharacter _
2540 , TokenCharacter &amp; &quot;R1&quot; _
2541 , TokenCharacter &amp; &quot;C1&quot; _
2542 , TokenCharacter &amp; &quot;R2&quot; _
2543 , TokenCharacter &amp; &quot;C2&quot; _
2544 , TokenCharacter &amp; &quot;S&quot; _
2545 , cstPseudoToken _
2547 , Array(cstPseudoToken _
2548 , sR1 _
2549 , sC1 _
2550 , sR2 _
2551 , sC2 _
2552 , sSheetName _
2553 , TokenCharacter _
2557 Finally:
2558 Printf = sPrintf
2559 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2560 Exit Function
2561 Catch:
2562 GoTo Finally
2563 End Function &apos; SFDocuments.SF_Calc.Printf
2565 REM -----------------------------------------------------------------------------
2566 Public Function PrintOut(Optional ByVal SheetName As Variant _
2567 , Optional ByVal Pages As Variant _
2568 , Optional ByVal Copies As Variant _
2569 ) As Boolean
2570 &apos;&apos;&apos; Send the content of the given sheet to the printer.
2571 &apos;&apos;&apos; The printer might be defined previously by default, by the user or by the SetPrinter() method
2572 &apos;&apos;&apos; Args:
2573 &apos;&apos;&apos; SheetName: the sheet to print. Default = the active sheet
2574 &apos;&apos;&apos; Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
2575 &apos;&apos;&apos; Copies: the number of copies
2576 &apos;&apos;&apos; Returns:
2577 &apos;&apos;&apos; True when successful
2578 &apos;&apos;&apos; Examples:
2579 &apos;&apos;&apos; oDoc.PrintOut(&quot;SheetX&quot;, &quot;1-4;10;15-18&quot;, Copies := 2)
2581 Dim bPrint As Boolean &apos; Return value
2582 Dim oSheet As Object &apos; SheetName as a reference
2584 Const cstThisSub = &quot;SFDocuments.Calc.PrintOut&quot;
2585 Const cstSubArgs = &quot;[SheetName=&quot;&quot;~&quot;&quot;], [Pages=&quot;&quot;&quot;&quot;], [Copies=1]&quot;
2587 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2588 bPrint = False
2590 Check:
2591 If IsMissing(SheetName) Or IsEmpty(SheetName) Then SheetName = &quot;&quot;
2592 If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
2593 If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
2595 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2596 If Not _IsStillAlive() Then GoTo Finally
2597 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True, True) Then GoTo Finally
2598 If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
2599 If Not ScriptForge.SF_Utils._Validate(Copies, &quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
2600 End If
2602 Try:
2603 If SheetName = &quot;~&quot; Then SheetName = &quot;&quot;
2604 &apos; Make given sheet active
2605 If Len(SheetName) &gt; 0 Then
2606 With _Component
2607 Set oSheet = .getSheets.getByName(SheetName)
2608 Set .CurrentController.ActiveSheet = oSheet
2609 End With
2610 End If
2612 bPrint = [_Super].PrintOut(Pages, Copies, _Component)
2614 Finally:
2615 PrintOut = bPrint
2616 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2617 Exit Function
2618 Catch:
2619 GoTo Finally
2620 End Function &apos; SFDocuments.SF_Calc.PrintOut
2622 REM -----------------------------------------------------------------------------
2623 Public Function Properties() As Variant
2624 &apos;&apos;&apos; Return the list or properties of the Calc class as an array
2626 Properties = Array( _
2627 &quot;CurrentSelection&quot; _
2628 , &quot;CustomProperties&quot; _
2629 , &quot;Description&quot; _
2630 , &quot;DocumentProperties&quot; _
2631 , &quot;DocumentType&quot; _
2632 , &quot;ExportFilters&quot; _
2633 , &quot;FileSystem&quot; _
2634 , &quot;FirstCell&quot; _
2635 , &quot;FirstColumn&quot; _
2636 , &quot;FirstRow&quot; _
2637 , &quot;Height&quot; _
2638 , &quot;ImportFilters&quot; _
2639 , &quot;IsAlive&quot; _
2640 , &quot;IsBase&quot; _
2641 , &quot;IsCalc&quot; _
2642 , &quot;IsDraw&quot; _
2643 , &quot;IsFormDocument&quot; _
2644 , &quot;IsImpress&quot; _
2645 , &quot;IsMath&quot; _
2646 , &quot;IsWriter&quot; _
2647 , &quot;Keywords&quot; _
2648 , &quot;LastCell&quot; _
2649 , &quot;LastColumn&quot; _
2650 , &quot;LastRow&quot; _
2651 , &quot;Range&quot; _
2652 , &quot;Readonly&quot; _
2653 , &quot;Region&quot; _
2654 , &quot;Sheet&quot; _
2655 , &quot;SheetName&quot; _
2656 , &quot;Sheets&quot; _
2657 , &quot;StyleFamilies&quot; _
2658 , &quot;Subject&quot; _
2659 , &quot;Title&quot; _
2660 , &quot;Width&quot; _
2661 , &quot;XCellRange&quot; _
2662 , &quot;XComponent&quot; _
2663 , &quot;XDocumentSettings&quot; _
2664 , &quot;XRectangle&quot; _
2665 , &quot;XSheetCellCursor&quot; _
2666 , &quot;XSpreadsheet&quot; _
2669 End Function &apos; SFDocuments.SF_Calc.Properties
2671 REM -----------------------------------------------------------------------------
2672 Public Function RemoveDuplicates(Optional ByVal Range As Variant _
2673 , Optional ByVal Columns As Variant _
2674 , Optional ByVal Header As Variant _
2675 , Optional ByVal CaseSensitive As Variant _
2676 , Optional ByVal Mode As Variant _
2677 ) As String
2678 &apos;&apos;&apos; Remove duplicate values from a range of values.
2679 &apos;&apos;&apos; The comparison between rows is done on a subset of the columns in the range.
2680 &apos;&apos;&apos; The resulting range replaces the input range, in which, either:
2681 &apos;&apos;&apos; all duplicate rows are cleared from their content
2682 &apos;&apos;&apos; all duplicate rows are suppressed and rows below are pushed upwards.
2683 &apos;&apos;&apos; Anyway, the first copy of each set of duplicates is kept and the initial sequence is preserved.
2684 &apos;&apos;&apos; Args:
2685 &apos;&apos;&apos; Range: the range, as a string, from which the duplicate rows should be removed
2686 &apos;&apos;&apos; Columns: an array of column numbers to compare; items are in the interval [1 .. range width]
2687 &apos;&apos;&apos; Default = the first column in the range
2688 &apos;&apos;&apos; Header: when True, the first row is a header row. Default = False.
2689 &apos;&apos;&apos; CaseSensitive: for string comparisons. Default = False.
2690 &apos;&apos;&apos; Mode: either &quot;CLEAR&quot; or &quot;COMPACT&quot; (Default)
2691 &apos;&apos;&apos; For large ranges, the &quot;COMPACT&quot; mode is probably significantly slower.
2692 &apos;&apos;&apos; Returns:
2693 &apos;&apos;&apos; The resulting range as a string
2694 &apos;&apos;&apos; Examples:
2695 &apos;&apos;&apos; oCalc.RemoveDuplicates(&quot;Sheet1.B2:K11&quot;, Array(1, 2), Header := True, CaseSensitive := True)
2697 Dim sRemove As String &apos; Return value
2698 Dim oRangeAddress As Object &apos; Parsed range as an _Address object
2699 Dim sMirrorRange As String &apos; Mirror of initial range
2700 Dim lRandom As Long &apos; Random number to build the worksheet name
2701 Dim sWorkSheet As String &apos; Name of worksheet
2702 Dim vRows() As Variant &apos; Array of row numbers
2703 Dim sRowsRange As String &apos; Range of the last column of the worksheet
2704 Dim sFullMirrorRange As String &apos; Mirrored data + rows column
2705 Dim sLastRowsRange As String &apos; Same as sRowsRange without the first cell
2706 Dim sDuplicates As String &apos; Formula identifying a duplicate row
2707 Dim lColumn As Long &apos; Single column number
2708 Dim sColumn As String &apos; Single column name
2709 Dim sFilter As String &apos; Filter formula for final compaction or clearing
2711 Const cstThisSub = &quot;SFDocuments.Calc.RemoveDuplicates&quot;
2712 Const cstSubArgs = &quot;Range, [Columns], [Header=False], [CaseSensitive=False], [Mode=&quot;&quot;COMPACT&quot;&quot;|&quot;&quot;CLEAR&quot;&quot;]&quot;
2714 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2715 sRemove = &quot;&quot;
2717 Check:
2718 If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = Array(1)
2719 If Not IsArray(Columns) Then Columns = Array(Columns)
2720 If IsMissing(Header) Or IsEmpty(Header) Then Header = False
2721 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
2722 If IsMissing(Mode) Or IsEmpty(Mode) Then Mode = &quot;COMPACT&quot;
2723 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2724 If Not _IsStillAlive(True) Then GoTo Finally
2725 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
2726 If Not ScriptForge.SF_Utils._ValidateArray(Columns, &quot;Columns&quot;, 1, ScriptForge.V_NUMERIC, True) Then GoTo Finally
2727 If Not ScriptForge.SF_Utils._Validate(Header, &quot;Header&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
2728 If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
2729 If Not ScriptForge.SF_Utils._Validate(Mode, &quot;Mode&quot;, V_STRING, Array(&quot;COMPACT&quot;, &quot;CLEAR&quot;)) Then GoTo Finally
2730 End If
2732 Try:
2733 &apos; Let&apos;s assume the initial range is &quot;$Sheet1.$B$11:$K$110&quot; (100 rows, 10 columns, no header)
2734 &apos; Ignore header, consider only the effective data
2735 If Header Then Set oRangeAddress = _Offset(Range, 1, 0, Height(Range) - 1, 0) Else Set oRangeAddress = _ParseAddress(Range)
2737 &apos;** Step 1: create a worksheet and copy the range in A1
2738 lRandom = ScriptForge.SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN.NV&quot;, 1, 999999)
2739 sWorkSheet = &quot;SF_WORK_&quot; &amp; Right(&quot;000000&quot; &amp; lRandom, 6)
2740 InsertSheet(sWorkSheet)
2741 &apos; sMirrorRange = &quot;$SF_WORK.$A$1:$J$100&quot;
2742 sMirrorRange = CopyToCell(oRangeAddress, &quot;$&quot; &amp; sWorkSheet &amp; &quot;.$A$1&quot;)
2744 &apos;** Step 2: add a column in the mirror with the row numbers in the initial range
2745 &apos; vRows = [11..110]
2746 With oRangeAddress.XCellRange
2747 vRows = ScriptForge.RangeInit(CLng(.RangeAddress.StartRow + 1), CLng(.RangeAddress.EndRow + 1))
2748 End With
2749 &apos; sRowsRange = &quot;$SF_WORK.$K$1:$K$100&quot;
2750 sRowsRange = SetArray(Offset(sMirrorRange, , Width(sMirrorRange), 1, 1), vRows())
2752 &apos;** Step 3: sort the mirrored data, including the row numbers column
2753 &apos; sFullMirrorRange = &quot;$SF_WORK.$A$1:$K$100&quot;
2754 sFullMirrorRange = Offset(sMirrorRange, , , , Width(sMirrorRange) + 1)
2755 SortRange(sFullMirrorRange, SortKeys := Columns, CaseSensitive := CaseSensitive)
2757 &apos;** Step 4: Filter out the row numbers containing duplicates
2758 &apos; sLastRowRange = &quot;$SF_WORK.$K$2:$K$100&quot;
2759 sLastRowsRange = Offset(sRowsRange, 1, , Height(sRowsRange) - 1)
2760 &apos; If Columns = (1, 3) =&gt; sDuplicates = &quot;=AND(TRUE;$A2=$A1;$C2=$C1)
2761 sDuplicates = &quot;=AND(TRUE&quot;
2762 For Each lColumn In Columns
2763 sColumn = _GetColumnName(lColumn)
2764 If CaseSensitive Then
2765 sDuplicates = sDuplicates &amp; &quot;;$&quot; &amp; sColumn &amp; &quot;2=$&quot; &amp; sColumn &amp; &quot;1&quot;
2766 Else
2767 sDuplicates = sDuplicates &amp; &quot;;UPPER($&quot; &amp; sColumn &amp; &quot;2)=UPPER($&quot; &amp; sColumn &amp; &quot;1)&quot;
2768 End If
2769 Next lColumn
2770 sDuplicates = sDuplicates &amp; &quot;)&quot;
2771 ClearValues(sLastRowsRange, sDuplicates, &quot;ROW&quot;)
2773 &apos;** Step 5: Compact or clear the rows in the initial range that are not retained in the final row numbers list
2774 &apos; sFilter = &quot;=ISNA(MATCH(ROW();$SF_WORK.$K$1:$K$100;0))&quot;
2775 sFilter = &quot;=ISNA(MATCH(ROW();&quot; &amp; sRowsRange &amp; &quot;;0))&quot;
2776 Select Case UCase(Mode)
2777 Case &quot;COMPACT&quot;
2778 sRemove = CompactUp(oRangeAddress.RangeName, WholeRow := False, FilterFormula := sFilter)
2779 If Header Then sRemove = Offset(sRemove, -1, 0, Height(sRemove) + 1)
2780 Case &quot;CLEAR&quot;
2781 ClearValues(oRangeAddress.RangeName, FilterFormula := sFilter, FilterScope := &quot;ROW&quot;)
2782 If Header Then sRemove = _ParseAddress(Range).RangeName Else sRemove = oRangeAddress.RangeName
2783 End Select
2785 &apos;** Housekeeping
2786 RemoveSheet(sWorkSheet)
2788 Finally:
2789 RemoveDuplicates = sRemove
2790 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2791 Exit Function
2792 Catch:
2793 GoTo Finally
2794 End Function &apos; SFDocuments.SF_Calc.RemoveDuplicates
2796 REM -----------------------------------------------------------------------------
2797 Public Function RemoveSheet(Optional ByVal SheetName As Variant) As Boolean
2798 &apos;&apos;&apos; Remove an existing sheet from the document
2799 &apos;&apos;&apos; Args:
2800 &apos;&apos;&apos; SheetName: The name of the sheet to remove
2801 &apos;&apos;&apos; Returns:
2802 &apos;&apos;&apos; True if the sheet could be removed successfully
2803 &apos;&apos;&apos; Examples:
2804 &apos;&apos;&apos; oDoc.RemoveSheet(&quot;SheetX&quot;)
2806 Dim bRemove As Boolean &apos; Return value
2807 Const cstThisSub = &quot;SFDocuments.Calc.RemoveSheet&quot;
2808 Const cstSubArgs = &quot;SheetName&quot;
2810 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2811 bRemove = False
2813 Check:
2814 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2815 If Not _IsStillAlive(True) Then GoTo Finally
2816 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
2817 End If
2819 Try:
2820 _Component.getSheets.RemoveByName(SheetName)
2821 bRemove = True
2823 Finally:
2824 RemoveSheet = bRemove
2825 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2826 Exit Function
2827 Catch:
2828 GoTo Finally
2829 End Function &apos; SFDocuments.SF_Calc.RemoveSheet
2831 REM -----------------------------------------------------------------------------
2832 Public Function RenameSheet(Optional ByVal SheetName As Variant _
2833 , Optional ByVal NewName As Variant _
2834 ) As Boolean
2835 &apos;&apos;&apos; Rename a specified sheet
2836 &apos;&apos;&apos; Args:
2837 &apos;&apos;&apos; SheetName: The name of the sheet to rename
2838 &apos;&apos;&apos; NewName: Must not exist
2839 &apos;&apos;&apos; Returns:
2840 &apos;&apos;&apos; True if the sheet could be renamed successfully
2841 &apos;&apos;&apos; Exceptions:
2842 &apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
2843 &apos;&apos;&apos; Examples:
2844 &apos;&apos;&apos; oDoc.RenameSheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
2846 Dim bRename As Boolean &apos; Return value
2847 Const cstThisSub = &quot;SFDocuments.Calc.RenameSheet&quot;
2848 Const cstSubArgs = &quot;SheetName, NewName&quot;
2850 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2851 bRename = False
2853 Check:
2854 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2855 If Not _IsStillAlive(True) Then GoTo Finally
2856 If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
2857 If Not _ValidateSheet(NewName, &quot;NewName&quot;, True) Then GoTo Finally
2858 End If
2860 Try:
2861 _Component.getSheets.getByName(SheetName).setName(NewName)
2862 bRename = True
2864 Finally:
2865 RenameSheet = bRename
2866 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2867 Exit Function
2868 Catch:
2869 GoTo Finally
2870 End Function &apos; SFDocuments.SF_Calc.RenameSheet
2872 REM -----------------------------------------------------------------------------
2873 Public Function SetArray(Optional ByVal TargetCell As Variant _
2874 , Optional ByRef Value As Variant _
2875 ) As String
2876 &apos;&apos;&apos; Set the given (array of) values starting from the target cell
2877 &apos;&apos;&apos; The updated area expands itself from the target cell or from the top-left corner of the given range
2878 &apos;&apos;&apos; as far as determined by the size of the input Value.
2879 &apos;&apos;&apos; Vectors are always expanded vertically
2880 &apos;&apos;&apos; Args:
2881 &apos;&apos;&apos; TargetCell : the cell or the range as a string that should receive a new value
2882 &apos;&apos;&apos; Value: a scalar, a vector or an array with the new values
2883 &apos;&apos;&apos; The new values should be strings, numeric values or dates. Other types empty the corresponding cell
2884 &apos;&apos;&apos; Returns:
2885 &apos;&apos;&apos; A string representing the updated range
2886 &apos;&apos;&apos; Exceptions:
2887 &apos;&apos;&apos; OFFSETADDRESSERROR The computed range of cells falls beyond the sheet boundaries
2888 &apos;&apos;&apos; Examples:
2889 &apos;&apos;&apos; oDoc.SetArray(&quot;SheetX.A1&quot;, SF_Array.RangeInit(1, 1000))
2891 Dim sSet As String &apos; Return value
2892 Dim oSet As Object &apos; _Address alias of sSet
2893 Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
2894 Const cstThisSub = &quot;SFDocuments.Calc.SetArray&quot;
2895 Const cstSubArgs = &quot;TargetCell, Value&quot;
2897 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2898 sSet = &quot;&quot;
2900 Check:
2901 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2902 If Not _IsStillAlive() Then GoTo Finally
2903 If Not ScriptForge.SF_Utils._Validate(TargetCell, &quot;TargetCell&quot;, V_STRING) Then GoTo Finally
2904 If IsArray(Value) Then
2905 If Not ScriptForge.SF_Utils._ValidateArray(Value, &quot;Value&quot;) Then GoTo Finally
2906 Else
2907 If Not ScriptForge.SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Finally
2908 End If
2909 End If
2911 Try:
2912 &apos; Convert argument to data array and derive new range from its size
2913 vDataArray = ScriptForge.SF_Array.ConvertToDataArray(Value, IsRange := True)
2914 If UBound(vDataArray) &lt; LBound(vDataArray) Then GoTo Finally
2915 Set oSet = _Offset(TargetCell, 0, 0, plHeight := UBound(vDataArray) + 1, plWidth := UBound(vDataArray(0)) + 1) &apos; +1 : vDataArray is zero-based
2916 With oSet
2917 .XCellRange.setDataArray(vDataArray)
2918 sSet = .RangeName
2919 End With
2921 Finally:
2922 SetArray = sSet
2923 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
2924 Exit Function
2925 Catch:
2926 GoTo Finally
2927 End Function &apos; SFDocuments.SF_Calc.SetArray
2929 REM -----------------------------------------------------------------------------
2930 Public Function SetCellStyle(Optional ByVal TargetRange As Variant _
2931 , Optional ByVal Style As Variant _
2932 , Optional ByVal FilterFormula As Variant _
2933 , Optional ByVal FilterScope As Variant _
2934 ) As String
2935 &apos;&apos;&apos; Apply the given cell style in the given range
2936 &apos;&apos;&apos; If the cell style does not exist, an error is raised
2937 &apos;&apos;&apos; The range is updated and the remainder of the sheet is left untouched
2938 &apos;&apos;&apos; Either the full range is updated or a selection based on a FilterFormula
2939 &apos;&apos;&apos; Args:
2940 &apos;&apos;&apos; TargetRange : the range as a string that should receive a new cell style
2941 &apos;&apos;&apos; Style: the style name as a string
2942 &apos;&apos;&apos; FilterFormula: a Calc formula to select among the given Range
2943 &apos;&apos;&apos; When left empty, all the cells of the range are formatted with the new style
2944 &apos;&apos;&apos; FilterScope: &quot;CELL&quot; (default value), &quot;ROW&quot; or &quot;COLUMN&quot;
2945 &apos;&apos;&apos; When FilterFormula is present, FilterScope is mandatory
2946 &apos;&apos;&apos; Returns:
2947 &apos;&apos;&apos; A string representing the updated range
2948 &apos;&apos;&apos; Examples:
2949 &apos;&apos;&apos; oDoc.SetCellStyle(&quot;A1:F1&quot;, &quot;Heading 2&quot;)
2950 &apos;&apos;&apos; oDoc.SetCellStype(&quot;A1:J20&quot;, &quot;Wrong&quot;, &quot;=(A1&lt;0)&quot;, &quot;CELL&quot;)
2952 Dim sSet As String &apos; Return value
2953 Dim oAddress As _Address &apos; Alias of TargetRange
2954 Dim oStyleFamilies As Object &apos; com.sun.star.container.XNameAccess
2955 Dim vStyles As Variant &apos; Array of existing cell styles
2956 Dim vRanges() As Variant &apos; Array of filtered ranges
2957 Dim i As Long
2959 Const cstStyle = &quot;CellStyles&quot;
2960 Const cstThisSub = &quot;SFDocuments.Calc.SetCellStyle&quot;
2961 Const cstSubArgs = &quot;TargetRange, Style, [FilterFormula=&quot;&quot;], [FilterScope=&quot;&quot;CELL&quot;&quot;|&quot;&quot;ROW&quot;&quot;|&quot;&quot;COLUMN&quot;&quot;]&quot;
2963 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
2964 sSet = &quot;&quot;
2966 Check:
2967 If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then FilterFormula = &quot;&quot;
2968 If IsMissing(FilterScope) Or IsEmpty(FilterScope) Then FilterScope = &quot;CELL&quot;
2969 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
2970 If Not _IsStillAlive() Then GoTo Finally
2971 If Not ScriptForge.SF_Utils._Validate(TargetRange, &quot;TargetRange&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
2972 &apos; Check that the given style really exists
2973 Set oStyleFamilies = _Component.StyleFamilies
2974 If oStyleFamilies.hasByName(cstStyle) Then vStyles = oStyleFamilies.getByName(cstStyle).getElementNames() Else vStyles = Array()
2975 If Not ScriptForge.SF_Utils._Validate(Style, &quot;Style&quot;, V_STRING, vStyles, True) Then GoTo Finally
2976 &apos; Filter formula
2977 If Not ScriptForge.SF_Utils._Validate(FilterFormula, &quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
2978 If Len(FilterFormula) &gt; 0 Then
2979 If Not ScriptForge.SF_Utils._Validate(FilterScope, &quot;FilterScope&quot;, V_STRING, Array(&quot;CELL&quot;, &quot;ROW&quot;, &quot;COLUMN&quot;)) Then GoTo Finally
2980 Else
2981 If Not ScriptForge.SF_Utils._Validate(FilterScope, &quot;FilterScope&quot;, V_STRING) Then GoTo Finally
2982 End If
2983 End If
2985 Try:
2986 If VarType(TargetRange) = V_STRING Then Set oAddress = _ParseAddress(TargetRange) Else Set oAddress = TargetRange
2987 With oAddress
2988 If Len(FilterFormula) = 0 Then &apos; When the full range should be updated
2989 .XCellRange.CellStyle = Style
2990 Else &apos; When the range has to be cut in subranges
2991 vRanges() = _ComputeFilter(oAddress, FilterFormula, UCase(FilterScope))
2992 For i = 0 To UBound(vRanges)
2993 vRanges(i).XCellRange.CellStyle = Style
2994 Next i
2995 End If
2996 sSet = .RangeName
2997 End With
2999 Finally:
3000 SetCellStyle = sSet
3001 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3002 Exit Function
3003 Catch:
3004 GoTo Finally
3005 End Function &apos; SFDocuments.SF_Calc.SetCellStyle
3007 REM -----------------------------------------------------------------------------
3008 Public Function SetFormula(Optional ByVal TargetRange As Variant _
3009 , Optional ByRef Formula As Variant _
3010 ) As String
3011 &apos;&apos;&apos; Set the given (array of) formulae in the given range
3012 &apos;&apos;&apos; The full range is updated and the remainder of the sheet is left untouched
3013 &apos;&apos;&apos; If the given formula is a string:
3014 &apos;&apos;&apos; the unique formula is pasted across the whole range with adjustment of the relative references
3015 &apos;&apos;&apos; Otherwise
3016 &apos;&apos;&apos; If the size of Formula &lt; the size of Range, then the other cells are emptied
3017 &apos;&apos;&apos; If the size of Formula &gt; the size of Range, then Formula is only partially copied
3018 &apos;&apos;&apos; Vectors are always expanded vertically, except if the range has a height of exactly 1 row
3019 &apos;&apos;&apos; Args:
3020 &apos;&apos;&apos; TargetRange : the range as a string that should receive a new Formula
3021 &apos;&apos;&apos; Formula: a scalar, a vector or an array with the new formula(e) as strings for each cell of the range.
3022 &apos;&apos;&apos; Returns:
3023 &apos;&apos;&apos; A string representing the updated range
3024 &apos;&apos;&apos; Examples:
3025 &apos;&apos;&apos; oDoc.SetFormula(&quot;A1&quot;, &quot;=A2&quot;)
3026 &apos;&apos;&apos; oDoc.SetFormula(&quot;A1:F1&quot;, Array(&quot;=A2&quot;, &quot;=B2&quot;, &quot;=C2+10&quot;)) &apos; Horizontal vector, partially empty
3027 &apos;&apos;&apos; oDoc.SetFormula(&quot;A1:D2&quot;, &quot;=E1&quot;) &apos; D2 contains the formula &quot;=H2&quot;
3029 Dim sSet As String &apos; Return value.XSpreadsheet.Name)
3030 Dim oAddress As Object &apos; Alias of TargetRange
3031 Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
3032 Const cstThisSub = &quot;SFDocuments.Calc.SetFormula&quot;
3033 Const cstSubArgs = &quot;TargetRange, Formula&quot;
3035 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3036 sSet = &quot;&quot;
3038 Check:
3039 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3040 If Not _IsStillAlive() Then GoTo Finally
3041 If Not ScriptForge.SF_Utils._Validate(TargetRange, &quot;TargetRange&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
3042 If IsArray(Formula) Then
3043 If Not ScriptForge.SF_Utils._ValidateArray(Formula, &quot;Formula&quot;, 0, V_STRING) Then GoTo Finally
3044 Else
3045 If Not ScriptForge.SF_Utils._Validate(Formula, &quot;Formula&quot;, V_STRING) Then GoTo Finally
3046 End If
3047 End If
3049 Try:
3050 If VarType(TargetRange) = V_STRING Then Set oAddress = _ParseAddress(TargetRange) Else Set oAddress = TargetRange
3051 With oAddress
3052 If IsArray(Formula) Then
3053 &apos; Convert to data array and limit its size to the size of the initial range
3054 vDataArray = ScriptForge.SF_Array.ConvertToDataArray(Formula, Rows := .Height, Columns := .Width)
3055 If UBound(vDataArray) &lt; LBound(vDataArray) Then GoTo Finally
3056 .XCellRange.setFormulaArray(vDataArray)
3057 Else
3058 With .XCellRange
3059 &apos; Store formula in top-left cell and paste it along the whole range
3060 .getCellByPosition(0, 0).setFormula(Formula)
3061 .fillSeries(com.sun.star.sheet.FillDirection.TO_BOTTOM, com.sun.star.sheet.FillMode.SIMPLE, 0, 0, 0)
3062 .fillSeries(com.sun.star.sheet.FillDirection.TO_RIGHT, com.sun.star.sheet.FillMode.SIMPLE, 0, 0, 0)
3063 End With
3064 End If
3065 sSet = .RangeName
3066 End With
3068 Finally:
3069 SetFormula = sSet
3070 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3071 Exit Function
3072 Catch:
3073 GoTo Finally
3074 End Function &apos; SFDocuments.SF_Calc.SetFormula
3076 REM -----------------------------------------------------------------------------
3077 Private Function SetProperty(Optional ByVal psProperty As String _
3078 , Optional ByVal pvValue As Variant _
3079 ) As Boolean
3080 &apos;&apos;&apos; Set the new value of the named property
3081 &apos;&apos;&apos; Args:
3082 &apos;&apos;&apos; psProperty: the name of the property
3083 &apos;&apos;&apos; pvValue: the new value of the given property
3084 &apos;&apos;&apos; Returns:
3085 &apos;&apos;&apos; True if successful
3087 Dim bSet As Boolean &apos; Return value
3088 Static oSession As Object &apos; Alias of SF_Session
3089 Dim cstThisSub As String
3090 Const cstSubArgs = &quot;Value&quot;
3092 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3093 bSet = False
3095 cstThisSub = &quot;SFDocuments.Calc.set&quot; &amp; psProperty
3096 If IsMissing(pvValue) Then pvValue = Empty
3097 &apos;ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) &apos; Validation done in Property Lets
3099 If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
3100 bSet = True
3101 Select Case UCase(psProperty)
3102 Case UCase(&quot;CurrentSelection&quot;)
3103 CurrentSelection = pvValue
3104 Case UCase(&quot;CustomProperties&quot;)
3105 CustomProperties = pvValue
3106 Case UCase(&quot;Description&quot;)
3107 Description = pvValue
3108 Case UCase(&quot;Keywords&quot;)
3109 Keywords = pvValue
3110 Case UCase(&quot;Subject&quot;)
3111 Subject = pvValue
3112 Case UCase(&quot;Title&quot;)
3113 Title = pvValue
3114 Case Else
3115 bSet = False
3116 End Select
3118 Finally:
3119 SetProperty = bSet
3120 &apos;ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3121 Exit Function
3122 Catch:
3123 GoTo Finally
3124 End Function &apos; SFDocuments.SF_Calc.SetProperty
3126 REM -----------------------------------------------------------------------------
3127 Public Function SetValue(Optional ByVal TargetRange As Variant _
3128 , Optional ByRef Value As Variant _
3129 ) As String
3130 &apos;&apos;&apos; Set the given value in the given range
3131 &apos;&apos;&apos; The full range is updated and the remainder of the sheet is left untouched
3132 &apos;&apos;&apos; If the size of Value &lt; the size of Range, then the other cells are emptied
3133 &apos;&apos;&apos; If the size of Value &gt; the size of Range, then Value is only partially copied
3134 &apos;&apos;&apos; Vectors are always expanded vertically, except if the range has a height of exactly 1 row
3135 &apos;&apos;&apos; Args:
3136 &apos;&apos;&apos; TargetRange : the range as a string that should receive a new value
3137 &apos;&apos;&apos; Value: a scalar, a vector or an array with the new values for each cell of the range.
3138 &apos;&apos;&apos; The new values should be strings, numeric values or dates. Other types empty the corresponding cell
3139 &apos;&apos;&apos; Returns:
3140 &apos;&apos;&apos; A string representing the updated range
3141 &apos;&apos;&apos; Examples:
3142 &apos;&apos;&apos; oDoc.SetValue(&quot;A1&quot;, 2)
3143 &apos;&apos;&apos; oDoc.SetValue(&quot;A1:F1&quot;, Array(1, 2, 3)) &apos; Horizontal vector, partially empty
3144 &apos;&apos;&apos; oDoc.SetValue(&quot;A1:D2&quot;, SF_Array.AppendRow(Array(1, 2, 3, 4), Array(5, 6, 7, 8)))
3146 Dim sSet As String &apos; Return value
3147 Dim oAddress As Object &apos; Alias of TargetRange
3148 Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
3149 Const cstThisSub = &quot;SFDocuments.Calc.SetValue&quot;
3150 Const cstSubArgs = &quot;TargetRange, Value&quot;
3152 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3153 sSet = &quot;&quot;
3155 Check:
3156 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3157 If Not _IsStillAlive() Then GoTo Finally
3158 If Not ScriptForge.SF_Utils._Validate(TargetRange, &quot;TargetRange&quot;, V_STRING) Then GoTo Finally
3159 If IsArray(Value) Then
3160 If Not ScriptForge.SF_Utils._ValidateArray(Value, &quot;Value&quot;) Then GoTo Finally
3161 Else
3162 If Not ScriptForge.SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Finally
3163 End If
3164 End If
3166 Try:
3167 Set oAddress = _ParseAddress(TargetRange)
3168 With oAddress
3169 &apos; Convert to data array and limit its size to the size of the initial range
3170 vDataArray = ScriptForge.SF_Array.ConvertToDataArray(Value, IsRange := True, Rows := .Height, Columns := .Width)
3171 If UBound(vDataArray) &lt; LBound(vDataArray) Then GoTo Finally
3172 .XCellRange.setDataArray(vDataArray)
3173 sSet = .RangeName
3174 End With
3176 Finally:
3177 SetValue = sSet
3178 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3179 Exit Function
3180 Catch:
3181 GoTo Finally
3182 End Function &apos; SFDocuments.SF_Calc.SetValue
3184 REM -----------------------------------------------------------------------------
3185 Public Function ShiftDown(Optional ByVal Range As Variant _
3186 , Optional ByVal WholeRow As Variant _
3187 , Optional ByVal Rows As Variant _
3188 ) As String
3189 &apos;&apos;&apos; Move a specified range and all cells below in the same columns downwards by inserting empty cells
3190 &apos;&apos;&apos; The inserted cells can span whole rows or be limited to the width of the range
3191 &apos;&apos;&apos; The height of the inserted area is provided by the Rows argument
3192 &apos;&apos;&apos; Nothing happens if the range shift crosses one of the edges of the worksheet
3193 &apos;&apos;&apos; The execution of the method has no effect on the current selection
3194 &apos;&apos;&apos; Args:
3195 &apos;&apos;&apos; Range: the range above which cells have to be inserted, as a string
3196 &apos;&apos;&apos; WholeRow: when True (default = False), insert whole rows
3197 &apos;&apos;&apos; Rows: the height of the area to insert. Default = the height of the Range argument
3198 &apos;&apos;&apos; Returns:
3199 &apos;&apos;&apos; A string representing the new location of the initial range
3200 &apos;&apos;&apos; Examples:
3201 &apos;&apos;&apos; newrange = oDoc.ShiftDown(&quot;SheetX.A1:F10&quot;) &apos; &quot;$SheetX.$A$11:$F$20&quot;
3202 &apos;&apos;&apos; newrange = oDoc.ShiftDown(&quot;SheetX.A1:F10&quot;, Rows := 3) &apos; &quot;$SheetX.$A$4:$F$13&quot;
3204 Dim sShift As String &apos; Return value
3205 Dim oSourceAddress As Object &apos; Alias of Range as _Address
3206 Dim lHeight As Long &apos; Range height
3207 Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right width
3208 Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellInsertMode enum values
3210 Const cstThisSub = &quot;SFDocuments.Calc.ShiftDown&quot;
3211 Const cstSubArgs = &quot;Range, [WholeRow=False], [Rows]&quot;
3213 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3214 sShift = &quot;&quot;
3216 Check:
3217 If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
3218 If IsMissing(Rows) Or IsEmpty(Rows) Then Rows = 0
3219 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3220 If Not _IsStillAlive(True) Then GoTo Finally
3221 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
3222 If Not ScriptForge.SF_Utils._Validate(WholeRow, &quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3223 If Not ScriptForge.SF_Utils._Validate(Rows, &quot;Rows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
3224 End If
3226 Try:
3227 Set oSourceAddress = _ParseAddress(Range)
3229 With oSourceAddress
3231 &apos; Manage the height of the area to shift
3232 &apos; The insertCells() method inserts a number of rows equal to the height of the cell range to shift
3233 lHeight = .Height
3234 If Rows &lt;= 0 Then Rows = lHeight
3235 If _LastCell(.XSpreadsheet)(1) + Rows &gt; MAXROWS Then GoTo Catch
3236 If Rows &lt;&gt; lHeight Then
3237 Set oShiftAddress = _Offset(oSourceAddress, 0, 0, Rows, 0).XCellRange.RangeAddress
3238 Else
3239 Set oShiftAddress = .XCellRange.RangeAddress
3240 End If
3242 &apos; Determine the shift mode
3243 With com.sun.star.sheet.CellInsertMode
3244 If WholeRow Then lShiftMode = .ROWS Else lShiftMode = .DOWN
3245 End With
3247 &apos; Move the cells as requested. This modifies .XCellRange
3248 .XSpreadsheet.insertCells(oShiftAddress, lShiftMode)
3250 &apos; Determine the receiving area
3251 sShift = .XCellRange.AbsoluteName
3253 End With
3255 Finally:
3256 ShiftDown = sShift
3257 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3258 Exit Function
3259 Catch:
3260 &apos; When error, return the original range
3261 If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
3262 GoTo Finally
3263 End Function &apos; SFDocuments.SF_Calc.ShiftDown
3265 REM -----------------------------------------------------------------------------
3266 Public Function ShiftLeft(Optional ByVal Range As Variant _
3267 , Optional ByVal WholeColumn As Variant _
3268 , Optional ByVal Columns As Variant _
3269 ) As String
3270 &apos;&apos;&apos; Delete the leftmost columns of a specified range and move all cells at their right leftwards
3271 &apos;&apos;&apos; The deleted cells can span whole columns or be limited to the height of the range
3272 &apos;&apos;&apos; The width of the deleted area is provided by the Columns argument
3273 &apos;&apos;&apos; The execution of the method has no effect on the current selection
3274 &apos;&apos;&apos; Args:
3275 &apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
3276 &apos;&apos;&apos; WholeColumn: when True (default = False), erase whole columns
3277 &apos;&apos;&apos; Columns: the width of the area to delete.
3278 &apos;&apos;&apos; Default = the width of the Range argument, it is also its maximum value
3279 &apos;&apos;&apos; Returns:
3280 &apos;&apos;&apos; A string representing the location of the remaining part of the initial range,
3281 &apos;&apos;&apos; or the zero-length string if the whole range has been deleted
3282 &apos;&apos;&apos; Examples:
3283 &apos;&apos;&apos; newrange = oDoc.ShiftLeft(&quot;SheetX.G1:L10&quot;) &apos; &quot;&quot;&quot;
3284 &apos;&apos;&apos; newrange = oDoc.ShiftLeft(&quot;SheetX.G1:L10&quot;, Columns := 3) &apos; &quot;$SheetX.$G$1:$I$10&quot;
3286 Dim sShift As String &apos; Return value
3287 Dim oSourceAddress As Object &apos; Alias of Range as _Address
3288 Dim lWidth As Long &apos; Range width
3289 Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right width
3290 Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellDeleteMode enum values
3292 Const cstThisSub = &quot;SFDocuments.Calc.ShiftLeft&quot;
3293 Const cstSubArgs = &quot;Range, [WholeColumn=False], [Columns]&quot;
3295 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3296 sShift = &quot;&quot;
3298 Check:
3299 If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = False
3300 If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = 0
3301 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3302 If Not _IsStillAlive(True) Then GoTo Finally
3303 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
3304 If Not ScriptForge.SF_Utils._Validate(WholeColumn, &quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3305 If Not ScriptForge.SF_Utils._Validate(Columns, &quot;Columns&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
3306 End If
3308 Try:
3309 Set oSourceAddress = _ParseAddress(Range)
3310 Set _LastParsedAddress = Nothing &apos; Range will be erased. Force re-parsing next time
3312 With oSourceAddress
3314 &apos; Manage the width of the area to delete
3315 &apos; The removeRange() method erases a number of columns equal to the width of the cell range to delete
3316 lWidth = .Width
3317 If Columns &lt;= 0 Then Columns = lWidth
3318 If Columns &lt; lWidth Then
3319 Set oShiftAddress = _Offset(oSourceAddress, 0, 0, 0, Columns).XCellRange.RangeAddress
3320 Else &apos; Columns is capped at the range width
3321 Set oShiftAddress = .XCellRange.RangeAddress
3322 End If
3324 &apos; Determine the Delete mode
3325 With com.sun.star.sheet.CellDeleteMode
3326 If WholeColumn Then lShiftMode = .COLUMNS Else lShiftMode = .LEFT
3327 End With
3329 &apos; Move the cells as requested. This modifies .XCellRange
3330 .XSpreadsheet.removeRange(oShiftAddress, lShiftMode)
3332 &apos; Determine the remaining area
3333 If Columns &lt; lWidth Then sShift = .XCellRange.AbsoluteName
3335 End With
3337 Finally:
3338 ShiftLeft = sShift
3339 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3340 Exit Function
3341 Catch:
3342 &apos; When error, return the original range
3343 If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
3344 GoTo Finally
3345 End Function &apos; SFDocuments.SF_Calc.ShiftLeft
3347 REM -----------------------------------------------------------------------------
3348 Public Function ShiftRight(Optional ByVal Range As Variant _
3349 , Optional ByVal WholeColumn As Variant _
3350 , Optional ByVal Columns As Variant _
3351 ) As String
3352 &apos;&apos;&apos; Move a specified range and all next cells in the same rows to the right by inserting empty cells
3353 &apos;&apos;&apos; The inserted cells can span whole columns or be limited to the height of the range
3354 &apos;&apos;&apos; The width of the inserted area is provided by the Columns argument
3355 &apos;&apos;&apos; Nothing happens if the range shift crosses one of the edges of the worksheet
3356 &apos;&apos;&apos; The execution of the method has no effect on the current selection
3357 &apos;&apos;&apos; Args:
3358 &apos;&apos;&apos; Range: the range before which cells have to be inserted, as a string
3359 &apos;&apos;&apos; WholeColumn: when True (default = False), insert whole columns
3360 &apos;&apos;&apos; Columns: the width of the area to insert. Default = the width of the Range argument
3361 &apos;&apos;&apos; Returns:
3362 &apos;&apos;&apos; A string representing the new location of the initial range
3363 &apos;&apos;&apos; Examples:
3364 &apos;&apos;&apos; newrange = oDoc.ShiftRight(&quot;SheetX.A1:F10&quot;) &apos; &quot;$SheetX.$G$1:$L$10&quot;
3365 &apos;&apos;&apos; newrange = oDoc.ShiftRight(&quot;SheetX.A1:F10&quot;, Columns := 3) &apos; &quot;$SheetX.$D$1:$I$10&quot;
3367 Dim sShift As String &apos; Return value
3368 Dim oSourceAddress As Object &apos; Alias of Range as _Address
3369 Dim lWidth As Long &apos; Range width
3370 Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right width
3371 Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellInsertMode enum values
3373 Const cstThisSub = &quot;SFDocuments.Calc.ShiftRight&quot;
3374 Const cstSubArgs = &quot;Range, [WholeColumn=False], [Columns]&quot;
3376 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3377 sShift = &quot;&quot;
3379 Check:
3380 If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = False
3381 If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = 0
3382 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3383 If Not _IsStillAlive(True) Then GoTo Finally
3384 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
3385 If Not ScriptForge.SF_Utils._Validate(WholeColumn, &quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3386 If Not ScriptForge.SF_Utils._Validate(Columns, &quot;Columns&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
3387 End If
3389 Try:
3390 Set oSourceAddress = _ParseAddress(Range)
3392 With oSourceAddress
3394 &apos; Manage the width of the area to Shift
3395 &apos; The insertCells() method inserts a number of columns equal to the width of the cell range to Shift
3396 lWidth = .Width
3397 If Columns &lt;= 0 Then Columns = lWidth
3398 If _LastCell(.XSpreadsheet)(0) + Columns &gt; MAXCOLS Then GoTo Catch
3399 If Columns &lt;&gt; lWidth Then
3400 Set oShiftAddress = _Offset(oSourceAddress, 0, 0, 0, Columns).XCellRange.RangeAddress
3401 Else
3402 Set oShiftAddress = .XCellRange.RangeAddress
3403 End If
3405 &apos; Determine the Shift mode
3406 With com.sun.star.sheet.CellInsertMode
3407 If WholeColumn Then lShiftMode = .COLUMNS Else lShiftMode = .RIGHT
3408 End With
3410 &apos; Move the cells as requested. This modifies .XCellRange
3411 .XSpreadsheet.insertCells(oShiftAddress, lShiftMode)
3413 &apos; Determine the receiving area
3414 sShift = .XCellRange.AbsoluteName
3416 End With
3418 Finally:
3419 ShiftRight = sShift
3420 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3421 Exit Function
3422 Catch:
3423 &apos; When error, return the original range
3424 If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
3425 GoTo Finally
3426 End Function &apos; SFDocuments.SF_Calc.ShiftRight
3428 REM -----------------------------------------------------------------------------
3429 Public Function ShiftUp(Optional ByVal Range As Variant _
3430 , Optional ByVal WholeRow As Variant _
3431 , Optional ByVal Rows As Variant _
3432 ) As String
3433 &apos;&apos;&apos; Delete the topmost rows of a specified range and move all cells below upwards
3434 &apos;&apos;&apos; The deleted cells can span whole rows or be limited to the width of the range
3435 &apos;&apos;&apos; The height of the deleted area is provided by the Rows argument
3436 &apos;&apos;&apos; The execution of the method has no effect on the current selection
3437 &apos;&apos;&apos; Args:
3438 &apos;&apos;&apos; Range: the range in which cells have to be erased, as a string
3439 &apos;&apos;&apos; WholeRow: when True (default = False), erase whole rows
3440 &apos;&apos;&apos; Rows: the height of the area to delete.
3441 &apos;&apos;&apos; Default = the height of the Range argument, it is also its maximum value
3442 &apos;&apos;&apos; Returns:
3443 &apos;&apos;&apos; A string representing the location of the remaining part of the initial range,
3444 &apos;&apos;&apos; or the zero-length string if the whole range has been deleted
3445 &apos;&apos;&apos; Examples:
3446 &apos;&apos;&apos; newrange = oDoc.ShiftUp(&quot;SheetX.G1:L10&quot;) &apos; &quot;&quot;
3447 &apos;&apos;&apos; newrange = oDoc.ShiftUp(&quot;SheetX.G1:L10&quot;, Rows := 3) &apos; &quot;$SheetX.$G$1:$I$10&quot;
3449 Dim sShift As String &apos; Return value
3450 Dim oSourceAddress As Object &apos; Alias of Range as _Address
3451 Dim lHeight As Long &apos; Range height
3452 Dim oShiftAddress As Object &apos; com.sun.star.table.CellRangeAddress - Range adjusted to the right height
3453 Dim lShiftMode As Long &apos; One of the com.sun.star.sheet.CellDeleteMode enum values
3455 Const cstThisSub = &quot;SFDocuments.Calc.ShiftUp&quot;
3456 Const cstSubArgs = &quot;Range, [WholeRow=False], [Rows]&quot;
3458 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3459 sShift = &quot;&quot;
3461 Check:
3462 If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
3463 If IsMissing(Rows) Or IsEmpty(Rows) Then Rows = 0
3464 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3465 If Not _IsStillAlive(True) Then GoTo Finally
3466 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
3467 If Not ScriptForge.SF_Utils._Validate(WholeRow, &quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3468 If Not ScriptForge.SF_Utils._Validate(Rows, &quot;Rows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
3469 End If
3471 Try:
3472 Set oSourceAddress = _ParseAddress(Range)
3473 Set _LastParsedAddress = Nothing &apos; Range will be erased. Force re-parsing next time
3475 With oSourceAddress
3477 &apos; Manage the height of the area to delete
3478 &apos; The removeRange() method erases a number of rows equal to the height of the cell range to delete
3479 lHeight = .Height
3480 If Rows &lt;= 0 Then Rows = lHeight
3481 If Rows &lt; lHeight Then
3482 Set oShiftAddress = _Offset(oSourceAddress, 0, 0, Rows, 0).XCellRange.RangeAddress
3483 Else &apos; Rows is capped at the range height
3484 Set oShiftAddress = .XCellRange.RangeAddress
3485 End If
3487 &apos; Determine the Delete mode
3488 With com.sun.star.sheet.CellDeleteMode
3489 If WholeRow Then lShiftMode = .ROWS Else lShiftMode = .UP
3490 End With
3492 &apos; Move the cells as requested. This modifies .XCellRange
3493 .XSpreadsheet.removeRange(oShiftAddress, lShiftMode)
3495 &apos; Determine the remaining area
3496 If Rows &lt; lHeight Then sShift = .XCellRange.AbsoluteName
3498 End With
3500 Finally:
3501 ShiftUp = sShift
3502 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3503 Exit Function
3504 Catch:
3505 &apos; When error, return the original range
3506 If Not IsNull(oSourceAddress) Then sShift = oSourceAddress.RangeName
3507 GoTo Finally
3508 End Function &apos; SFDocuments.SF_Calc.ShiftUp
3510 REM -----------------------------------------------------------------------------
3511 Public Function SortRange(Optional ByVal Range As Variant _
3512 , Optional ByVal SortKeys As Variant _
3513 , Optional ByVal SortOrder As Variant _
3514 , Optional ByVal DestinationCell As Variant _
3515 , Optional ByVal ContainsHeader As Variant _
3516 , Optional ByVal CaseSensitive As Variant _
3517 , Optional ByVal SortColumns As Variant _
3518 ) As Variant
3519 &apos;&apos;&apos; Sort the given range on any number of columns/rows. The sorting order may vary by column/row
3520 &apos;&apos;&apos; If the number of sort keys is &gt; 3 then the range is sorted several times, by groups of 3 keys,
3521 &apos;&apos;&apos; starting from the last key. In this context the algorithm used by Calc to sort ranges
3522 &apos;&apos;&apos; is presumed STABLE, i.e. it maintains the relative order of records with equal keys.
3523 &apos;&apos;&apos;
3524 &apos;&apos;&apos; Args:
3525 &apos;&apos;&apos; Range: the range to sort as a string
3526 &apos;&apos;&apos; SortKeys: a scalar (if 1 column/row) or an array of column/row numbers starting from 1
3527 &apos;&apos;&apos; SortOrder: a scalar or an array of strings: &quot;ASC&quot; or &quot;DESC&quot;
3528 &apos;&apos;&apos; Each item is paired with the corresponding item in SortKeys
3529 &apos;&apos;&apos; If the SortOrder array is shorter than SortKeys, the remaining keys are sorted
3530 &apos;&apos;&apos; in ascending order
3531 &apos;&apos;&apos; DestinationCell: the destination of the sorted range of cells, as a string
3532 &apos;&apos;&apos; If given as range, the destination will be reduced to its top-left cell
3533 &apos;&apos;&apos; By default, Range is overwritten with its sorted content
3534 &apos;&apos;&apos; ContainsHeader: when True, the first row/column is not sorted. Default = False
3535 &apos;&apos;&apos; CaseSensitive: only for string comparisons, default = False
3536 &apos;&apos;&apos; SortColumns: when True, the columns are sorted from left to right
3537 &apos;&apos;&apos; Default = False: rows are sorted from top to bottom.
3538 &apos;&apos;&apos; Returns:
3539 &apos;&apos;&apos; The modified range of cells as a string
3540 &apos;&apos;&apos; Example:
3541 &apos;&apos;&apos; oDoc.SortRange(&quot;A2:J200&quot;, Array(1, 3), , Array(&quot;ASC&quot;, &quot;DESC&quot;), CaseSensitive := True)
3542 &apos;&apos;&apos; &apos; Sort on columns A (ascending) and C (descending)
3544 Dim sSort As String &apos; Return value
3545 Dim oRangeAddress As _Address &apos; Parsed range
3546 Dim oRange As Object &apos; com.sun.star.table.XCellRange
3547 Dim oSortRange As Object &apos; The area to sort as an _Address object
3548 Dim oDestRange As Object &apos; Destination as a range
3549 Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
3550 Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
3551 Dim vSortDescriptor As Variant &apos; Array of com.sun.star.beans.PropertyValue
3552 Dim vSortFields As Variant &apos; Array of com.sun.star.table.TableSortField
3553 Dim sOrder As String &apos; Item in SortOrder
3554 Dim lSort As Long &apos; Counter for sub-sorts
3555 Dim lKeys As Long &apos; UBound of SortKeys
3556 Dim lKey As Long &apos; Actual index in SortKeys
3557 Dim i As Long, j As Long
3558 Const cstMaxKeys = 3 &apos; Maximum number of keys allowed in a single sorting step
3560 Const cstThisSub = &quot;SFDocuments.Calc.SortRange&quot;
3561 Const cstSubArgs = &quot;Range, SortKeys, [TargetRange=&quot;&quot;&quot;&quot;], [SortOrder=&quot;&quot;ASC&quot;&quot;], [DestinationCell=&quot;&quot;&quot;&quot;], [ContainsHeader=False], [CaseSensitive=False], [SortColumns=False]&quot;
3563 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3564 sSort = &quot;&quot;
3566 Check:
3567 If IsMissing(SortKeys) Or IsEmpty(SortKeys) Then
3568 SortKeys = Array(1)
3569 ElseIf Not IsArray(SortKeys) Then
3570 SortKeys = Array(SortKeys)
3571 End If
3572 If IsMissing(DestinationCell) Or IsEmpty(DestinationCell) Then DestinationCell = &quot;&quot;
3573 If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then
3574 SortOrder = Array(&quot;ASC&quot;)
3575 ElseIf Not IsArray(SortOrder) Then
3576 SortOrder = Array(SortOrder)
3577 End If
3578 If IsMissing(ContainsHeader) Or IsEmpty(ContainsHeader) Then ContainsHeader = False
3579 If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
3580 If IsMissing(SortColumns) Or IsEmpty(SortColumns) Then SortColumns = False
3581 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3582 If Not _IsStillAlive() Then GoTo Finally
3583 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
3584 If Not ScriptForge.SF_Utils._ValidateArray(SortKeys, &quot;SortKeys&quot;, 1, V_NUMERIC, True) Then GoTo Finally
3585 If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
3586 If Not ScriptForge.SF_Utils._ValidateArray(SortOrder, &quot;SortOrder&quot;, 1, V_STRING, True) Then GoTo Finally
3587 If Not ScriptForge.SF_Utils._Validate(ContainsHeader, &quot;ContainsHeader&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3588 If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3589 If Not ScriptForge.SF_Utils._Validate(SortColumns, &quot;SortColumns&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
3590 End If
3591 Set oRangeAddress = _ParseAddress(Range)
3592 If Len(DestinationCell) &gt; 0 Then Set oDestRange = _ParseAddress(DestinationCell) Else Set oDestRange = Nothing
3594 Try:
3595 &apos; Initialize a generic sort descriptor
3596 Set oRange = oRangeAddress.XCellRange
3597 vSortDescriptor = oRange.createSortDescriptor &apos; Makes a generic sort descriptor for ranges
3598 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;IsSortColumns&quot;, SortColumns)
3599 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;ContainsHeader&quot;, ContainsHeader)
3600 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;BindFormatsToContent&quot;, True)
3601 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;IsUserListEnabled&quot;, False)
3603 &apos; Sort by keys group
3604 &apos; If keys = (1, 2, 3, 4, 5) then groups = (4, 5), (1, 2, 3)
3605 lKeys = UBound(SortKeys)
3606 lSort = Int(lKeys / cstMaxKeys)
3607 Set oSortRange = oRangeAddress
3609 For j = lSort To 0 Step -1 &apos; Sort first on last sort keys
3611 &apos; The 1st sort must consider the destination area. Next sorts are done on the destination area
3612 If Len(DestinationCell) = 0 Or j &lt; lSort Then
3613 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;CopyOutputData&quot;, False)
3614 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;OutputPosition&quot;, Nothing)
3615 Else
3616 Set oDestAddress = oDestRange.XCellRange.RangeAddress
3617 Set oDestCell = New com.sun.star.table.CellAddress
3618 With oDestAddress
3619 oDestCell.Sheet = .Sheet
3620 oDestCell.Column = .StartColumn
3621 oDestCell.Row = .StartRow
3622 End With
3623 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;CopyOutputData&quot;, True)
3624 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;OutputPosition&quot;, oDestCell)
3625 End If
3627 &apos; Define the sorting keys
3628 vSortFields = DimArray(lKeys Mod cstMaxKeys)
3629 For i = 0 To UBound(vSortFields)
3630 vSortFields(i) = New com.sun.star.table.TableSortField
3631 lKey = j * cstMaxKeys + i
3632 If lKey &gt; UBound(SortOrder) Then sOrder = &quot;&quot; Else sOrder = SortOrder(lKey)
3633 If Len(sOrder) = 0 Then sOrder = &quot;ASC&quot;
3634 With vSortFields(i)
3635 .Field = SortKeys(lKey) - 1
3636 .IsAscending = ( UCase(sOrder) = &quot;ASC&quot; )
3637 .IsCaseSensitive = CaseSensitive
3638 End With
3639 Next i
3640 lKeys = lKeys - UBound(vSortFields) - 1
3642 &apos; Associate the keys and the descriptor, and sort
3643 vSortDescriptor = ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;SortFields&quot;, vSortFields)
3644 oSortRange.XCellRange.sort(vSortDescriptor)
3646 &apos; Next loop, if any, is done on the destination area
3647 If Len(DestinationCell) &gt; 0 And j = lSort And lSort &gt; 0 Then Set oSortRange = _Offset(oDestRange, 0, 0, oRangeAddress.Height, oRangeAddress.Width)
3649 Next j
3651 &apos; Compute the changed area
3652 If Len(DestinationCell) = 0 Then
3653 sSort = oRangeAddress.RangeName
3654 Else
3655 With oRangeAddress
3656 sSort = _Offset(oDestRange, 0, 0, .Height, .Width).RangeName
3657 End With
3658 End If
3660 Finally:
3661 SortRange = sSort
3662 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
3663 Exit Function
3664 Catch:
3665 GoTo Finally
3666 End Function &apos; SFDocuments.SF_Calc.SortRange
3668 REM ======================================================= SUPERCLASS PROPERTIES
3670 REM -----------------------------------------------------------------------------
3671 Property Get CustomProperties() As Variant
3672 CustomProperties = [_Super].GetProperty(&quot;CustomProperties&quot;)
3673 End Property &apos; SFDocuments.SF_Calc.CustomProperties
3675 REM -----------------------------------------------------------------------------
3676 Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
3677 [_Super].CustomProperties = pvCustomProperties
3678 End Property &apos; SFDocuments.SF_Calc.CustomProperties
3680 REM -----------------------------------------------------------------------------
3681 Property Get Description() As Variant
3682 Description = [_Super].GetProperty(&quot;Description&quot;)
3683 End Property &apos; SFDocuments.SF_Calc.Description
3685 REM -----------------------------------------------------------------------------
3686 Property Let Description(Optional ByVal pvDescription As Variant)
3687 [_Super].Description = pvDescription
3688 End Property &apos; SFDocuments.SF_Calc.Description
3690 REM -----------------------------------------------------------------------------
3691 Property Get DocumentProperties() As Variant
3692 DocumentProperties = [_Super].GetProperty(&quot;DocumentProperties&quot;)
3693 End Property &apos; SFDocuments.SF_Calc.DocumentProperties
3695 REM -----------------------------------------------------------------------------
3696 Property Get DocumentType() As String
3697 DocumentType = [_Super].GetProperty(&quot;DocumentType&quot;)
3698 End Property &apos; SFDocuments.SF_Calc.DocumentType
3700 REM -----------------------------------------------------------------------------
3701 Property Get ExportFilters() As Variant
3702 ExportFilters = [_Super].GetProperty(&quot;ExportFilters&quot;)
3703 End Property &apos; SFDocuments.SF_Calc.ExportFilters
3705 REM -----------------------------------------------------------------------------
3706 Property Get FileSystem() As String
3707 FileSystem = [_Super].GetProperty(&quot;FileSystem&quot;)
3708 End Property &apos; SFDocuments.SF_Calc.FileSystem
3710 REM -----------------------------------------------------------------------------
3711 Property Get ImportFilters() As Variant
3712 ImportFilters = [_Super].GetProperty(&quot;ImportFilters&quot;)
3713 End Property &apos; SFDocuments.SF_Calc.ImportFilters
3715 REM -----------------------------------------------------------------------------
3716 Property Get IsAlive() As Boolean
3717 IsAlive = [_Super].GetProperty(&quot;IsAlive&quot;)
3718 End Property &apos; SFDocuments.SF_Calc.IsAlive
3720 REM -----------------------------------------------------------------------------
3721 Property Get IsBase() As Boolean
3722 IsBase = [_Super].GetProperty(&quot;IsBase&quot;)
3723 End Property &apos; SFDocuments.SF_Calc.IsBase
3725 REM -----------------------------------------------------------------------------
3726 Property Get IsCalc() As Boolean
3727 IsCalc = [_Super].GetProperty(&quot;IsCalc&quot;)
3728 End Property &apos; SFDocuments.SF_Calc.IsCalc
3730 REM -----------------------------------------------------------------------------
3731 Property Get IsDraw() As Boolean
3732 IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
3733 End Property &apos; SFDocuments.SF_Calc.IsDraw
3735 REM -----------------------------------------------------------------------------
3736 Property Get IsFormDocument() As Boolean
3737 IsFormDocument = [_Super].GetProperty(&quot;IsFormDocument&quot;)
3738 End Property &apos; SFDocuments.SF_Writer.IsFormDocument
3740 REM -----------------------------------------------------------------------------
3741 Property Get IsImpress() As Boolean
3742 IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
3743 End Property &apos; SFDocuments.SF_Calc.IsImpress
3745 REM -----------------------------------------------------------------------------
3746 Property Get IsMath() As Boolean
3747 IsMath = [_Super].GetProperty(&quot;IsMath&quot;)
3748 End Property &apos; SFDocuments.SF_Calc.IsMath
3750 REM -----------------------------------------------------------------------------
3751 Property Get IsWriter() As Boolean
3752 IsWriter = [_Super].GetProperty(&quot;IsWriter&quot;)
3753 End Property &apos; SFDocuments.SF_Calc.IsWriter
3755 REM -----------------------------------------------------------------------------
3756 Property Get Keywords() As Variant
3757 Keywords = [_Super].GetProperty(&quot;Keywords&quot;)
3758 End Property &apos; SFDocuments.SF_Calc.Keywords
3760 REM -----------------------------------------------------------------------------
3761 Property Let Keywords(Optional ByVal pvKeywords As Variant)
3762 [_Super].Keywords = pvKeywords
3763 End Property &apos; SFDocuments.SF_Calc.Keywords
3765 REM -----------------------------------------------------------------------------
3766 Property Get Readonly() As Variant
3767 Readonly = [_Super].GetProperty(&quot;Readonly&quot;)
3768 End Property &apos; SFDocuments.SF_Calc.Readonly
3770 REM -----------------------------------------------------------------------------
3771 Property Get StyleFamilies() As Variant
3772 StyleFamilies = [_Super].GetProperty(&quot;StyleFamilies&quot;)
3773 End Property &apos; SFDocuments.SF_Calc.StyleFamilies
3775 REM -----------------------------------------------------------------------------
3776 Property Get Subject() As Variant
3777 Subject = [_Super].GetProperty(&quot;Subject&quot;)
3778 End Property &apos; SFDocuments.SF_Calc.Subject
3780 REM -----------------------------------------------------------------------------
3781 Property Let Subject(Optional ByVal pvSubject As Variant)
3782 [_Super].Subject = pvSubject
3783 End Property &apos; SFDocuments.SF_Calc.Subject
3785 REM -----------------------------------------------------------------------------
3786 Property Get Title() As Variant
3787 Title = [_Super].GetProperty(&quot;Title&quot;)
3788 End Property &apos; SFDocuments.SF_Calc.Title
3790 REM -----------------------------------------------------------------------------
3791 Property Let Title(Optional ByVal pvTitle As Variant)
3792 [_Super].Title = pvTitle
3793 End Property &apos; SFDocuments.SF_Calc.Title
3795 REM -----------------------------------------------------------------------------
3796 Property Get XComponent() As Variant
3797 XComponent = [_Super].GetProperty(&quot;XComponent&quot;)
3798 End Property &apos; SFDocuments.SF_Calc.XComponent
3800 REM -----------------------------------------------------------------------------
3801 Property Get XDocumentSettings() As Variant
3802 XDocumentSettings = [_Super].GetProperty(&quot;XDocumentSettings&quot;)
3803 End Property &apos; SFDocuments.SF_Calc.XDocumentSettings
3805 REM ========================================================== SUPERCLASS METHODS
3807 REM -----------------------------------------------------------------------------
3808 &apos;Public Function Activate() As Boolean
3809 &apos; Activate = [_Super].Activate()
3810 &apos;End Function &apos; SFDocuments.SF_Calc.Activate
3812 REM -----------------------------------------------------------------------------
3813 Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
3814 CloseDocument = [_Super].CloseDocument(SaveAsk)
3815 End Function &apos; SFDocuments.SF_Calc.CloseDocument
3817 REM -----------------------------------------------------------------------------
3818 Public Function ContextMenus(Optional ByVal ContextMenuName As Variant _
3819 , Optional ByVal SubmenuChar As Variant _
3820 ) As Variant
3821 ContextMenus = [_Super].ContextMenus(ContextMenuName, SubmenuChar)
3822 End Function &apos; SFDocuments.SF_Calc.ContextMenus
3824 REM -----------------------------------------------------------------------------
3825 Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
3826 , Optional ByVal Before As Variant _
3827 , Optional ByVal SubmenuChar As Variant _
3828 ) As Object
3829 Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
3830 End Function &apos; SFDocuments.SF_Calc.CreateMenu
3832 REM -----------------------------------------------------------------------------
3833 Public Sub DeleteStyles(Optional ByVal Family As Variant _
3834 , Optional ByRef StylesList As Variant _
3836 [_Super].DeleteStyles(Family, StylesList)
3837 End Sub &apos; SFDocuments.SF_Calc.DeleteStyles
3839 REM -----------------------------------------------------------------------------
3840 Public Sub Echo(Optional ByVal EchoOn As Variant _
3841 , Optional ByVal Hourglass As Variant _
3843 [_Super].Echo(EchoOn, Hourglass)
3844 End Sub &apos; SFDocuments.SF_Calc.Echo
3846 REM -----------------------------------------------------------------------------
3847 Public Function ExportAsPDF(Optional ByVal FileName As Variant _
3848 , Optional ByVal Overwrite As Variant _
3849 , Optional ByVal Pages As Variant _
3850 , Optional ByVal Password As Variant _
3851 , Optional ByVal Watermark As Variant _
3852 ) As Boolean
3853 ExportAsPDF = [_Super].ExportAsPDF(FileName, Overwrite, Pages, Password, Watermark)
3854 End Function &apos; SFDocuments.SF_Calc.ExportAsPDF
3856 REM -----------------------------------------------------------------------------
3857 Public Sub ImportStylesFromFile(Optional FileName As Variant _
3858 , Optional ByRef Families As Variant _
3859 , Optional ByVal Overwrite As variant _
3860 ) As Variant
3861 [_Super]._ImportStylesFromFile(FileName, Families, Overwrite)
3862 End Sub &apos; SFDocuments.SF_Calc.ImportStylesFromFile
3864 REM -----------------------------------------------------------------------------
3865 Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
3866 RemoveMenu = [_Super].RemoveMenu(MenuHeader)
3867 End Function &apos; SFDocuments.SF_Calc.RemoveMenu
3869 REM -----------------------------------------------------------------------------
3870 Public Sub RunCommand(Optional ByVal Command As Variant _
3871 , ParamArray Args As Variant _
3873 [_Super].RunCommand(Command, Args)
3874 End Sub &apos; SFDocuments.SF_Calc.RunCommand
3876 REM -----------------------------------------------------------------------------
3877 Public Function Save() As Boolean
3878 Save = [_Super].Save()
3879 End Function &apos; SFDocuments.SF_Calc.Save
3881 REM -----------------------------------------------------------------------------
3882 Public Function SaveAs(Optional ByVal FileName As Variant _
3883 , Optional ByVal Overwrite As Variant _
3884 , Optional ByVal Password As Variant _
3885 , Optional ByVal FilterName As Variant _
3886 , Optional ByVal FilterOptions As Variant _
3887 ) As Boolean
3888 SaveAs = [_Super].SaveAs(FileName, Overwrite, Password, FilterName, FilterOptions)
3889 End Function &apos; SFDocuments.SF_Calc.SaveAs
3891 REM -----------------------------------------------------------------------------
3892 Public Function SaveCopyAs(Optional ByVal FileName As Variant _
3893 , Optional ByVal Overwrite As Variant _
3894 , Optional ByVal Password As Variant _
3895 , Optional ByVal FilterName As Variant _
3896 , Optional ByVal FilterOptions As Variant _
3897 ) As Boolean
3898 SaveCopyAs = [_Super].SaveCopyAs(FileName, Overwrite, Password, FilterName, FilterOptions)
3899 End Function &apos; SFDocuments.SF_Calc.SaveCopyAs
3901 REM -----------------------------------------------------------------------------
3902 Public Function SetPrinter(Optional ByVal Printer As Variant _
3903 , Optional ByVal Orientation As Variant _
3904 , Optional ByVal PaperFormat As Variant _
3905 ) As Boolean
3906 SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
3907 End Function &apos; SFDocuments.SF_Calc.SetPrinter
3909 REM -----------------------------------------------------------------------------
3910 Public Function Styles(Optional ByVal Family As Variant _
3911 , Optional ByVal NamePattern As variant _
3912 , Optional ByVal Used As variant _
3913 , Optional ByVal UserDefined As Variant _
3914 , Optional ByVal ParentStyle As Variant _
3915 , Optional ByVal Category As Variant _
3916 ) As Variant
3917 Styles = [_Super].Styles(Family, NamePattern, Used, UserDefined, ParentStyle, Category)
3918 End Function &apos; SFDocuments.SF_Calc.Styles
3920 REM -----------------------------------------------------------------------------
3921 Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
3922 Toolbars = [_Super].Toolbars(ToolbarName)
3923 End Function &apos; SFDocuments.SF_Calc.Toolbars
3925 REM -----------------------------------------------------------------------------
3926 Public Function XStyle(Optional ByVal Family As Variant _
3927 , Optional ByVal StyleName As variant _
3928 ) As Object
3929 Set XStyle = [_Super].XStyle(Family, StyleName)
3930 End Function &apos; SFDocuments.SF_Calc.XStyle
3932 REM =========================================================== PRIVATE FUNCTIONS
3934 REM -----------------------------------------------------------------------------
3935 Private Sub _ClearRange(ByVal psTarget As String _
3936 , Optional ByVal Range As Variant _
3937 , Optional FilterFormula As Variant _
3938 , Optional FilterScope As Variant _
3940 &apos;&apos;&apos; Clear the given range with the given options
3941 &apos;&apos;&apos; The range may be filtered by a formula for a selective clearance
3942 &apos;&apos;&apos; Arguments checking is done in this Sub, not in the calling one
3943 &apos;&apos;&apos; Args:
3944 &apos;&apos;&apos; psTarget: &quot;All&quot;, &quot;Formats&quot; or &quot;Values&quot;
3945 &apos;&apos;&apos; Range: the range to clear as a string
3946 &apos;&apos;&apos; FilterFormula: a selection of cells based on a Calc formula
3947 &apos;&apos;&apos; When left empty, all the cells of the range are cleared
3948 &apos;&apos;&apos; psFilterScope: &quot;CELL&quot;, &quot;ROW&quot; or &quot;COLUMN&quot;
3950 Dim lClear As Long &apos; A combination of com.sun.star.sheet.CellFlags
3951 Dim oRange As Object &apos; Alias of Range
3952 Dim vRanges() As Variant &apos; Array of subranges resulting from the application of the filter
3953 Dim i As Long
3955 Dim cstThisSub As String : cstThisSub = &quot;SFDocuments.Calc.Clear&quot; &amp; psTarget
3956 Const cstSubArgs = &quot;Range, [FilterFormula=&quot;&quot;], [FilterScope=&quot;&quot;CELL&quot;&quot;|&quot;&quot;ROW&quot;&quot;|&quot;&quot;COLUMN&quot;&quot;]&quot;
3958 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
3960 Check:
3961 If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then FilterFormula = &quot;&quot;
3962 If IsMissing(FilterScope) Or IsEmpty(FilterScope) Then FilterScope = &quot;CELL&quot;
3963 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
3964 If Not _IsStillAlive() Then GoTo Finally
3965 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
3966 If Not ScriptForge.SF_Utils._Validate(FilterFormula, &quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
3967 If Len(FilterFormula) &gt; 0 Then
3968 If Not ScriptForge.SF_Utils._Validate(FilterScope, &quot;FilterScope&quot;, V_STRING, Array(&quot;CELL&quot;, &quot;ROW&quot;, &quot;COLUMN&quot;)) Then GoTo Finally
3969 Else
3970 If Not ScriptForge.SF_Utils._Validate(FilterScope, &quot;FilterScope&quot;, V_STRING) Then GoTo Finally
3971 End If
3972 End If
3974 Try:
3975 With com.sun.star.sheet.CellFlags
3976 Select Case psTarget
3977 Case &quot;All&quot;
3978 lClear = .VALUE + .DATETIME + .STRING + .ANNOTATION + .FORMULA _
3979 + .HARDATTR + .STYLES + .OBJECTS + .EDITATTR + .FORMATTED
3980 Case &quot;Formats&quot;
3981 lClear = .HARDATTR + .STYLES + .EDITATTR + .FORMATTED
3982 Case &quot;Values&quot;
3983 lClear = .VALUE + .DATETIME + .STRING + .FORMULA
3984 End Select
3985 End With
3987 If VarType(Range) = V_STRING Then Set oRange = _ParseAddress(Range) Else Set oRange = Range
3989 &apos; Without filter, the whole range is cleared
3990 &apos; Otherwise the filter cuts the range in subranges and clears them one by one
3991 If Len(FilterFormula) = 0 Then
3992 oRange.XCellRange.clearContents(lClear)
3993 Else
3994 vRanges() = _ComputeFilter(oRange, FilterFormula, UCase(FilterScope))
3995 For i = 0 To UBound(vRanges)
3996 vRanges(i).XCellRange.clearContents(lClear)
3997 Next i
3998 End If
4000 Finally:
4001 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
4002 Exit Sub
4003 Catch:
4004 GoTo Finally
4005 End Sub &apos; SFDocuments.SF_Calc._ClearRange
4007 REM -----------------------------------------------------------------------------
4008 Private Function _ComputeFilter(ByRef poRange As Object _
4009 , ByVal psFilterFormula As String _
4010 , ByVal psFilterScope As String _
4011 ) As Variant
4012 &apos;&apos;&apos; Compute in the given range the cells, rows or columns for which
4013 &apos;&apos;&apos; the given formula returns TRUE
4014 &apos;&apos;&apos; Args:
4015 &apos;&apos;&apos; poRange: the range on which to compute the filter as an _Address type
4016 &apos;&apos;&apos; psFilterFormula: the formula to be applied on each row, column or cell
4017 &apos;&apos;&apos; psFilterSCope: &quot;ROW&quot;, &quot;COLUMN&quot; or &quot;CELL&quot;
4018 &apos;&apos;&apos; Returns:
4019 &apos;&apos;&apos; An array of ranges as objects of type _Address
4021 Dim vRanges As Variant &apos; Return value
4022 Dim oRange As Object &apos; A single vRanges() item
4023 Dim lLast As Long &apos; Last used row or column number in the sheet containing Range
4024 Dim oFormulaRange As _Address &apos; Range where the FilterFormula must be stored
4025 Dim sFormulaDirection As String &apos; Either V(ertical), H(orizontal) or B(oth)
4026 Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
4027 Dim vFilter As Variant &apos; Array of Boolean values indicating which rows should be erased
4028 Dim bFilter As Boolean &apos; A single item in vFilter
4029 Dim iDims As Integer &apos; Number of dimensions of vFilter()
4030 Dim lLower As Long &apos; Lower level of contiguous True filter values
4031 Dim lUpper As Long &apos; Upper level of contiguous True filter values
4032 Dim i As Long, j As Long
4034 Check:
4035 &apos; Error handling is determined by the calling method
4036 vRanges = Array()
4038 Try:
4039 With poRange
4041 &apos; Compute the range where to apply the formula
4042 &apos; Determine the direction of the range containing the formula vertical, horizontal or both
4043 Select Case psFilterScope
4044 Case &quot;ROW&quot;
4045 lLast = LastColumn(.SheetName)
4046 &apos; Put formulas as a single column in the unused area at the right of the range to filter
4047 Set oFormulaRange = _Offset(poRange, 0, lLast - .XCellRange.RangeAddress.StartColumn + 1, 0, 1)
4048 sFormulaDirection = &quot;V&quot;
4049 Case &quot;COLUMN&quot;
4050 lLast = LastRow(.SheetName)
4051 &apos; Put formulas as a single row in the unused area at the bottom of the range to filter
4052 Set oFormulaRange = _Offset(poRange, lLast - .XCellRange.RangeAddress.StartRow + 1, 0, 1, 0)
4053 sFormulaDirection = &quot;H&quot;
4054 Case &quot;CELL&quot;
4055 lLast = LastRow(.SheetName)
4056 &apos; Put formulas as a matrix in the unused area at the bottom of the range to filter
4057 Set oFormulaRange = _Offset(poRange, lLast - .XCellRange.RangeAddress.StartRow + 1, 0, 0, 0)
4058 sFormulaDirection = &quot;B&quot;
4059 If oFormulaRange.Width = 1 Then
4060 sFormulaDirection = &quot;V&quot;
4061 ElseIf oFormulaRange.Height = 1 Then
4062 sFormulaDirection = &quot;H&quot;
4063 End If
4064 End Select
4066 &apos; Apply the formula and get the result as an array of Boolean values. Clean up
4067 SetFormula(oFormulaRange, psFilterFormula)
4068 vDataArray = oFormulaRange.XCellRange.getDataArray()
4069 vFilter = ScriptForge.SF_Array.ConvertFromDataArray(vDataArray)
4070 iDims = ScriptForge.SF_Array.CountDims(vFilter)
4071 ClearAll(oFormulaRange)
4073 &apos; Convert the filter values (0 = False, 1 = True) to a set of ranges
4074 Select Case iDims
4075 Case -1 &apos; Scalar
4076 If vFilter = 1 Then vRanges = ScriptForge.SF_Array.Append(vRanges, poRange)
4077 Case 0 &apos; Empty array
4078 &apos; Nothing to do
4079 Case 1, 2 &apos; Vector or Array
4080 &apos; Strategy: group contiguous applicable rows/columns to optimize heavy operations like CompactUp, CompactLeft
4081 &apos; Stack the contiguous ranges of True values in vRanges()
4083 &apos; To manage vector and array with same code, setup a single fictitious loop when vector, otherwise scan array by row
4084 For i = 0 To Iif(iDims = 1, 0, UBound(vFilter, 1))
4085 lLower = -1 : lUpper = -1
4087 For j = 0 To UBound(vFilter, iDims)
4088 If iDims = 1 Then bFilter = CBool(vFilter(j)) Else bFilter = CBool(vFilter(i, j))
4089 If j = UBound(vFilter, iDims) And bFilter Then &apos; Don&apos;t forget the last item
4090 If lLower &lt; 0 Then lLower = j
4091 lUpper = j
4092 ElseIf Not bFilter Then
4093 If lLower &gt;= 0 Then lUpper = j - 1
4094 ElseIf bFilter Then
4095 If lLower &lt; 0 Then lLower = j
4096 End If
4097 &apos; Determine the next applicable range when one found and limit reached
4098 If lUpper &gt; -1 Then
4099 If sFormulaDirection = &quot;V&quot; Then &apos; ROW
4100 Set oRange = _Offset(poRange, lLower, 0, lUpper - lLower + 1, 0)
4101 ElseIf sFormulaDirection = &quot;H&quot; Then &apos; COLUMN
4102 Set oRange = _Offset(poRange, 0, lLower, 0, lUpper - lLower + 1)
4103 Else &apos; CELL
4104 Set oRange = _Offset(poRange, i, lLower, 1, lUpper - lLower + 1)
4105 End If
4106 If Not IsNull(oRange) Then vRanges = ScriptForge.SF_Array.Append(vRanges, oRange)
4107 lLower = -1 : lUpper = -1
4108 End If
4109 Next j
4111 Next i
4112 Case Else
4113 &apos; Should not happen
4114 End Select
4116 End With
4118 Finally:
4119 _ComputeFilter = vRanges()
4120 Exit Function
4121 End Function &apos; SFDocuments.SF_Calc._ComputeFilter
4123 REM -----------------------------------------------------------------------------
4124 Private Function _DFunction(ByVal psFunction As String _
4125 , Optional ByVal Range As Variant _
4126 ) As Double
4127 &apos;&apos;&apos; Apply the given function on all the numeric values stored in the given range
4128 &apos;&apos;&apos; Args:
4129 &apos;&apos;&apos; Range : the range as a string where to apply the function on
4130 &apos;&apos;&apos; Returns:
4131 &apos;&apos;&apos; The resulting value as a double
4133 Dim dblGet As Double &apos; Return value
4134 Dim oAddress As Object &apos; Alias of Range
4135 Dim vFunction As Variant &apos; com.sun.star.sheet.GeneralFunction.XXX
4136 Dim cstThisSub As String : cstThisSub = &quot;SFDocuments.Calc.&quot; &amp; psFunction
4137 Const cstSubArgs = &quot;Range&quot;
4139 If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
4140 dblGet = 0
4142 Check:
4143 If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
4144 If Not _IsStillAlive() Then GoTo Finally
4145 If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
4146 End If
4148 Try:
4149 &apos; Get the data
4150 Set oAddress = _ParseAddress(Range)
4151 Select Case psFunction
4152 Case &quot;DAvg&quot; : vFunction = com.sun.star.sheet.GeneralFunction.AVERAGE
4153 Case &quot;DCount&quot; : vFunction = com.sun.star.sheet.GeneralFunction.COUNTNUMS
4154 Case &quot;DMax&quot; : vFunction = com.sun.star.sheet.GeneralFunction.MAX
4155 Case &quot;DMin&quot; : vFunction = com.sun.star.sheet.GeneralFunction.MIN
4156 Case &quot;DSum&quot; : vFunction = com.sun.star.sheet.GeneralFunction.SUM
4157 Case Else : GoTo Finally
4158 End Select
4159 dblGet = oAddress.XCellRange.computeFunction(vFunction)
4161 Finally:
4162 _DFunction = dblGet
4163 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
4164 Exit Function
4165 Catch:
4166 GoTo Finally
4167 End Function &apos; SFDocuments.SF_Calc._DFunction
4169 REM -----------------------------------------------------------------------------
4170 Private Function _FileIdent() As String
4171 &apos;&apos;&apos; Returns a file identification from the information that is currently available
4172 &apos;&apos;&apos; Useful e.g. for display in error messages
4174 _FileIdent = [_Super]._FileIdent()
4176 End Function &apos; SFDocuments.SF_Calc._FileIdent
4178 REM -----------------------------------------------------------------------------
4179 Function _GetColumnName(ByVal plColumnNumber As Long) As String
4180 &apos;&apos;&apos; Convert a column number (range 1, 2,..16384) into its letter counterpart (range &apos;A&apos;, &apos;B&apos;,..&apos;XFD&apos;).
4181 &apos;&apos;&apos; Args:
4182 &apos;&apos;&apos; ColumnNumber: the column number, must be in the interval 1 ... 16384
4183 &apos;&apos;&apos; Returns:
4184 &apos;&apos;&apos; a string representation of the column name, in range &apos;A&apos;..&apos;XFD&apos;
4185 &apos;&apos;&apos; Adapted from a Python function by sundar nataraj
4186 &apos;&apos;&apos; http://stackoverflow.com/questions/23861680/convert-spreadsheet-number-to-column-letter
4188 Dim sCol As String &apos; Return value
4189 Dim lDiv As Long &apos; Intermediate result
4190 Dim lMod As Long &apos; Result of modulo 26 operation
4192 Try:
4193 sCol = &quot;&quot;
4194 lDiv = plColumnNumber
4195 Do While lDiv &gt; 0
4196 lMod = (lDiv - 1) Mod 26
4197 sCol = Chr(65 + lMod) &amp; sCol
4198 lDiv = (lDiv - lMod) \ 26
4199 Loop
4201 Finally:
4202 _GetColumnName = sCol
4203 End Function &apos; SFDocuments.SF_Calc._GetColumnName
4205 REM -----------------------------------------------------------------------------
4206 Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
4207 , Optional ByVal pbError As Boolean _
4208 ) As Boolean
4209 &apos;&apos;&apos; Returns True if the document has not been closed manually or incidentally since the last use
4210 &apos;&apos;&apos; If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
4211 &apos;&apos;&apos; Args:
4212 &apos;&apos;&apos; pbForUpdate: if True (default = False), check additionally if document is open for editing
4213 &apos;&apos;&apos; pbError: if True (default), raise a fatal error
4215 Dim bAlive As Boolean &apos; Return value
4217 If IsMissing(pbForUpdate) Then pbForUpdate = False
4218 If IsMissing(pbError) Then pbError = True
4220 Try:
4221 bAlive = [_Super]._IsStillAlive(pbForUpdate, pbError)
4223 Finally:
4224 _IsStillAlive = bAlive
4225 Exit Function
4226 End Function &apos; SFDocuments.SF_Calc._IsStillAlive
4228 REM -----------------------------------------------------------------------------
4229 Private Function _LastCell(ByRef poSheet As Object) As Variant
4230 &apos;&apos;&apos; Returns in an array the coordinates of the last used cell in the given sheet
4232 Dim oCursor As Object &apos; Cursor on the cell
4233 Dim oRange As Object &apos; The used range
4234 Dim vCoordinates(0 To 1) As Long &apos; Return value: (0) = Column, (1) = Row
4236 Try:
4237 Set oCursor = poSheet.createCursorByRange(poSheet.getCellRangeByName(&quot;A1&quot;))
4238 oCursor.gotoEndOfUsedArea(True)
4239 Set oRange = poSheet.getCellRangeByName(oCursor.AbsoluteName)
4241 vCoordinates(0) = oRange.RangeAddress.EndColumn + 1
4242 vCoordinates(1) = oRange.RangeAddress.EndRow + 1
4244 Finally:
4245 _LastCell = vCoordinates
4246 End Function &apos; SFDocuments.SF_Calc._LastCell
4248 REM -----------------------------------------------------------------------------
4249 Public Function _Offset(ByRef pvRange As Variant _
4250 , ByVal plRows As Long _
4251 , ByVal plColumns As Long _
4252 , ByVal plHeight As Long _
4253 , ByVal plWidth As Long _
4254 ) As Object
4255 &apos;&apos;&apos; Returns a new range offset by a certain number of rows and columns from a given range
4256 &apos;&apos;&apos; Args:
4257 &apos;&apos;&apos; pvRange : the range, as a string or an object, from which the function searches for the new range
4258 &apos;&apos;&apos; plRows : the number of rows by which the reference was corrected up (negative value) or down.
4259 &apos;&apos;&apos; plColumns : the number of columns by which the reference was corrected to the left (negative value) or to the right.
4260 &apos;&apos;&apos; plHeight : the vertical height for an area that starts at the new reference position.
4261 &apos;&apos;&apos; plWidth : the horizontal width for an area that starts at the new reference position.
4262 &apos;&apos;&apos; Arguments Rows and Columns must not lead to zero or negative start row or column.
4263 &apos;&apos;&apos; Arguments Height and Width must not lead to zero or negative count of rows or columns.
4264 &apos;&apos;&apos; Returns:
4265 &apos;&apos;&apos; A new range as object of type _Address
4266 &apos;&apos;&apos; Exceptions:
4267 &apos;&apos;&apos; OFFSETADDRESSERROR The computed range of cells falls beyond the sheet boundaries
4269 Dim oOffset As Object &apos; Return value
4270 Dim oAddress As Object &apos; Alias of Range
4271 Dim oSheet As Object &apos; com.sun.star.sheet.XSpreadsheet
4272 Dim oRange As Object &apos; com.sun.star.table.XCellRange
4273 Dim oNewRange As Object &apos; com.sun.star.table.XCellRange
4274 Dim lLeft As Long &apos; New range coordinates
4275 Dim lTop As Long
4276 Dim lRight As Long
4277 Dim lBottom As Long
4279 Set oOffset = Nothing
4281 Check:
4282 If plHeight &lt; 0 Or plWidth &lt; 0 Then GoTo CatchAddress
4284 Try:
4285 If VarType(pvRange) = V_STRING Then Set oAddress = _ParseAddress(pvRange) Else Set oAddress = pvRange
4286 Set oSheet = oAddress.XSpreadSheet
4287 Set oRange = oAddress.XCellRange.RangeAddress
4290 &apos; Compute and validate new coordinates
4291 With oRange
4292 lLeft = .StartColumn + plColumns
4293 lTop = .StartRow + plRows
4294 lRight = lLeft + Iif(plWidth = 0, .EndColumn - .StartColumn, plWidth - 1)
4295 lBottom = lTop + Iif(plHeight = 0, .EndRow - .StartRow, plHeight - 1)
4296 If lLeft &lt; 0 Or lRight &lt; 0 Or lTop &lt; 0 Or lBottom &lt; 0 _
4297 Or lLeft &gt;= MAXCOLS Or lRight &gt;= MAXCOLS _
4298 Or lTop &gt;= MAXROWS Or lBottom &gt;= MAXROWS _
4299 Then GoTo CatchAddress
4300 Set oNewRange = oSheet.getCellRangeByPosition(lLeft, lTop, lRight, lBottom)
4301 End With
4303 &apos; Define the new range address
4304 Set oOffset = New _Address
4305 With oOffset
4306 .ObjectType = CALCREFERENCE
4307 .ServiceName = SERVICEREFERENCE
4308 .RawAddress = oNewRange.AbsoluteName
4309 .Component = _Component
4310 .XSpreadsheet = oNewRange.Spreadsheet
4311 .SheetName = .XSpreadsheet.Name
4312 .SheetIndex = .XSpreadsheet.RangeAddress.Sheet
4313 .RangeName = .RawAddress
4314 .XCellRange = oNewRange
4315 .Height = oNewRange.RangeAddress.EndRow - oNewRange.RangeAddress.StartRow + 1
4316 .Width = oNewRange.RangeAddress.EndColumn - oNewRange.RangeAddress.StartColumn + 1
4317 End With
4319 Finally:
4320 Set _Offset = oOffset
4321 Exit Function
4322 Catch:
4323 GoTo Finally
4324 CatchAddress:
4325 ScriptForge.SF_Exception.RaiseFatal(OFFSETADDRESSERROR, &quot;Range&quot;, oAddress.RawAddress _
4326 , &quot;Rows&quot;, plRows, &quot;Columns&quot;, plColumns, &quot;Height&quot;, plHeight, &quot;Width&quot;, plWidth _
4327 , &quot;Document&quot;, [_Super]._FileIdent())
4328 GoTo Finally
4329 End Function &apos; SFDocuments.SF_Calc._Offset
4331 REM -----------------------------------------------------------------------------
4332 Private Function _ParseAddress(ByVal psAddress As String) As Object
4333 &apos;&apos;&apos; Parse and validate a sheet or range reference
4334 &apos;&apos;&apos; Syntax to parse:
4335 &apos;&apos;&apos; [Sheet].[Range]
4336 &apos;&apos;&apos; Sheet =&gt; [$][&apos;]sheet[&apos;] or document named range or ~
4337 &apos;&apos;&apos; Range =&gt; A1:D10, A1, A:D, 10:10 ($ ignored), or sheet named range or ~ or *
4338 &apos;&apos;&apos; Returns:
4339 &apos;&apos;&apos; An object of type _Address
4340 &apos;&apos;&apos; Exceptions:
4341 &apos;&apos;&apos; CALCADDRESSERROR &apos; Address could not be parsed to a valid address
4343 Dim oAddress As Object &apos; Return value
4344 Dim sAddress As String &apos; Alias of psAddress
4345 Dim vRangeName As Variant &apos; Array Sheet/Range
4346 Dim lStart As Long &apos; Position of found regex
4347 Dim sSheet As String &apos; Sheet component
4348 Dim sRange As String &apos; Range component
4349 Dim oSheets As Object &apos; com.sun.star.sheet.XSpreadsheets
4350 Dim oNamedRanges As Object &apos; com.sun.star.sheet.XNamedRanges
4351 Dim oRangeAddress As Object &apos; Alias for rangeaddress
4352 Dim vLastCell As Variant &apos; Result of _LastCell() method
4353 Dim oSelect As Object &apos; Current selection
4355 &apos; If psAddress has already been parsed, get the result back
4356 If Not IsNull(_LastParsedAddress) Then
4357 &apos; Given argument must contain an explicit reference to a sheet
4358 If (InStr(psAddress, &quot;~.&quot;) = 0 And InStr(psAddress, &quot;.&quot;) &gt; 0 And psAddress = _LastParsedAddress.RawAddress) _
4359 Or psAddress = _LastParsedAddress.RangeName Then
4360 Set _ParseAddress = _LastParsedAddress
4361 Exit Function
4362 Else
4363 Set _LastParsedAddress = Nothing
4364 End If
4365 End If
4367 &apos; Reinitialize a new _Address object
4368 Set oAddress = New _Address
4369 With oAddress
4370 sSheet = &quot;&quot; : sRange = &quot;&quot;
4371 .SheetName = &quot;&quot; : .RangeName = &quot;&quot;
4373 .ObjectType = CALCREFERENCE
4374 .ServiceName = SERVICEREFERENCE
4375 .RawAddress = psAddress
4376 Set .XSpreadSheet = Nothing : Set .XCellRange = Nothing
4378 &apos; Remove leading &quot;$&apos; when followed with an apostrophe
4379 If Left(psAddress, 2) = &quot;$&apos;&quot; Then sAddress = Mid(psAddress, 2) Else sAddress = psAddress
4380 &apos; Split in sheet and range components on dot not enclosed in single quotes
4381 vRangeName = ScriptForge.SF_String.SplitNotQuoted(sAddress, Delimiter := &quot;.&quot;, QuoteChar := &quot;&apos;&quot;)
4382 sSheet = ScriptForge.SF_String.Unquote(Replace(vRangeName(0), &quot;&apos;&apos;&quot;, &quot;\&apos;&quot;), QuoteChar := &quot;&apos;&quot;)
4383 &apos; Keep a leading &quot;$&quot; in the sheet name only if name enclosed in single quotes
4384 &apos; Notes:
4385 &apos; sheet names may contain &quot;$&quot; (even &quot;$&quot; is a valid sheet name), named ranges must not
4386 &apos; sheet names may contain apostrophes (except in 1st and last positions), range names must not
4387 If Left(vRangeName(0), 2) &lt;&gt; &quot;&apos;$&quot; And Left(sSheet, 1) = &quot;$&quot; And Len(sSheet) &gt; 1 Then sSheet = Mid(sSheet, 2)
4388 If UBound(vRangeName) &gt; 0 Then sRange = vRangeName(1)
4390 &apos; Resolve sheet part: either a document named range, or the active sheet or a real sheet
4391 Set oSheets = _Component.getSheets()
4392 Set oNamedRanges = _Component.NamedRanges
4393 If oSheets.hasByName(sSheet) Then
4394 ElseIf sSheet = &quot;~&quot; And Len(sRange) &gt; 0 Then
4395 sSheet = _Component.CurrentController.ActiveSheet.Name
4396 ElseIf oNamedRanges.hasByName(sSheet) Then
4397 .XCellRange = oNamedRanges.getByName(sSheet).ReferredCells
4398 sSheet = oSheets.getByIndex(oNamedRanges.getByName(sSheet).ReferencePosition.Sheet).Name
4399 Else
4400 sRange = sSheet
4401 sSheet = _Component.CurrentController.ActiveSheet.Name
4402 End If
4403 .SheetName = sSheet
4404 .XSpreadSheet = oSheets.getByName(sSheet)
4405 .SheetIndex = .XSpreadSheet.RangeAddress.Sheet
4407 &apos; Resolve range part - either a sheet named range or the current selection or a real range or &quot;&quot;
4408 If IsNull(.XCellRange) Then
4409 Set oNamedRanges = .XSpreadSheet.NamedRanges
4410 If sRange = &quot;~&quot; Then
4411 Set oSelect = _Component.CurrentController.getSelection()
4412 If oSelect.supportsService(&quot;com.sun.star.sheet.SheetCellRanges&quot;) Then &apos; Multiple selections
4413 Set .XCellRange = oSelect.getByIndex(0)
4414 Else
4415 Set .XCellRange = oSelect
4416 End If
4417 ElseIf sRange = &quot;*&quot; Or sRange = &quot;&quot; Then
4418 vLastCell = _LastCell(.XSpreadSheet)
4419 sRange = &quot;A1:&quot; &amp; _GetColumnName(vLastCell(0)) &amp; CStr(vLastCell(1))
4420 Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
4421 ElseIf oNamedRanges.hasByName(sRange) Then
4422 .XCellRange = oNamedRanges.getByName(sRange).ReferredCells
4423 Else
4424 On Local Error GoTo CatchError
4425 Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
4426 &apos; If range reaches the limits of the sheets, reduce it up to the used area
4427 Set oRangeAddress = .XCellRange.RangeAddress
4428 If oRangeAddress.StartColumn = 0 And oRangeAddress.EndColumn = MAXCOLS - 1 Then
4429 vLastCell = _LastCell(.XSpreadSheet)
4430 sRange = &quot;A&quot; &amp; CStr(oRangeAddress.StartRow + 1) &amp; &quot;:&quot; _
4431 &amp; _GetColumnName(vLastCell(0)) &amp; CStr(oRangeAddress.EndRow + 1)
4432 Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
4433 ElseIf oRangeAddress.StartRow = 0 And oRangeAddress.EndRow = MAXROWS - 1 Then
4434 vLastCell = _LastCell(.XSpreadSheet)
4435 sRange = _GetColumnName(oRangeAddress.StartColumn + 1) &amp; &quot;1&quot; &amp; &quot;:&quot; _
4436 &amp; _GetColumnName(oRangeAddress.EndColumn + 1) &amp; CStr(_LastCell(.XSpreadSheet)(1))
4437 Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
4438 End If
4439 End If
4440 End If
4441 If IsNull(.XCellRange) Then GoTo CatchAddress
4443 Set oRangeAddress = .XCellRange.RangeAddress
4444 .RangeName = .XCellRange.AbsoluteName
4445 .Height = oRangeAddress.EndRow - oRangeAddress.StartRow + 1
4446 .Width = oRangeAddress.EndColumn - oRangeAddress.StartColumn + 1
4448 &apos; Remember the current component in case of use outside the current instance
4449 Set .Component = _Component
4451 End With
4453 &apos; Store last parsed address for reuse
4454 Set _LastParsedAddress = oAddress
4456 Finally:
4457 Set _ParseAddress = oAddress
4458 Exit Function
4459 CatchError:
4460 ScriptForge.SF_Exception.Clear()
4461 CatchAddress:
4462 ScriptForge.SF_Exception.RaiseFatal(CALCADDRESSERROR, &quot;Range&quot;, psAddress _
4463 , &quot;Document&quot;, [_Super]._FileIdent())
4464 GoTo Finally
4465 End Function &apos; SFDocuments.SF_Calc._ParseAddress
4467 REM -----------------------------------------------------------------------------
4468 Private Function _PropertyGet(Optional ByVal psProperty As String _
4469 , Optional ByVal pvArg As Variant _
4470 ) As Variant
4471 &apos;&apos;&apos; Return the value of the named property
4472 &apos;&apos;&apos; Args:
4473 &apos;&apos;&apos; psProperty: the name of the property
4475 Dim oProperties As Object &apos; Document or Custom properties
4476 Dim vLastCell As Variant &apos; Coordinates of last used cell in a sheet
4477 Dim oSelect As Object &apos; Current selection
4478 Dim vRanges As Variant &apos; List of selected ranges
4479 Dim oAddress As Object &apos; _Address type for range description
4480 Dim oCursor As Object &apos; com.sun.star.sheet.XSheetCellCursor
4481 Dim i As Long
4482 Dim cstThisSub As String
4483 Const cstSubArgs = &quot;&quot;
4485 _PropertyGet = False
4487 cstThisSub = &quot;SFDocuments.Calc.get&quot; &amp; psProperty
4488 ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
4489 If Not _IsStillAlive() Then GoTo Finally
4491 Select Case UCase(psProperty)
4492 Case UCase(&quot;CurrentSelection&quot;)
4493 Set oSelect = _Component.CurrentController.getSelection()
4494 If IsNull(oSelect) Then
4495 _PropertyGet = Array()
4496 ElseIf oSelect.supportsService(&quot;com.sun.star.sheet.SheetCellRanges&quot;) Then &apos; Multiple selections
4497 vRanges = Array()
4498 For i = 0 To oSelect.Count - 1
4499 vRanges = ScriptForge.SF_Array.Append(vRanges, oSelect.getByIndex(i).AbsoluteName)
4500 Next i
4501 _PropertyGet = vRanges
4502 Else
4503 _PropertyGet = oSelect.AbsoluteName
4504 End If
4505 Case UCase(&quot;Height&quot;)
4506 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4507 _PropertyGet = 0
4508 Else
4509 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4510 _PropertyGet = _ParseAddress(pvArg).Height
4511 End If
4512 Case UCase(&quot;FirstCell&quot;), UCase(&quot;FirstRow&quot;), UCase(&quot;FirstColumn&quot;) _
4513 , UCase(&quot;LastCell&quot;), UCase(&quot;LastColumn&quot;), UCase(&quot;LastRow&quot;) _
4514 , UCase(&quot;SheetName&quot;)
4515 If IsMissing(pvArg) Or IsEmpty(pvArg) Then &apos; Avoid errors when instance is watched in Basic IDE
4516 If InStr(UCase(psProperty), &quot;CELL&quot;) &gt; 0 Then _PropertyGet = &quot;&quot; Else _PropertyGet = -1
4517 Else
4518 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4519 Set oAddress = _ParseAddress(pvArg)
4520 With oAddress.XCellRange
4521 Select Case UCase(psProperty)
4522 Case UCase(&quot;FirstCell&quot;)
4523 _PropertyGet = A1Style(.RangeAddress.StartRow + 1, .RangeAddress.StartColumn + 1, , , oAddress.XSpreadsheet.Name)
4524 Case UCase(&quot;FirstColumn&quot;) : _PropertyGet = CLng(.RangeAddress.StartColumn + 1)
4525 Case UCase(&quot;FirstRow&quot;) : _PropertyGet = CLng(.RangeAddress.StartRow + 1)
4526 Case UCase(&quot;LastCell&quot;)
4527 _PropertyGet = A1Style(.RangeAddress.EndRow + 1, .RangeAddress.EndColumn + 1, , , oAddress.XSpreadsheet.Name)
4528 Case UCase(&quot;LastColumn&quot;) : _PropertyGet = CLng(.RangeAddress.EndColumn + 1)
4529 Case UCase(&quot;LastRow&quot;) : _PropertyGet = CLng(.RangeAddress.EndRow + 1)
4530 Case UCase(&quot;SheetName&quot;) : _PropertyGet = oAddress.XSpreadsheet.Name
4531 End Select
4532 End With
4533 End If
4534 Case UCase(&quot;Range&quot;)
4535 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4536 Set _PropertyGet = Nothing
4537 Else
4538 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4539 Set _PropertyGet = _ParseAddress(pvArg)
4540 End If
4541 Case UCase(&quot;Region&quot;)
4542 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4543 _PropertyGet = &quot;&quot;
4544 Else
4545 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4546 Set oAddress = _ParseAddress(pvArg)
4547 With oAddress
4548 Set oCursor = .XSpreadsheet.createCursorByRange(.XCellRange)
4549 oCursor.collapseToCurrentRegion()
4550 _PropertyGet = oCursor.AbsoluteName
4551 End With
4552 End If
4553 Case UCase(&quot;Sheet&quot;)
4554 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4555 Set _PropertyGet = Nothing
4556 Else
4557 If Not _ValidateSheet(pvArg, &quot;SheetName&quot;, , True) Then GoTo Finally
4558 Set _PropertyGet = _ParseAddress(pvArg)
4559 End If
4560 Case UCase(&quot;Sheets&quot;)
4561 _PropertyGet = _Component.getSheets.getElementNames()
4562 Case UCase(&quot;Width&quot;)
4563 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4564 _PropertyGet = 0
4565 Else
4566 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4567 _PropertyGet = _ParseAddress(pvArg).Width
4568 End If
4569 Case UCase(&quot;XCellRange&quot;)
4570 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4571 Set _PropertyGet = Nothing
4572 Else
4573 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4574 Set _PropertyGet = _ParseAddress(pvArg).XCellRange
4575 End If
4576 Case UCase(&quot;XRectangle&quot;)
4577 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4578 Set _PropertyGet = Nothing
4579 Else
4580 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4581 Set _PropertyGet = _RangePosition(pvArg)
4582 End If
4583 Case UCase(&quot;XSheetCellCursor&quot;)
4584 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4585 Set _PropertyGet = Nothing
4586 Else
4587 If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
4588 Set oAddress = _ParseAddress(pvArg)
4589 Set _PropertyGet = oAddress.XSpreadsheet.createCursorByRange(oAddress.XCellRange)
4590 End If
4591 Case UCase(&quot;XSpreadsheet&quot;)
4592 If IsMissing(pvArg) Or IsEmpty(pvArg) Then
4593 Set _PropertyGet = Nothing
4594 Else
4595 If Not _ValidateSheet(pvArg, &quot;SheetName&quot;, , True) Then GoTo Finally
4596 Set _PropertyGet = _Component.getSheets.getByName(pvArg)
4597 End If
4598 Case Else
4599 _PropertyGet = Null
4600 End Select
4602 Finally:
4603 ScriptForge.SF_Utils._ExitFunction(cstThisSub)
4604 Exit Function
4605 End Function &apos; SFDocuments.SF_Calc._PropertyGet
4607 REM -----------------------------------------------------------------------------
4608 Private Function _QuoteSheetName(ByVal psSheetName As String) As String
4609 &apos;&apos;&apos; Return the given sheet name surrounded with single quotes
4610 &apos;&apos;&apos; when required to insert the sheet name into a Calc formula
4611 &apos;&apos;&apos; Enclosed single quotes are doubled
4612 &apos;&apos;&apos; Args:
4613 &apos;&apos;&apos; psSheetName: the name to quote
4614 &apos;&apos;&apos; Returns:
4615 &apos;&apos;&apos; The quoted or unchanged sheet name
4617 Dim sSheetName As String &apos; Return value
4618 Dim i As Long
4620 Try:
4621 &apos; Surround the sheet name with single quotes when required by the presence of single quotes
4622 If InStr(psSheetName, &quot;&apos;&quot;) &gt; 0 Then
4623 sSheetName = &quot;&apos;&quot; &amp; Replace(psSheetName, &quot;&apos;&quot;, &quot;&apos;&apos;&quot;) &amp; &quot;&apos;&quot;
4624 Else
4625 &apos; Surround the sheet name with single quotes when required by the presence of at least one of the special characters
4626 sSheetName = psSheetName
4627 For i = 1 To Len(cstSPECIALCHARS)
4628 If InStr(sSheetName, Mid(cstSPECIALCHARS, i, 1)) &gt; 0 Then
4629 sSheetName = &quot;&apos;&quot; &amp; sSheetName &amp; &quot;&apos;&quot;
4630 Exit For
4631 End If
4632 Next i
4633 End If
4635 Finally:
4636 _QuoteSheetName = sSheetName
4637 Exit Function
4638 End Function &apos; SFDocuments.SF_Calc._QuoteSheetName
4640 REM -----------------------------------------------------------------------------
4641 Private Function _RangePosition(ByVal psRange As String) As Object
4642 &apos;&apos;&apos; Determine a best guess of the coordinates (in pixels) of the given range
4643 &apos;&apos;&apos; Inspired (and enhanced) from https://forum.openoffice.org/en/forum/viewtopic.php?p=308693#p308693
4644 &apos;&apos;&apos; Args:
4645 &apos;&apos;&apos; psRange: the range as a string
4646 &apos;&apos;&apos; Returns:
4647 &apos;&apos;&apos; a com.sun.star.awt.Rectangle UNO structure
4649 Dim oRectOnScreen As New com.sun.star.awt.Rectangle &apos; Range position versus top-left screen corner (return value)
4650 Dim oRect As New com.sun.star.awt.Rectangle &apos; Range position versus the A1 cell
4651 Dim oLocation As Object &apos; com.sun.star.awt.Rectangle
4652 Dim oController As Object &apos; Current controller
4653 Dim oXRange As Object &apos; com.sun.star.Table.CellRange
4655 Check:
4656 On Local Error GoTo Finally
4658 Try:
4659 Set oController = _Component.CurrentController
4660 Set oXRange = _ParseAddress(psRange).XCellRange
4661 &apos; Grab the window location on the screen
4662 Set oLocation = oController.ComponentWindow.AccessibleContext.LocationOnScreen
4664 With oRect
4665 .X = oXRange.Position.X
4666 .Y = oXRange.Position.Y
4667 .Width = oXRange.Size.Width
4668 .Height = oXRange.Size.Height
4669 End With
4671 &apos;Compute the rectangle in pixels (empirical computation)
4672 With oController
4673 oRectOnScreen.X = .VisibleAreaOnScreen.X _
4674 + .VisibleAreaOnScreen.Width * (oRect.X - .VisibleArea.X) / .VisibleArea.Width _
4675 - oLocation.X
4676 oRectOnScreen.Y = .VisibleAreaOnScreen.Y _
4677 + .VisibleAreaOnScreen.Height * (oRect.Y - .VisibleArea.Y) / .VisibleArea.Height _
4678 - oLocation.Y
4679 oRectOnScreen.Width = oRect.Width * .VisibleAreaOnScreen.Width / .VisibleArea.Width
4680 oRectOnScreen.Height = oRect.Height * .VisibleAreaOnScreen.Height / .VisibleArea.Height
4681 End With
4683 Finally:
4684 Set _RangePosition = oRectOnScreen
4685 Exit Function
4686 End Function &apos; SFDocuments.SF_Calc._RangePosition
4688 REM -----------------------------------------------------------------------------
4689 Private Function _Repr() As String
4690 &apos;&apos;&apos; Convert the SF_Calc instance to a readable string, typically for debugging purposes (DebugPrint ...)
4691 &apos;&apos;&apos; Args:
4692 &apos;&apos;&apos; Return:
4693 &apos;&apos;&apos; &quot;[DOCUMENT]: Type/File&quot;
4695 _Repr = &quot;[Calc]: &quot; &amp; [_Super]._FileIdent()
4697 End Function &apos; SFDocuments.SF_Calc._Repr
4699 REM -----------------------------------------------------------------------------
4700 Private Sub _RestoreSelections(ByRef pvComponent As Variant _
4701 , ByRef pvSelection As Variant _
4703 &apos;&apos;&apos; Set the selection to a single or a multiple range
4704 &apos;&apos;&apos; Does not work well when multiple selections and macro terminating in Basic IDE
4705 &apos;&apos;&apos; Called by the CopyToCell and CopyToRange methods
4706 &apos;&apos;&apos; Args:
4707 &apos;&apos;&apos; pvComponent: should work for foreign instances as well
4708 &apos;&apos;&apos; pvSelection: the stored selection done previously by Component.CurrentController.getSelection()
4710 Dim oCellRanges As Object &apos; com.sun.star.sheet.SheetCellRanges
4711 Dim vRangeAddresses As Variant &apos; Array of com.sun.star.table.CellRangeAddress
4712 Dim i As Long
4714 Try:
4715 If IsArray(pvSelection) Then
4716 Set oCellRanges = pvComponent.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
4717 vRangeAddresses = Array()
4718 ReDim vRangeAddresses(0 To UBound(pvSelection))
4719 For i = 0 To UBound(pvSelection)
4720 vRangeAddresses(i) = pvSelection.getByIndex(i).RangeAddress
4721 Next i
4722 oCellRanges.addRangeAddresses(vRangeAddresses, False)
4723 pvComponent.CurrentController.select(oCellRanges)
4724 Else
4725 pvComponent.CurrentController.select(pvSelection)
4726 End If
4728 Finally:
4729 Exit Sub
4730 End Sub &apos; SFDocuments.SF_Calc._RestoreSelections
4732 REM -----------------------------------------------------------------------------
4733 Private Function _ValidateSheet(Optional ByRef pvSheetName As Variant _
4734 , Optional ByVal psArgName As String _
4735 , Optional ByVal pvNew As Variant _
4736 , Optional ByVal pvActive As Variant _
4737 , Optional ByVal pvOptional as Variant _
4738 , Optional ByVal pvNumeric As Variant _
4739 , Optional ByVal pvReference As Variant _
4740 , Optional ByVal pvResetSheet As Variant _
4741 ) As Boolean
4742 &apos;&apos;&apos; Sheet designation validation function similar to the SF_Utils._ValidateXXX functions
4743 &apos;&apos;&apos; Args:
4744 &apos;&apos;&apos; pvSheetName: string or numeric position
4745 &apos;&apos;&apos; pvArgName: the name of the variable to be used in the error message
4746 &apos;&apos;&apos; pvNew: if True, sheet must not exist (default = False)
4747 &apos;&apos;&apos; pvActive: if True, the shortcut &quot;~&quot; is accepted (default = False)
4748 &apos;&apos;&apos; pvOptional: if True, a zero-length string is accepted (default = False)
4749 &apos;&apos;&apos; pvNumeric: if True, the sheet position is accepted (default = False)
4750 &apos;&apos;&apos; pvReference: if True, a sheet reference is acceptable (default = False)
4751 &apos;&apos;&apos; pvNumeric and pvReference must not both be = True
4752 &apos;&apos;&apos; pvResetSheet: if True, return in pvSheetName the correct (case-sensitive) sheet name (default = False)
4753 &apos;&apos;&apos; Returns
4754 &apos;&apos;&apos; True if valid. SheetName is reset to current value if = &quot;~&quot;
4755 &apos;&apos;&apos; Exceptions
4756 &apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
4758 Dim vSheets As Variant &apos; List of sheets
4759 Dim lSheet As Long &apos; Index in list of sheets
4760 Dim vTypes As Variant &apos; Array of accepted variable types
4761 Dim bValid As Boolean &apos; Return value
4763 Check:
4764 If IsMissing(pvNew) Or IsEmpty(pvNew) Then pvNew = False
4765 If IsMissing(pvActive) Or IsEmpty(pvActive) Then pvActive = False
4766 If IsMissing(pvOptional) Or IsEmpty(pvOptional) Then pvOptional = False
4767 If IsMissing(pvNumeric) Or IsEmpty(pvNumeric) Then pvNumeric = False
4768 If IsMissing(pvReference) Or IsEmpty(pvReference) Then pvReference = False
4769 If IsMissing(pvResetSheet) Or IsEmpty(pvResetSheet) Then pvResetSheet = False
4771 &apos; Define the acceptable variable types
4772 If pvNumeric Then
4773 vTypes = Array(V_STRING, V_NUMERIC)
4774 ElseIf pvReference Then
4775 vTypes = Array(V_STRING, ScriptForge.V_OBJECT)
4776 Else
4777 vTypes = V_STRING
4778 End If
4779 If Not ScriptForge.SF_Utils._Validate(pvSheetName, psArgName, vTypes, , , Iif(pvReference, CALCREFERENCE, &quot;&quot;)) Then GoTo Finally
4780 bValid = False
4782 Try:
4783 If VarType(pvSheetName) = V_STRING Then
4784 If pvOptional And Len(pvSheetName) = 0 Then
4785 ElseIf pvActive And pvSheetName = &quot;~&quot; Then
4786 pvSheetName = _Component.CurrentController.ActiveSheet.Name
4787 Else
4788 vSheets = _Component.getSheets.getElementNames()
4789 If pvNew Then
4790 &apos; ScriptForge.SF_String.FindRegex(sAddress, &quot;^&apos;[^\[\]*?:\/\\]+&apos;&quot;)
4791 If ScriptForge.SF_Array.Contains(vSheets, pvSheetName) Then GoTo CatchDuplicate
4792 Else
4793 If Not ScriptForge.SF_Utils._Validate(pvSheetName, psArgName, V_STRING, vSheets) Then GoTo Finally
4794 If pvResetSheet Then
4795 lSheet = ScriptForge.SF_Array.IndexOf(vSheets, pvSheetName, CaseSensitive := False)
4796 pvSheetName = vSheets(lSheet)
4797 End If
4798 End If
4799 End If
4800 End If
4801 bValid = True
4803 Finally:
4804 _ValidateSheet = bValid
4805 Exit Function
4806 CatchDuplicate:
4807 ScriptForge.SF_Exception.RaiseFatal(DUPLICATESHEETERROR, psArgName, pvSheetName, &quot;Document&quot;, [_Super]._FileIdent())
4808 GoTo Finally
4809 End Function &apos; SFDocuments.SF_Calc._ValidateSheet
4811 REM -----------------------------------------------------------------------------
4812 Private Function _ValidateSheetName(ByRef psSheetName As String _
4813 , ByVal psArgName As String _
4814 ) As Boolean
4815 &apos;&apos;&apos; Check the validity of the sheet name:
4816 &apos;&apos;&apos; A sheet name - must not be empty
4817 &apos;&apos;&apos; - must not contain next characters: []*?:/\
4818 &apos;&apos;&apos; - must not use &apos; (the apostrophe) as first or last character
4819 &apos;&apos;&apos; Args:
4820 &apos;&apos;&apos; psSheetName: the name to check
4821 &apos;&apos;&apos; psArgName: the name of the argument to appear in error messages
4822 &apos;&apos;&apos; Returns:
4823 &apos;&apos;&apos; True when the sheet name is valid
4824 &apos;&apos;&apos; Exceptions:
4825 &apos;&apos;&apos; CALCADDRESSERROR &apos; Sheet name could not be parsed to a valid name
4827 Dim bValid As Boolean &apos; Return value
4829 Try:
4830 bValid = ( Len(psSheetName) &gt; 0 )
4831 If bValid Then bValid = ( Left(psSheetName, 1) &lt;&gt; &quot;&apos;&quot; And Right(psSheetName, 1) &lt;&gt; &quot;&apos;&quot; )
4832 If bValid Then bValid = ( Len(ScriptForge.SF_String.FindRegex(psSheetName, &quot;^[^\[\]*?:\/\\]+$&quot;, 1, CaseSensitive := False)) &gt; 0 )
4833 If Not bValid Then GoTo CatchSheet
4835 Finally:
4836 _ValidateSheetName = bValid
4837 Exit Function
4838 CatchSheet:
4839 ScriptForge.SF_Exception.RaiseFatal(CALCADDRESSERROR, psArgName, psSheetName _
4840 , &quot;Document&quot;, [_Super]._FileIdent())
4841 GoTo Finally
4842 End Function &apos; SFDocuments.SF_Calc._ValidateSheetName
4844 REM ============================================ END OF SFDOCUMENTS.SF_CALC
4845 </script:module>