wizards/source/scriptforge/SF_Utils.xba          |    2 
 wizards/source/scriptforge/python/scriptforge.py |    6 
 wizards/source/sfdocuments/SF_Calc.xba           |  224 ++++++++++++++++++++++-
 3 files changed, 228 insertions(+), 4 deletions(-)

New commits:
commit 43507de5764732300ae9a35cc570b7722a7e1a80
Author:     Jean-Pierre Ledure <j...@ledure.be>
AuthorDate: Sun Apr 10 17:05:33 2022 +0200
Commit:     Jean-Pierre Ledure <j...@ledure.be>
CommitDate: Sun Apr 10 18:06:05 2022 +0200

    ScriptForge - (SF_Calc) new CompactUp() and CompactLeft() methods
    
    The CompactUp(CompactLeft) method:
    
    Delete the rows(columns) of a specified range matching a filter
    expressed as a formula applied on each row(column).
    The deleted cells can span whole rows(columns)
    or be limited to the width(height) of the range.
    The execution of the method has no effect on the
    current selection.
    
    Args:
      Range: the range in which cells have to be erased, as a string
      WholeRow(WholeColumn): when True (default = False),
        erase whole rows(columns)
      FilterFormula: the formula to be applied on each row(column).
        The row(column) is erased when the formula results in True.
        The formula shall probably involve one or more cells of
        the first row(column) of the range..
        By default, a row is erased when all the cells
        of the row(column) are empty,
        i.e. suppose the range is "A1:J200" (width = 10),
        the default value [for CompactUp] becomes "=(COUNTBLANK(A1:J1)=10)"
    
    Returns:
      A string representing the location of the initial range
      after compaction, or the zero-length string if the whole range
      has been deleted.
    
    Examples for CompactUp():
      newrange = oDoc.CompactUp("SheetX.G1:L10")
          ' All empty rows of the range are suppressed
      newrange = oDoc.CompactUp("SheetX.G1:L10", WholeRow := True, _
          FilterFormula := "=(G1=""X"")")
          ' The rows having a "X" in column G are completely suppressed
    
    Both methods are available for use from Basic and Python scripts.
    
    Change-Id: Ib1269b22bcd189ca86a1bd3bda2c67e895598cb0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132783
    Tested-by: Jean-Pierre Ledure <j...@ledure.be>
    Tested-by: Jenkins
    Reviewed-by: Jean-Pierre Ledure <j...@ledure.be>

diff --git a/wizards/source/scriptforge/SF_Utils.xba 
b/wizards/source/scriptforge/SF_Utils.xba
index 5dbe667a52f0..e26cca66a776 100644
--- a/wizards/source/scriptforge/SF_Utils.xba
+++ b/wizards/source/scriptforge/SF_Utils.xba
@@ -1107,4 +1107,4 @@ Finally:
 End Function   &apos;  ScriptForge.SF_Utils._VarTypeObj
 
 REM ================================================= END OF 
SCRIPTFORGE.SF_UTILS
-</script:module>
+</script:module>
\ No newline at end of file
diff --git a/wizards/source/scriptforge/python/scriptforge.py 
b/wizards/source/scriptforge/python/scriptforge.py
index c1261a14fc40..600d8469e623 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -2086,6 +2086,12 @@ class SFDocuments:
         def ClearValues(self, range):
             return self.ExecMethod(self.vbMethod, 'ClearValues', range)
 
+        def CompactLeft(self, range, wholecolumn = False, filterformula = ''):
+            return self.ExecMethod(self.vbMethod, 'CompactLeft', range, 
wholecolumn, filterformula)
+
+        def CompactUp(self, range, wholerow = False, filterformula = ''):
+            return self.ExecMethod(self.vbMethod, 'CompactUp', range, 
wholerow, filterformula)
+
         def CopySheet(self, sheetname, newname, beforesheet = 32768):
             sheet = (sheetname.objectreference if isinstance(sheetname, 
SFDocuments.SF_CalcReference) else sheetname)
             return self.ExecMethod(self.vbMethod + self.flgObject, 
'CopySheet', sheet, newname, beforesheet)
diff --git a/wizards/source/sfdocuments/SF_Calc.xba 
b/wizards/source/sfdocuments/SF_Calc.xba
index bc5681992eec..33a523874f39 100644
--- a/wizards/source/sfdocuments/SF_Calc.xba
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -90,7 +90,6 @@ Private Const RANGEEXPORTERROR                =       
&quot;RANGEEXPORTERROR&quot;
 REM ============================================================= PRIVATE 
MEMBERS
 
 Private [Me]                                   As Object
-Private [_Parent]                              As Object
 Private [_Super]                               As Object               &apos;  
Document superclass, which the current instance is a subclass of
 Private ObjectType                             As String               &apos;  
Must be CALC
 Private ServiceName                            As String
@@ -137,7 +136,6 @@ REM ====================================================== 
CONSTRUCTOR/DESTRUCTO
 REM 
-----------------------------------------------------------------------------
 Private Sub Class_Initialize()
        Set [Me] = Nothing
-       Set [_Parent] = Nothing
        Set [_Super] = Nothing
        ObjectType = &quot;CALC&quot;
        ServiceName = &quot;SFDocuments.Calc&quot;
@@ -651,6 +649,224 @@ Catch:
        GoTo Finally
 End Sub        &apos;  SF_Documents.SF_Calc.ClearValues
 
+REM 
-----------------------------------------------------------------------------
+Public Function CompactLeft(Optional ByVal Range As Variant _
+                                                               , Optional 
ByVal WholeColumn As Variant _
+                                                               , Optional 
ByVal FilterFormula As Variant _
+                                                               ) As String
+&apos;&apos;&apos;     Delete the columns of a specified range matching a 
filter expressed as a formula
+&apos;&apos;&apos;     applied on each column.
+&apos;&apos;&apos;     The deleted cells can span whole columns or be limited 
to the height of the range
+&apos;&apos;&apos;     The execution of the method has no effect on the 
current selection
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             Range: the range in which cells have to be 
erased, as a string
+&apos;&apos;&apos;             WholeColumn: when True (default = False), erase 
whole columns
+&apos;&apos;&apos;             FilterFormula: the formula to be applied on 
each column.
+&apos;&apos;&apos;                     The column is erased when the formula 
results in True,
+&apos;&apos;&apos;                     The formula shall probably involve one 
or more cells of the first column of the range..
+&apos;&apos;&apos;                     By default, a column is erased when all 
the cells of the column are empty,
+&apos;&apos;&apos;                     i.e. suppose the range is 
&quot;A1:J200&quot; (height = 0) the default value becomes
+&apos;&apos;&apos;                             
&quot;=(COUNTBLANK(A1:A200)=200)&quot;
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             A string representing the location of the 
initial range after compaction,
+&apos;&apos;&apos;             or the zero-length string if the whole range 
has been deleted
+&apos;&apos;&apos;     Examples:
+&apos;&apos;&apos;             newrange = 
oDoc.CompactLeft(&quot;SheetX.G1:L10&quot;)  &apos;  All empty columns of the 
range are suppressed
+&apos;&apos;&apos;             newrange = 
oDoc.CompactLeft(&quot;SheetX.G1:L10&quot;, WholeColumn := True, FilterFormula 
:= &quot;=(G$7=&quot;&quot;X&quot;&quot;)&quot;)
+&apos;&apos;&apos;                     &apos;  The columns having a 
&quot;X&quot; in row 7 are completely suppressed
+
+Dim sCompact As String                 &apos;  Return value
+Dim oSourceAddress As Object   &apos;  Alias of Range as _Address
+Dim lLastRow As Long                   &apos;  Last used row number in the 
sheet containing Range
+Dim sFormulaRange As String            &apos;  Range, as a string, where the 
FilterFormula must be stored
+Dim vCompact As Variant                        &apos;  Array of Boolean values 
indicating which columns should be erased
+Dim lCountDeleted As Long              &apos;  Count the deleted columns
+Dim lCountToDelete As Long             &apos;  Count contiguous columns to be 
deleted at once
+Dim sPartialRange As String            &apos;  Contiguous columns to be deleted
+Dim i As Long
+
+Const cstThisSub = &quot;SFDocuments.Calc.CompactLeft&quot;
+Const cstSubArgs = &quot;Range, [WholeColumn=False], 
[FilterFormula=&quot;&quot;&quot;&quot;]&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       sCompact = &quot;&quot;
+
+Check:
+       If IsMissing(WholeColumn) Or IsEmpty(WholeColumn) Then WholeColumn = 
False
+       If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then 
FilterFormula = &quot;&quot;
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not _IsStillAlive(True) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, 
V_STRING) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(WholeColumn, 
&quot;WholeColumn&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(FilterFormula, 
&quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
+       End If
+
+Try:
+       Set oSourceAddress = _ParseAddress(Range)
+
+       With oSourceAddress
+
+               &apos;  Set the default formula =&gt; all cells are blank
+               If FilterFormula = &quot;&quot; Then FilterFormula = 
Printf(&quot;=(COUNTBLANK(%C1%R1:%C1%R2)-&quot; &amp; .Height &amp; 
&quot;=0)&quot;, Range)
+               &apos;  Compute the range where to apply the formula
+               lLastRow = LastRow(.SheetName)
+               sFormulaRange = Offset(Range, lLastRow - 
.XCellRange.RangeAddress.StartColumn + 1, , 1)
+               SetFormula(sFormulaRange, FilterFormula)
+               &apos;  Get the columns to compact: 0 = False, 1 = True
+               vCompact = GetValue(sFormulaRange)
+               ClearAll(sFormulaRange)
+
+               &apos;  Iterates from the last to the first column of the range 
and remove the columns that match the filter
+               &apos;  by groups of contiguous columns
+               lCountDeleted = 0
+               lCountToDelete = 0
+               For i = UBound(vCompact) To 0 Step -1
+                       If vCompact(i) = 1 Then lCountToDelete = lCountToDelete 
+ 1
+                       If i &gt; 0 And vCompact(i) = 1 Then
+                               &apos;  Do nothing
+                       ElseIf lCountToDelete &gt; 0 Then               &apos;  
The current column must be kept but columns at the left must be removed
+                               &apos;  Do not forget when the 1st column must 
be removed
+                               sPartialRange = Offset(Range, , Iif(i = 0 And 
vCompact(i) = 1, 0, i + 1), , lCountToDelete)
+                               ShiftLeft(sPartialRange, WholeColumn)
+                               lCountDeleted = lCountDeleted + lCountToDelete
+                               lCountToDelete = 0
+                       End If
+               Next i
+
+               &apos;  Compute the final range position
+               If lCountDeleted &lt; .Width Then sCompact = Offset(Range, 0, 
0, , .Width - lCountDeleted)
+
+               &apos;  Push rightwards the cells that migrated leftwards 
irrelevantly
+               If Not WholeColumn Then
+                       If Len(sCompact) &gt; 0 Then
+                               sPartialRange = Offset(sCompact, 0, .Width - 
lCountDeleted, , lCountDeleted)
+                       Else
+                               sPartialRange = .RangeName
+                       End If
+                       ShiftRight(sPartialRange, WholeColumn := False)
+               End If
+
+       End With
+
+Finally:
+       CompactLeft = sCompact
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       &apos;  When error, return the original range
+       If Not IsNull(oSourceAddress) Then sCompact = oSourceAddress.RangeName
+       GoTo Finally
+End Function    &apos;   SFDocuments.SF_Calc.CompactLeft
+
+REM 
-----------------------------------------------------------------------------
+Public Function CompactUp(Optional ByVal Range As Variant _
+                                                               , Optional 
ByVal WholeRow As Variant _
+                                                               , Optional 
ByVal FilterFormula As Variant _
+                                                               ) As String
+&apos;&apos;&apos;     Delete the rows of a specified range matching a filter 
expressed as a formula
+&apos;&apos;&apos;     applied on each row.
+&apos;&apos;&apos;     The deleted cells can span whole rows or be limited to 
the width of the range
+&apos;&apos;&apos;     The execution of the method has no effect on the 
current selection
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             Range: the range in which cells have to be 
erased, as a string
+&apos;&apos;&apos;             WholeRow: when True (default = False), erase 
whole rows
+&apos;&apos;&apos;             FilterFormula: the formula to be applied on 
each row.
+&apos;&apos;&apos;                     The row is erased when the formula 
results in True,
+&apos;&apos;&apos;                     The formula shall probably involve one 
or more cells of the first row of the range..
+&apos;&apos;&apos;                     By default, a row is erased when all 
the cells of the row are empty,
+&apos;&apos;&apos;                     i.e. suppose the range is 
&quot;A1:J200&quot; (width = 10) the default value becomes
+&apos;&apos;&apos;                             
&quot;=(COUNTBLANK(A1:J1)=10)&quot;
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             A string representing the location of the 
initial range after compaction,
+&apos;&apos;&apos;             or the zero-length string if the whole range 
has been deleted
+&apos;&apos;&apos;     Examples:
+&apos;&apos;&apos;             newrange = 
oDoc.CompactUp(&quot;SheetX.G1:L10&quot;)    &apos;  All empty rows of the 
range are suppressed
+&apos;&apos;&apos;             newrange = 
oDoc.CompactUp(&quot;SheetX.G1:L10&quot;, WholeRow := True, FilterFormula := 
&quot;=(G1=&quot;&quot;X&quot;&quot;)&quot;)
+&apos;&apos;&apos;                     &apos;  The rows having a &quot;X&quot; 
in column G are completely suppressed
+
+Dim sCompact As String                 &apos;  Return value
+Dim oSourceAddress As Object   &apos;  Alias of Range as _Address
+Dim lLastCol As Long                   &apos;  Last used column number in the 
sheet containing Range
+Dim sFormulaRange As String            &apos;  Range, as a string, where the 
FilterFormula must be stored
+Dim vCompact As Variant                        &apos;  Array of Boolean values 
indicating which rows should be erased
+Dim lCountDeleted As Long              &apos;  Count the deleted rows
+Dim lCountToDelete As Long             &apos;  Count contiguous rows to be 
deleted at once
+Dim sPartialRange As String            &apos;  Contiguous rows to be deleted
+Dim i As Long
+
+Const cstThisSub = &quot;SFDocuments.Calc.CompactUp&quot;
+Const cstSubArgs = &quot;Range, [WholeRow=False], 
[FilterFormula=&quot;&quot;&quot;&quot;]&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       sCompact = &quot;&quot;
+
+Check:
+       If IsMissing(WholeRow) Or IsEmpty(WholeRow) Then WholeRow = False
+       If IsMissing(FilterFormula) Or IsEmpty(FilterFormula) Then 
FilterFormula = &quot;&quot;
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not _IsStillAlive(True) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, 
V_STRING) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(WholeRow, 
&quot;WholeRow&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(FilterFormula, 
&quot;FilterFormula&quot;, V_STRING) Then GoTo Finally
+       End If
+
+Try:
+       Set oSourceAddress = _ParseAddress(Range)
+
+       With oSourceAddress
+
+               &apos;  Set the default formula =&gt; all cells are blank
+               If FilterFormula = &quot;&quot; Then FilterFormula = 
Printf(&quot;=(COUNTBLANK(%C1%R1:%C2%R1)-&quot; &amp; .Width &amp; 
&quot;=0)&quot;, Range)
+               &apos;  Compute the range where to apply the formula
+               lLastCol = LastColumn(.SheetName)
+               sFormulaRange = Offset(Range, , lLastCol - 
.XCellRange.RangeAddress.StartRow + 1, , 1)
+               SetFormula(sFormulaRange, FilterFormula)
+               &apos;  Get the rows to compact: 0 = False, 1 = True
+               vCompact = GetValue(sFormulaRange)
+               ClearAll(sFormulaRange)
+
+               &apos;  Iterates from the last to the first row of the range 
and remove the rows that match the filter
+               &apos;  by groups of contiguous rows
+               lCountDeleted = 0
+               lCountToDelete = 0
+               For i = UBound(vCompact) To 0 Step -1
+                       If vCompact(i) = 1 Then lCountToDelete = lCountToDelete 
+ 1
+                       If i &gt; 0 And vCompact(i) = 1 Then
+                               &apos;  Do nothing
+                       ElseIf lCountToDelete &gt; 0 Then               &apos;  
The current row must be kept but rows below must be removed
+                               &apos;  Do not forget when the 1st row must be 
removed
+                               sPartialRange = Offset(Range, Iif(i = 0 And 
vCompact(i) = 1, 0, i + 1), , lCountToDelete)
+                               ShiftUp(sPartialRange, WholeRow)
+                               lCountDeleted = lCountDeleted + lCountToDelete
+                               lCountToDelete = 0
+                       End If
+               Next i
+
+               &apos;  Compute the final range position
+               If lCountDeleted &lt; .Height Then sCompact = Offset(Range, 0, 
0, .Height - lCountDeleted)
+
+               &apos;  Push downwards the cells that migrated upwards 
irrelevantly
+               If Not WholeRow Then
+                       If Len(sCompact) &gt; 0 Then
+                               sPartialRange = Offset(sCompact, .Height - 
lCountDeleted, 0, lCountDeleted)
+                       Else
+                               sPartialRange = .RangeName
+                       End If
+                       ShiftDown(sPartialRange, WholeRow := False)
+               End If
+
+       End With
+
+Finally:
+       CompactUp = sCompact
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       &apos;  When error, return the original range
+       If Not IsNull(oSourceAddress) Then sCompact = oSourceAddress.RangeName
+       GoTo Finally
+End Function    &apos;   SFDocuments.SF_Calc.CompactUp
+
 REM 
-----------------------------------------------------------------------------
 Public Function CopySheet(Optional ByVal SheetName As Variant _
                                                                , Optional 
ByVal NewName As Variant _
@@ -1925,7 +2141,7 @@ Public Function Offset(Optional ByRef Range As Variant _
 &apos;&apos;&apos;     Exceptions:
 &apos;&apos;&apos;             OFFSETADDRESSERROR              The computed 
range of cells falls beyond the sheet boundaries
 &apos;&apos;&apos;     Examples:
-&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)
+&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)
 &apos;&apos;&apos;             oDoc.Offset(&quot;A1&quot;, 2, 2, 5, 6) &apos;  
&quot;&apos;SheetX&apos;.$C$3:$H$7&quot;
 
 Dim sOffset As String                          &apos;  Return value
@@ -2727,6 +2943,7 @@ Check:
 
 Try:
        Set oSourceAddress = _ParseAddress(Range)
+       Set _LastParsedAddress = Nothing        &apos;  Range will be erased. 
Force re-parsing next time
 
        With oSourceAddress
 
@@ -2889,6 +3106,7 @@ Check:
 
 Try:
        Set oSourceAddress = _ParseAddress(Range)
+       Set _LastParsedAddress = Nothing        &apos;  Range will be erased. 
Force re-parsing next time
 
        With oSourceAddress
 

Reply via email to