lobasic-macros

LibreOffice macros I use often
Log | Files | Refs

commit ec2b843e116b1f28600d2f3f75c2c55447b75ed5
parent eb97a0eb5088fe1192a737243be809285ed40546
Author: Bharatvaj Hemanth <bharatvaj@yahoo.com>
Date:   Sat, 24 Aug 2024 23:33:36 +0530

Completed pending report generation

Completed SBC list generation

Automation 100%

Diffstat:
DStandard/Bharatgas.xba | 411-------------------------------------------------------------------------------
AStandard/CylinderAutomation.xba | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AStandard/HandyTools.xba | 473+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MStandard/script.xlb | 3++-
4 files changed, 742 insertions(+), 412 deletions(-)

diff --git a/Standard/Bharatgas.xba b/Standard/Bharatgas.xba @@ -1,410 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> -<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Bharatgas" script:language="StarBasic">REM ***** BASIC ***** -&apos;Option VBASupport 1 -Option Explicit - -Global Const exportFolder = &quot;C:\Users\bhara\tSync\Pending-01-07-2024&quot; -Global Const rowsToSkip = 1 -Global Const insertNewRowFor = False -Global Const printOnlySummary = False -Global Const roughHeaderMatch = True -Global Const highlightBasedOn = &quot;Payment Option&quot; -Global Const highlightSearchString = &quot;Online Payment&quot; -Global Const highlightRemoveColumn = True -&apos; TODO change suffix based on the report type -Global Const sheetNameSuffix = &quot;- PENDING&quot; -Global Const shouldExportPDF = True -Global Const isPendingReport = True - -Function UsedRangeCursor(Optional ByRef oSheet as Object) as Object - &apos;FIXME Check if the split has already happen - Dim cursor as Object - if IsNull(oSheet) Or IsMissing(oSheet) Then - oSheet = ThisComponent.getCurrentController().getActiveSheet() - End If - cursor = oSheet.createCursor() - cursor.gotoStartOfUsedArea(False) - cursor.gotoEndOfUsedArea(True) - UsedRangeCursor = cursor -End Function - -Function UserFriendlyName(str as String) as String - Dim l as Long - Dim c as String - Dim i as Long - Dim prevChar as String - str = Trim(str) - &apos; Check if Len(str) is really called multiple times - l = Len(str) - For i = 0 To l - c = Mid(str, i + 1, 1) - If i &gt; 1 And (c &gt; &quot;A&quot; And c &lt; &quot;Z&quot;) Then - &apos; Only prepend space if &apos;c&apos; is not the first character... - &apos; or previous char doesn&apos;t have space - UserFriendlyName = UserFriendlyName &amp; IIf(prevChar = &quot; &quot;, &quot;&quot;, &quot; &quot;) &amp; c - Else - UserFriendlyName = UserFriendlyName &amp; c - End If - prevChar = c - Next -End Function - -Sub TestFn() - MsgBox UserFriendlyName(&quot;Area Name&quot;) - MsgBox UserFriendlyName(&quot;AreaName&quot;) - MsgBox UserFriendlyName(&quot; AreaName&quot;) -End Sub - -Sub SortAreaName(Optional oSheet As Variant, Optional cursor as Variant) - Dim oRange as Object - Dim oSortFields(1) as new com.sun.star.util.SortField - Dim oSortDesc(0) as new com.sun.star.beans.PropertyValue - Dim endRow as Integer - Dim endColumn as Integer - - If IsMissing(oSheet) Then - oSheet = ThisComponent.Sheets(0) - cursor = UsedRangeCursor(oSheet) - End If - - endRow = cursor.RangeAddress.EndRow - endColumn = cursor.RangeAddress.EndColumn - - oRange = oSheet.getCellRangeByPosition(0, 1, endColumn, endRow) - ThisComponent.getCurrentController.select(oRange) - - &apos; Area - oSortFields(0).Field = 0 - oSortFields(0).SortAscending = True - - &apos; FIXME This is not working - &apos; Date - oSortFields(1).Field = 4 - oSortFields(1).SortAscending = True - - oSortDesc(0).Name = &quot;SortFields&quot; - oSortDesc(0).Value = oSortFields - - oRange.Sort(oSortDesc) -End Sub - -Sub NewSheet(sheetName as String) - Dim sheets as Object - sheets = ThisComponent.Sheets() - If Not sheets.hasByName(sheetName) Then - sheets.insertNewByName(sheetName, sheets.getCount()) - End If - -End Sub - -Sub CleanColumnHeaders(oSheet as Object, endColumn as Integer) - Dim cell as Object - Dim neatName as String - Dim i as Integer - For i = 0 To endColumn - cell = oSheet.getCellByPosition(i, 0) - neatName = cell.getString() - neatName = UserFriendlyName(neatName) - cell.setString(neatName) - Next -End Sub - -Sub RemoveExtraMergeCells(oSheet as Object, oRangeAddress as Variant) - Dim oRange as Object - Dim oSortFields(0) as new com.sun.star.util.SortField - Dim oSortDesc(0) as new com.sun.star.beans.PropertyValue - Dim endRow as Integer - - endRow = oRangeAddress.EndRow - lastColumn = oRangeAddress.EndColumn - - rem set the range on which to sort&apos; - - &apos;oRange = oSheet.getCellRangeByName(&quot;A2:F20&quot;) - oRange = oSheet.getCellRangeByPosition(0, 0, lastColumn, 0) - ThisComponent.getCurrentController.select(oRange) - initialColumnCount = oRange.Columns.getCount() - 1 - deletedColumns = 0 - For j = 0 To (initialColumnCount - deletedColumns) - oCell = oRange.getCellByPosition(j, 0) - con = oCell.String - If con = &quot;&quot; Then - oRange.Columns.removeByIndex(j, 1) - deletedColumns = deletedColumns - 1 - Else - Print con - End If - Next -End Sub - - -Sub UnFreezeSelection - Dim document as Object - Dim dispatcher as Object - document = ThisComponent.CurrentController.Frame - dispatcher = createUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;) - dispatcher.executeDispatch(document, &quot;.uno:FreezePanes&quot;, &quot;&quot;, 0, Array()) -End Sub - -Function GetHeaderPosition(ByRef oSheet as Object, searchString as String, endColumn as Long) as Integer - Dim iColumn as Integer - Dim oCell as Object - Dim cellString as String - GetHeaderPosition = -1 - If roughHeaderMatch Then - searchString = UserFriendlyName(searchString) - End If - For iColumn = 0 To endColumn - 1 - oCell = oSheet.getCellByPosition(iColumn, 0) - cellString = oCell.String - If roughHeaderMatch Then - cellString = UserFriendlyName(cellString) - End If - If cellString = searchString Then - GetHeaderPosition = iColumn - Exit For - End If - Next iColumn -End Function - -Sub HighlightOnline(ByRef oSheet as Object, endColumn as Long, endRow as Long) - &apos; Fix false positives when having ONLINE and the content has &quot;Online Payment&quot; - Dim currentStr as String - Dim oCell as Object - Dim oCellRange as Object - Dim str as String - Dim iSearchColumn as Long - Dim i as Integer - - &apos; Search for column position that has highlightBasedOn - iSearchColumn = GetHeaderPosition(oSheet, highlightBasedOn, endRow) - If iSearchColumn = -1 Then Exit Sub - For i = 0 To endRow - 1 - oCell = oSheet.getCellByPosition(iSearchColumn, i) - If InStr(oCell.getString(), highlightSearchString) &gt; 0 Then - oCellRange = oSheet.getCellRangeByPosition(0, i, endColumn, i) - oCellRange.CellBackColor = RGB(255, 255, 0) &apos; Yellow - End If - Next i - - If highlightRemoveColumn Then - oSheet.Columns.removeByIndex(iSearchColumn, 1) - End If -End Sub - - -Sub MainNew - Dim oRange as Object - Dim oSheet as Object - Dim oCellStyle as Object - Dim pageStyle as Object - Dim oStyle as Object - oSheet = ThisComponent.Sheets.getByIndex(0) - &apos;oRange = oSheet.getCellRangeByPosition(1, 1, 4, 1) - &apos;oCellStyle = ThisComponent.StyleFamilies.getByName(&quot;CellStyles&quot;).getByName(&quot;InterHeader&quot;) - &apos;oRange.CellStyle = &quot;InterHeader&quot; - pageStyle = ThisComponent.StyleFamilies.getByName(&quot;PageStyles&quot;) - oStyle = pageStyle.getByName(&quot;Default&quot;) - oStyle.CenterVertically = True - pageStyle.insertByName(&quot;NewStyle&quot;) - - if NOT IsNull(pageStyle) then - Print pageStyle.dbg_methods - end if - -End Sub - -Sub Main - Dim s as Object - Dim cursor as Object - Dim c as Integer - Dim destSheet as Variant - Dim sheetName as String - Dim iArea as Long - Dim d as String - Dim a as String - Dim startRow as Long - Dim areaNames as New Collection - Dim dColumns as Object - Dim endRow as Long - Dim endColumn as Long - Dim areaColumn as Object - Dim areaRange, idRange, bookRange - Dim headerRange as Object - Dim cellRangeToCopy as Object - Dim pageStyle as Object - - s = ThisComponent.Sheets(0) - cursor = UsedRangeCursor(s) - - &apos; Skip Header - startRow = rowsToSkip - endRow = cursor.RangeAddress.EndRow - endColumn = cursor.RangeAddress.EndColumn - - &apos; TODO pass the column name/index as an argument - &apos; Transformations to be applied to the Main sheet before splitting the sheet by Area Name - &apos;Call UnFreezeSelection - cursor = UsedRangeCursor(s) - If isPendingReport Then - Call HighlightOnline(s, endColumn, endRow) - End If - Call SortAreaName(s, cursor) - Call CleanColumnHeaders(s, endColumn) - - &apos; Justify Leftmost cells to left and Rightmost cells to right - &apos; TODO Maybe use more descriptive code? Like (&quot;AreaName&quot;)? - idRange = s.getCellRangeByPosition(1,startRow, 1, endRow) - idRange.setPropertyValue(&quot;HoriJustify&quot;, com.sun.star.table.CellHoriJustify.LEFT) - - bookRange = s.getCellRangeByPosition(endColumn, startRow, endColumn, endRow) - bookRange.setPropertyValue(&quot;HoriJustify&quot;, com.sun.star.table.CellHoriJustify.RIGHT) - - areaColumn = s.getCellRangeByPosition(0,startRow, 0, endRow) - headerRange = s.getCellRangeByPosition(0, 0, endColumn, 0) - - headerRange.CellStyle = &quot;Heading 1&quot; - - &apos;On Error Goto ErrorHandler - For iArea = rowsToSkip To endRow - 1 - d = areaColumn.getCellByPosition(0, iArea).String - If d = &quot;&quot; Then - Exit For - End If - - If a &lt;&gt; d Or iArea = (endRow - 1) Then - &apos; FIXME Get the columns automatically from the sheet - &apos; FIXME Covert the end column from endColumn above - - If insertNewRowFor Then - &apos; FIXME This is a stub, not correct - s.Rows.insertByIndex(startRow, 1) - startRow = startRow + 1 - endRow = endRow + 1 - End If - - areaRange = s.getCellRangeByPosition(0, startRow, endColumn, iArea) - If printOnlySummary Then - &apos; TODO maybe there is an elegant way than - &apos; writing this two times - If shouldExportPDF Then - ExportPDF(destSheet) - End If - GoTo Continue - End If - - &apos; TODO subtotals might solve this - &apos;s.group(areaRange.RangeAddress, 1) - - sheetName = a &amp; sheetNameSuffix - - &apos; Copy the Headers from the Main Document - &apos; FIXME This DOES NOT work when using with filtered data - &apos; TODO Get the number of columns to copy dynamically from the Sheet. - cellRangeToCopy = areaRange.RangeAddress - - If (cellRangeToCopy.EndRow - cellRangeToCopy.StartRow) = 0 Then - Goto Continue - End If - - &apos; Prepare Destination sheet - NewSheet(sheetName) - - destSheet = ThisComponent.Sheets().getByName(sheetName) - - pageStyle = ThisComponent.StyleFamilies.getByName(&quot;PageStyles&quot;).getByName(&quot;Default&quot;) - pageStyle.setPropertyValue(&quot;PrintGrid&quot;, True) - pageStyle.setPropertyValue(&quot;CenterHorizontally&quot;, True) - &apos; Make the margins 0.2&quot; thick - pageStyle.setPropertyValue(&quot;LeftMargin&quot;, 0.2 * 2540) - pageStyle.setPropertyValue(&quot;RightMargin&quot;, 0.2 * 2540) - - &apos; Customize the Destination Sheet&apos;s Columns - &apos; TODO Make snuggly calculation. There should be a minimum width and AutoFit - With destSheet.getColumns() - If isPendingReport Then - .getByName(&quot;B&quot;).Width = 2500 - .getByName(&quot;C&quot;).Width = 8000 - .getByName(&quot;D&quot;).Width = 2500 - Else - .getByName(&quot;B&quot;).Width = 1700 - .getByName(&quot;C&quot;).Width = 5000 - .getByName(&quot;D&quot;).Width = 11000 - .getByName(&quot;E&quot;).Width = 2200 - End If - End With - - - &apos; Copy Header - &apos; TODO Check if it&apos;s possible to use UsedRange instead of endColumn - s.copyRange(destSheet.getCellRangeByName(&quot;A1&quot;).CellAddress, _ - headerRange.RangeAddress) - - &apos; Copy all the contents uptil - s.copyRange(destSheet.getCellRangeByName(&quot;A2&quot;).CellAddress, _ - cellRangeToCopy) - - &apos;TODO Remove Columns that should be deleted in leaveColumns - &apos; Better leave it when copying above - destSheet.getColumns().removeByIndex(0, 1) - destSheet.getColumns().removeByIndex(4, 1) - - - &apos;TODO Maybe use Dispatcher? - If shouldExportPDF Then - ExportPDF(destSheet) - End If - Continue: - startRow = (iArea + 1) - a = d - End If - Next iArea - - ErrorHandler: - MsgBox &quot;Error#: &quot; &amp; Erl &amp; Error - &apos;MsgBox &quot;arrCount: &quot; &amp; areaNames.Count - MsgBox &quot;a: &quot; &amp; a &amp; &quot;, d: &quot; &amp; d - Reset -End Sub - -Sub ValidateFileName(fileName as String) - Dim invalidChars as String : invalidChars = &quot;\/:*?&quot;&quot;&lt;&gt;|&quot; - - For i = 1 To Len(fileName) - c = Mid(fileName, i, 1) - If InStr(invalidChars, c) &gt; 0 Then - Print &quot;invalid&quot; &amp; c - End If - Next -End Sub - -Sub ExportPDF(Optional ByVal oSheet as Object) - &apos;Exit Sub - Dim cursor as Object - Dim args(2) as New com.sun.star.beans.PropertyValue - Dim fd(2) as New com.sun.star.beans.PropertyValue - - Dim fileName as String - Dim fileUrl As String - - cursor = UsedRangeCursor(oSheet) - - &apos;ThisComponent.CurrentController.select(cursor) - fileName = exportFolder &amp; &quot;\&quot; &amp; oSheet.Name &amp; &quot;.pdf&quot; - fileUrl = ConvertToUrl(fileName) - - With args(0) : .Name = &quot;FilterName&quot; : .Value = &quot;calc_pdf_Export&quot; : End With - WIth fd(0) : .Name = &quot;Selection&quot; : .Value = cursor : End With - - &apos; conflicts with the Selection - With fd(1) : .Name = &quot;SinglePageSheets&quot; : .Value = False : End With - With fd(2) : .Name = &quot;IsSkipEmptyPages&quot; : .Value = True : End With - - With args(1) : .Name = &quot;FilterData&quot; : .Value = fd : End With - With args(2) : .Name = &quot;Overwrite&quot; : .Value = True : End With - - ThisComponent.storeToURL(fileUrl, args) -End Sub - -</script:module> -\ No newline at end of file diff --git a/Standard/CylinderAutomation.xba b/Standard/CylinderAutomation.xba @@ -0,0 +1,266 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> +<script:module xmlns:script="http://openoffice.org/2000/script" script:name="CylinderAutomation" script:language="StarBasic">REM ***** BASIC ***** +&apos;Option VBASupport 1 +Option Explicit + +Global Const rowsToSkip = 1 +Global Const roughHeaderMatch = True +Global Const highlightBasedOn = &quot;Payment Option&quot; &apos; A yellow background is drawn that matches this column and &apos;highlightSearchString&apos; +Global Const highlightSearchString = &quot;Online&quot; &apos; Does partial match +Global Const highlightRemoveColumn = True &apos; True if you want remove the column once the highlight is done +Global Const reportType = &quot;PENDING&quot; &apos; Allowed values are &quot;PENDING&quot;, &quot;SAFETY&quot; and &quot;SBC&quot;. The number of columns that are copied and the column size will be affected +Global Const shouldExportPDF = True &apos; If True this will export all the created sheets with Area specific data individually TODO change name to easily understand +Global Const badDayThreshold = 4 &apos; The days below &apos;the maximum date in report&apos; to show as bad +Global Const shouldSegregateAreaWise = True&apos; True if you want to create sheets with Area specific data +Global Const exportFolderPrefix = &quot;C:\Users\bhara\Sync\&quot; + +&apos; Values are loaded from the document +Private tillDate as Date +Private tillDateStr as String +Private sheetNameSuffix as String +Private exportFolder as String + +&apos;Private shouldExportSummaryPDF as Boolean&apos; If True the first page will be exported as PDF + +Sub Main + Dim oDoc : oDoc = ThisComponent + Dim s as Object + Dim cursor as Object + Dim c as Integer + Dim destSheet as Variant + Dim sheetName$, d$, a$ + Dim areaColumn%, areaNames as New Collection + Dim startColumn%, startRow%, endColumn%, endRow% + Dim rowsToRemove%, iArea% + Dim areaRange, idRange, bookRange + Dim dColumns as Object + Dim headerRange as Object + Dim cellRangeToCopy as Object + Dim pageStyle as Object + Dim oCellStyles + Dim oConFormat + Dim oCondition(2) as new com.sun.star.beans.PropertyValue + Dim T4Style + + &apos; Initialize Globals + &apos; Casting to Long removes the time component + tillDate = CLng(Now()) + + s = oDoc.Sheets(0) + cursor = UsedRangeCursor(s) + + &apos; NaiveLastTable gives us the last non-blank table&apos;s + rowsToRemove = NaiveLastTable(s) + If rowsToRemove &lt;&gt; 0 Then + s.getRows().removeByIndex(0, rowsToRemove + 1) + End If + + startRow = 1 + startColumn = 0 + endRow = cursor.RangeAddress.EndRow + endColumn = cursor.RangeAddress.EndColumn + + &apos; TODO move this to knowledge base + oCellStyles = ThisComponent.StyleFamilies(&quot;CellStyles&quot;) + If Not oCellStyles.hasByName(&quot;T4&quot;) Then + T4Style = oDoc.createInstance(&quot;com.sun.star.style.CellStyle&quot;) + oCellStyles.insertByName(&quot;T4&quot;, T4Style) + oCellStyles.getByName(&quot;T4&quot;).CellBackColor = RGB(255, 0, 0) + End If + + If ThisComponent.CurrentController.hasFrozenPanes() Then + Call UnFreezeSelection + End If + + &apos; TODO pass the column name/index as an argument + &apos; Transformations to be applied to the Main sheet before splitting the sheet by Area Name + cursor = UsedRangeCursor(s) + + Call CleanColumnHeaders(s, endColumn) + + areaColumn = GetHeaderPosition(s, endColumn, &quot;Area&quot;) + Call ShortenDirections(s, areaColumn) + + If Left(reportType, 1) = &quot;P&quot; Then + Call ApplyTheme &quot;millennium.ots&quot; + endColumn = RemoveColumnsExcept(s, endColumn, Array( _ + &quot;Area&quot;, _ + &quot;ID&quot;, _ + &quot;Name&quot;, _ + &quot;Mobile&quot;, _ + &quot;Book&quot;, _ + &quot;Payment Option&quot; _ + )) + + endColumn = HighlightRowWithColumn(s, endColumn, endRow, _ + &quot;Payment Option&quot;, &quot;Online Payment&quot;, True, _ + RGB(255, 255, 0)) + + &apos; Justify Leftmost cells to left and Rightmost cells to right + + bookRange = GetColumnRange(s, endColumn, endRow, &quot;Book&quot;) + bookRange.setPropertyValue(&quot;HoriJustify&quot;, com.sun.star.table.CellHoriJustify.RIGHT) + + FormatRangeAsNumber(s, new com.sun.star.lang.Locale, oDoc.getNumberFormats(), bookRange, &quot;DD/MM&quot;) + + tillDate = FindHighestDateAsString(s, &quot;Book&quot;, endColumn, endRow) + + With oCondition(0) : .Name = &quot;Operator&quot; : .Value = com.sun.star.sheet.ConditionOperator.LESS_EQUAL : End With + oCondition(1).Name = &quot;Formula1&quot; : oCondition(1).Value = CLng(tillDate - badDayThreshold) + With oCondition(2) : .Name = &quot;StyleName&quot; : .Value = &quot;T4&quot; : End With + oConFormat = bookRange.ConditionalFormat + oConFormat.clear() : oConFormat.addNew(oCondition) + + SetWidths(s, endColumn, Array( _ + Array(&quot;Area&quot;, 0), _ + Array(&quot;ID&quot;, 0), _ + Array(&quot;Name&quot;, 7000), _ + Array(&quot;Mobile&quot;, 0), _ + Array(&quot;Book&quot;, 0) _ + )) + ElseIf reportType = &quot;SBC&quot; Then + Call ApplyTheme &quot;pumpkin.ots&quot; + endColumn = RemoveColumnsExcept(s, endColumn, Array( _ + &quot;ID&quot;, _ + &quot;Name&quot;, _ + &quot;Address&quot;, _ + &quot;Mobile&quot;, _ + &quot;Area&quot;, _ + &quot;No Of Cylinder&quot; _ + )) + SetWidths(s, endColumn, Array( _ + Array(&quot;ID&quot;, 0), _ + Array(&quot;Name&quot;, 3000), _ + Array(&quot;Address&quot;, 8000), _ + Array(&quot;Mobile&quot;, 0), _ + Array(&quot;Area&quot;, 0) _ + )) + End If + + idRange = GetColumnRange(s , endColumn, endRow, &quot;ID&quot;) _ + .setPropertyValue(&quot;HoriJustify&quot;, com.sun.star.table.CellHoriJustify.LEFT) + + Call SortColumn(s, endColumn, endRow, &quot;Area&quot;) + + &apos; Setup exportFolder and sheetName + tillDateStr = Replace(CDate(tillDate), &quot;/&quot;, &quot;-&quot;) + tillDateStr = Trim(tillDateStr) + sheetNameSuffix = &quot; - &quot; &amp; reportType &amp; &quot; &quot; &amp; tillDateStr + exportFolder = exportFolderPrefix &amp; &quot;/&quot; &amp; reportType &amp; &quot; &quot; &amp; tillDateStr + + headerRange = s.getCellRangeByPosition(0, 0, endColumn, 0) + headerRange.CellStyle = &quot;Heading 1&quot; + + pageStyle = ThisComponent.StyleFamilies.getByName(&quot;PageStyles&quot;).getByName(&quot;Default&quot;) + pageStyle.setPropertyValue(&quot;PrintGrid&quot;, True) + pageStyle.setPropertyValue(&quot;CenterHorizontally&quot;, True) + &apos; Make the margins 0.2&quot; thick + + pageStyle.setPropertyValue(&quot;LeftMargin&quot;, 0.2 * 2540) + pageStyle.setPropertyValue(&quot;RightMargin&quot;, 0.2 * 2540) + + &apos; Change original sheet name + s.Name = &quot;SUMMARY&quot; &amp; sheetNameSuffix + + &apos; Export summary + If shouldExportPDF Then + ExportPDF(s, exportFolder) + End If + + If NOT shouldSegregateAreaWise Then Exit Sub + + Dim statusBar + statusBar = oDoc.CurrentController.StatusIndicator + statusBar.start(&quot;Creating Area Wise&quot;, 10) + + areaRange = s.getCellRangeByPosition(areaColumn, startRow, areaColumn, endRow) + a = areaRange.getCellByPosition(0, startRow).getString() + &apos;On Error Goto ErrorHandler + For iArea = startRow To endRow - 1 + d = areaRange.getCellByPosition(0, iArea).getString() + If d = &quot;&quot; Then + Exit For + End If + + If a &lt;&gt; d Or iArea = (endRow - 1) Then + statusBar.setValue((iArea / endRow) * 100) + &apos; FIXME Get the columns automatically from the sheet + &apos; FIXME Covert the end column from endColumn above + + Goto Con: + Dim cName + s.Rows.insertByIndex(startRow, 1) + cName = s.getCellByPosition(startColumn, startRow) + cName.setString(d) + startRow = startRow + 1 + endRow = endRow + 1 + + Con: + &apos; TODO maybe there is an elegant way than + &apos; writing this two times + sheetName = a &amp; sheetNameSuffix + + &apos; TODO subtotals might solve this + &apos;s.group(areaRange.RangeAddress, 1) + + &apos; Prepare Destination sheet + destSheet = NewSheet(sheetName) + + + &apos; Copy the Headers from the Main Document + If areaColumn &gt; 0 And areaColumn &lt; endColumn Then + MsgBox &quot;Can&apos;t have Area column in the middle&quot;, 16 + Exit Sub + End If + + &apos; start end + &apos;1 : endColumn 0 4 + &apos;areaColumn + 1 : endColumn 2 4 + &apos;0 : endColumn - 1 4 4 + + &apos; Copy Header + s.copyRange(destSheet.getCellRangeByName(&quot;A1&quot;).CellAddress, _ + s.getCellRangeByPosition( _ + (endColumn - areaColumn)/ endColumn, _ + 0, endcolumn - CInt(areaColumn/endColumn), 0).RangeAddress) + + &apos; Copy Contents + s.copyRange(destSheet.getCellRangeByName(&quot;A2&quot;).CellAddress, _ + s.getCellRangeByPosition(_ + (endColumn - areaColumn)/ endColumn, _ + startRow, _ + endcolumn - CInt(areaColumn/endColumn), _ + iArea).RangeAddress) + + &apos; Customize the Destination Sheet&apos;s Columns + If Left(reportType, 1) = &quot;P&quot; Then + SetWidths(destSheet, endColumn, Array( _ + Array(&quot;ID&quot;, 0), _ + Array(&quot;Name&quot;, 7000), _ + Array(&quot;Mobile&quot;, 0), _ + Array(&quot;Book&quot;, 0) _ + )) + ElseIf reportType = &quot;SBC&quot; Then + SetWidths(destSheet, endColumn, Array( _ + Array(&quot;ID&quot;, 0), _ + Array(&quot;Name&quot;, 4000), _ + Array(&quot;Address&quot;, 11000), _ + Array(&quot;Mobile&quot;, 0) _ + )) + End If + + If shouldExportPDF Then + ExportPDF(destSheet, exportFolder) + End If + Continue: + startRow = (iArea + 1) + a = d + End If + Next iArea + + ErrorHandler: + statusBar.end() + Reset +End Sub +</script:module> +\ No newline at end of file diff --git a/Standard/HandyTools.xba b/Standard/HandyTools.xba @@ -0,0 +1,472 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd"> +<script:module xmlns:script="http://openoffice.org/2000/script" script:name="HandyTools" script:language="StarBasic" script:moduleType="normal">REM ***** BASIC ***** +Option Explicit + +Function GetFriendlyWords() as Variant + GetFriendlyWords = Array( _ + &quot;AreaCodeDesc&quot;, &quot;Area&quot;, _ + &quot;AreaDescription&quot;, &quot;Area&quot;, _ + &quot;ConsumerNumber&quot;, &quot;ID&quot;, _ + &quot;ConsumerName&quot;, &quot;Name&quot;, _ + &quot;MobileNumber&quot;, &quot;Mobile&quot;, _ + &quot;BookDate&quot;, &quot;Book&quot;_ + ) + If (UBound(GetFriendlyWords) Mod 2) &lt;&gt; 1 Then + Print &quot;Mismatch in friendlyWords array&quot; + Exit Function + End If +End Function + +Sub FormatRangeAsNumber(oSheet, oLocale, ByRef oFormats, oRange, formatStr as String) + &apos; BASIC equivalent of &apos;Text to Columns&apos; + Dim formatNum as Long, i as Integer + Dim oReplace + oReplace = oRange.createReplaceDescriptor() + + If oRange.getCellByPosition(0,0).getValue() = 0 Then + formatNum = oFormats.queryKey(formatStr, oLocale, False) + &apos; add formatStr if it doesn&apos;t exist + If formatNum = -1 Then + formatNum = oFormats.addNew(formatStr, oLocale) + If formatNum = -1 Then + MsgBox &quot;Cannot add &quot; &amp; formatStr &amp; &quot; as NumberFormat&quot;, 0, &quot;Fatal&quot; + Exit Sub + End If + End If + + With oReplace + .searchString = &quot;.+&quot; + .replaceString = &quot;&amp;&quot; + .SearchRegularExpression = True + End With + + oRange.NumberFormat = formatNum + oRange.replaceAll(oReplace) + End If +End Sub + +Function GetColumnRange(oSheet, endColumn as Long, endRow as Long, searchString as String) as Object + Dim iHeaderPos + &apos;GetColumn = -1 + iHeaderPos = GetHeaderPosition(oSheet, endColumn, searchString) + If iHeaderPos = -1 Then + Exit Function + End If + GetColumnRange = oSheet.getCellRangeByPosition(iHeaderPos, 1, iHeaderPos, endRow) +End Function + +Function RemoveColumns(oSheet, endColumn as Integer, columnNames) as Long + Dim columnName as String + Dim iHeader as Integer + RemoveColumns = endColumn + For Each columnName in columnNames + iHeader = GetHeaderPosition(oSheet, endColumn, columnName) + If iHeader &lt;&gt; -1 Then + oSheet.getColumns().removeByIndex(iHeader, 1) + endColumn = endColumn - 1 + End If + Next + RemoveColumns = endColumn +End Function + +Function RemoveColumnsExcept(oSheet as Object, endColumn as Integer, columnNames as Variant) as Long + Dim headerStr as String, columnName as String + Dim i% : i = 0 + Dim rI% : rI = 0 + Dim columnsToRemove(endColumn) as String + Dim headerRange, headerData + Dim found as Boolean : found = False + RemoveColumnsExcept = endColumn + + headerRange = oSheet.getCellRangeByPosition(0, 0, endColumn, 0) + headerData = headerRange.getFormulaArray() + + &apos; TODO Handle condition when columnNames does not have valid header + &apos; This causes an extra string element in the array + For i = 0 To UBound(headerData(0)) + headerStr = headerData(0)(i) + found = False + For Each columnName in columnNames + If headerStr = columnName Then + found = True + Exit For + End If + Next columnName + If Not found Then + columnsToRemove(rI) = headerStr + rI = rI + 1 + End If + Next i + + If i = 0 Then + Exit Function + End If + + ReDim Preserve columnsToRemove(rI - 1) + + RemoveColumnsExcept = RemoveColumns(oSheet, endColumn, columnsToRemove) +End Function + +Sub ApplyTheme(sFileName As String) + Dim oFamilies + Dim aOptions(0) as New com.sun.star.beans.PropertyValue + Dim stylesDir() + Dim StylePath as String + GlobalScope.BasicLibraries.loadLibrary(&quot;Tools&quot;) + oFamilies = ThisComponent.StyleFamilies + StylesDir = GetOfficeSubPath(&quot;Template&quot;, &quot;wizard/styles/&quot;) + StylePath = StylesDir &amp; sFileName + aOptions(0).Name = &quot;OverwriteStyles&quot; + aOptions(0).Value = true + oFamilies.loadStylesFromURL(StylePath, aOptions()) +End Sub + +Function NaiveLastTable(oSheet) as Long + &apos; Return the row position last table that is separated by an empty row + Dim oRows + Dim iRow as Long + Dim usedRange + NaiveLastTable = 0 + + oRows = UsedRangeCursor(oSheet).Rows + + For iRow = 0 To oRows.getCount() - 1 + &apos;Print rows(i).dbg_methods() + If oRows.getByIndex(iRow).computeFunction(com.sun.star.sheet.GeneralFunction.COUNT) = 0 Then + NaiveLastTable = iRow + End If + Next +End Function + +Function IsValidFileName(fileName as String) as Boolean + Dim invalidChars as String : invalidChars = &quot;\/:*?&quot;&quot;&lt;&gt;|&quot; + Dim c as String + Dim i as Integer + IsValidFileName = False + For i = 1 To Len(fileName) + c = Mid(fileName, i, 1) + If InStr(invalidChars, c) &gt; 0 Then + Print &quot;Invalid character &apos;&quot; &amp; c &amp; &quot;&apos; found in &apos;&quot; &amp; fileName &amp; &quot;&apos;&quot; + Exit Function + End If + Next + IsValidFileName = True +End Function + +Sub ExportPDF(oSheet, exportFolder as String) + Dim cursor as Object + Dim args(2) as New com.sun.star.beans.PropertyValue + Dim fd(2) as New com.sun.star.beans.PropertyValue + Dim fileName as String + + If Not IsValidFileName(oSheet.Name) Then + Exit Sub + End If + + fileName = exportFolder &amp; &quot;/&quot; &amp; oSheet.Name &amp; &quot;.pdf&quot; + + WIth fd(0) : .Name = &quot;Selection&quot; : .Value = UsedRangeCursor(oSheet) : End With + &apos; Disabled, because it conflicts with selection + With fd(1) : .Name = &quot;SinglePageSheets&quot; : .Value = False : End With + With fd(2) : .Name = &quot;IsSkipEmptyPages&quot; : .Value = True : End With + + With args(0) : .Name = &quot;FilterName&quot; : .Value = &quot;calc_pdf_Export&quot; : End With + With args(1) : .Name = &quot;FilterData&quot; : .Value = fd : End With + With args(2) : .Name = &quot;Overwrite&quot; : .Value = True : End With + + ThisComponent.storeToURL(ConvertToUrl(fileName), args) +End Sub + + +Sub ListOfActiveCustomers() + Dim oSheet, destSheet, cursor, oRange + Dim startRow as Long + Dim endRow as Long + Dim startColumn as Long + Dim endColumn as Long + Dim requiredFields() + Dim requiredFieldIndices() as Integer + Dim iColumn as Integer, iRequiredField as Integer + Dim headerCellStr as String + + oSheet = ThisComponent.Sheets(0) + cursor = UsedRangeCursor(oSheet) + + &apos; Skip Header + startRow = NaiveLastTable(ThisComponent, cursor) + endRow = cursor.RangeAddress.EndRow + endColumn = cursor.RangeAddress.EndColumn + &apos; TODO Use data from PhoneNumber if some MobileNumber is missing + requiredFields = Array(&quot;ConsumerNumber&quot;, &quot;ConsumerName&quot;, &quot;MobileNumber&quot;, &quot;AreaCodeDesc&quot;, &quot;LastDelivDate&quot;) + &apos;oSheet.Rows.removeByIndex(0, 3) + + For iColumn = startColumn To endColumn + headerCellStr = oSheet.getCellByPosition(iColumn, startRow, iColumn, startRow).getString() + For iRequiredField = 0 To UBound(requiredFields) + If headerCellStr = requiredFields(iRequiredField) Then + &apos; TODO Allocate memory before hand and use a tracker index? + ReDim Preserve requiredFieldIndices(UBound(requiredFieldIndices) + 1) + requiredFieldIndices(UBound(requiredFieldIndices)) = iColumn + End If + Next iRequiredField + Next iColumn + destSheet = NewSheet(&quot;SBC Connection&quot;) + + Print Join(requiredFieldIndices) + + &apos; TODO Ignore the Header Table if it exists + &apos; i.e. If two tables exists, assume the first one to be header table + &apos; and ignore it while copying to new sheet + + &apos; Copy the cells in &apos;requiredFieldIndices&apos; to &apos;destSheet&apos; +End Sub + + +Function UsedRangeCursor(Optional ByRef oSheet as Object) as Object + Dim cursor as Object + if IsNull(oSheet) Or IsMissing(oSheet) Then + oSheet = ThisComponent.getCurrentController().getActiveSheet() + End If + cursor = oSheet.createCursor() + cursor.gotoStartOfUsedArea(False) + cursor.gotoEndOfUsedArea(True) + UsedRangeCursor = cursor +End Function + +Function UserFriendlyName(str as String) as String + &apos; Checks headerName and headerNameMatches for the string &apos;str&apos;, + &apos; If it&apos;s not available there, a naïve implementation adds spacing to &apos;str&apos; + Dim l as Long + Dim c as String + Dim i as Long + Dim prevChar as String + Dim friendlyWords : friendlyWords = GetFriendlyWords() + str = Trim(str) + &apos; Check if Len(str) is really called multiple times + l = Len(str) + &apos; Check with header &quot;database&quot; + + For i = 0 To UBound(friendlyWords) Step 2 + If friendlyWords(i) = str Then + UserFriendlyName = friendlyWords(i + 1) + Exit Function + End If + Next i + + For i = 0 To l + c = Mid(str, i + 1, 1) + If i &gt; 1 And (c &gt; &quot;A&quot; And c &lt; &quot;Z&quot;) Then + &apos; Only prepend space if &apos;c&apos; is not the first character... + &apos; or previous char doesn&apos;t have space + UserFriendlyName = UserFriendlyName &amp; IIf(prevChar = &quot; &quot;, &quot;&quot;, &quot; &quot;) &amp; c + Else + UserFriendlyName = UserFriendlyName &amp; c + End If + prevChar = c + Next +End Function + +Sub SortColumn(oSheet As Variant, endColumn as Integer, endRow as Integer, columnName as String) + Dim oRange as Object + Dim iHeaderPos as Integer + Dim oSortFields(1) as new com.sun.star.util.SortField + Dim oSortDesc(0) as new com.sun.star.beans.PropertyValue + + oRange = oSheet.getCellRangeByPosition(0, 1, endColumn, endRow) + ThisComponent.getCurrentController.select(oRange) + + iHeaderPos = GetHeaderPosition(oSheet, endColumn, columnName) + If iHeaderPos = -1 Then + Exit Sub + End If + &apos; Area + oSortFields(0).Field = iHeaderPos + oSortFields(0).SortAscending = True + + &apos; TODO Enable this later + &apos; Date + &apos;oSortFields(1).Field = 4 + &apos;oSortFields(1).SortAscending = True + + oSortDesc(0).Name = &quot;SortFields&quot; + oSortDesc(0).Value = oSortFields + + oRange.Sort(oSortDesc) +End Sub + +Function NewSheet(sheetName as String) as Object + Dim sheets as Object + sheets = ThisComponent.Sheets() + If Not sheets.hasByName(sheetName) Then + sheets.insertNewByName(sheetName, sheets.getCount()) + End If + NewSheet = sheets.getByName(sheetName) +End Function + +Sub CleanColumnHeaders(oSheet as Object, endColumn as Integer) + Dim cell as Object + Dim neatName as String + Dim i as Integer + For i = 0 To endColumn + cell = oSheet.getCellByPosition(i, 0) + neatName = cell.getString() + neatName = UserFriendlyName(neatName) + cell.setString(neatName) + Next +End Sub + +Sub RemoveExtraMergeCells(oSheet as Object, oRangeAddress as Variant) + Dim oRange as Object + Dim oSortFields(0) as new com.sun.star.util.SortField + Dim oSortDesc(0) as new com.sun.star.beans.PropertyValue + Dim endRow as Integer + + endRow = oRangeAddress.EndRow + lastColumn = oRangeAddress.EndColumn + + rem set the range on which to sort&apos; + + &apos;oRange = oSheet.getCellRangeByName(&quot;A2:F20&quot;) + oRange = oSheet.getCellRangeByPosition(0, 0, lastColumn, 0) + ThisComponent.getCurrentController.select(oRange) + initialColumnCount = oRange.Columns.getCount() - 1 + deletedColumns = 0 + For j = 0 To (initialColumnCount - deletedColumns) + oCell = oRange.getCellByPosition(j, 0) + con = oCell.String + If con = &quot;&quot; Then + oRange.Columns.removeByIndex(j, 1) + deletedColumns = deletedColumns - 1 + Else + Print con + End If + Next +End Sub + + +Sub UnFreezeSelection + Dim document as Object + Dim dispatcher as Object + document = ThisComponent.CurrentController.Frame + dispatcher = createUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;) + dispatcher.executeDispatch(document, &quot;.uno:FreezePanes&quot;, &quot;&quot;, 0, Array()) +End Sub + +Function GetHeaderPosition(ByRef oSheet as Object, endColumn as Integer, searchString as String) as Integer + Dim iColumn as Integer + Dim oCell as Object + Dim cellString as String + GetHeaderPosition = -1 + If searchString = &quot;&quot; Then + Exit Function + End If + If roughHeaderMatch Then + searchString = UserFriendlyName(searchString) + End If + For iColumn = 0 To endColumn + oCell = oSheet.getCellByPosition(iColumn, 0) + cellString = oCell.String + If cellString = &quot;&quot; Then + &apos;MsgBox &quot;Cannot have empty column, endColumn is &quot; &amp; CStr(endColumn), 16, &quot;Bad argument&quot; + Exit Function + End If + If roughHeaderMatch Then + cellString = UserFriendlyName(cellString) + End If + If cellString = searchString OR Instr(cellString, searchString) = 1 Then + GetHeaderPosition = iColumn + Exit For + End If + Next iColumn +End Function + +Function HighlightRowWithColumn(ByRef oSheet as Object, endColumn as Long, endRow as Long, highlightColumnName, highlightValue, removeColumn as Boolean, Optional highlightColor as Long) as Long + Dim currentStr as String + Dim oCell as Object + Dim oCellRange as Object + Dim str as String + Dim iSearchColumn as Long + Dim i as Integer + HighlightRowWithColumn = endColumn + + + &apos; Search for column position that has highlightBasedOn + iSearchColumn = GetHeaderPosition(oSheet, endColumn, highlightColumnName) + If iSearchColumn = -1 Then Exit Function + For i = 0 To endRow - 1 + oCell = oSheet.getCellByPosition(iSearchColumn, i) + If InStr(oCell.getString(), highlightValue) &gt; 0 Then + oCellRange = oSheet.getCellRangeByPosition(0, i, endColumn, i) + oCellRange.CellBackColor = highlightColor + End If + Next i + + If removeColumn Then + oSheet.Columns.removeByIndex(iSearchColumn, 1) + endColumn = endColumn - 1 + End If +End Function + +Function FindHighestDateAsString(oSheet as Object, columnName as String, endColumn as Integer, endRow as Integer) as Date + Dim dateHeaderPos + Dim dateColumn + Dim dateVal + dateHeaderPos = GetHeaderPosition(oSheet, endColumn, columnName) + If dateHeaderPos = -1 Then + MsgBox &quot;Cannot find a column header that starts with &apos;&quot; &amp; columnName &amp; &quot;&apos;&quot;, 0, &quot;Bad column name&quot; + Exit Function + End If + &apos; TODO Check if the column we are searching, actually has date values. + dateColumn = oSheet.getCellRangeByPosition(dateHeaderPos, 1, dateHeaderPos, endRow) + dateVal = dateColumn.computeFunction(com.sun.star.sheet.GeneralFunction.MAX) + If dateVal = 0 Then MsgBox &quot;Invalid date found in column &apos;&quot; &amp; columnName &amp; &quot;&apos; - &quot; &amp; dateHeaderPos &amp; &quot;&quot;, 16, &quot;Bad date found&quot; + FindHighestDateAsString = dateVal +End Function + +&apos; TODO Use a general function that takes arrays +&apos; and instead of the function ShortenDirections, use +&apos; ReplaceArrays to make it more usable across other projects. +Sub ShortenDirections(oSheet as Object, columnIdx as Integer) + &apos;Shorten East as E. etc + Dim toReplace() as String + Dim toReplaceWith() as String + Dim i as Long + Dim oDescriptor + Dim oColumn + Dim columnToReplace + oColumn = oSheet.getColumns().getByIndex(columnIdx) + &apos; TODO arrange it with convention + toReplace() = Array(&quot;East&quot;, &quot;West&quot;, &quot;South&quot;, &quot;North&quot;) + toReplaceWith() = Array(&quot;E.&quot;, &quot;W.&quot;, &quot;S.&quot;, &quot;N.&quot;) + oDescriptor = oColumn.createReplaceDescriptor() + For i = LBound(toReplace) To UBound(toReplace) + With oDescriptor + .SearchString = toReplace(i) + .ReplaceString = toReplaceWIth(i) + End With + oColumn.replaceAll(oDescriptor) + Next i +End Sub + +Sub SetWidths(oSheet, endColumn as Integer, columnWidthArray() as Variant) + &apos; columnWidthArray has values like Array(Array(&quot;Area&quot;, 0), Array(&quot;ID&quot;, 2000)) + &apos; 0 means autofill + Dim i as Integer + Dim columnWidth + Dim iHeaderColumn + For Each columnWidth in columnWidthArray + iHeaderColumn = GetHeaderPosition(oSheet, endColumn, columnWidth(0)) + If iHeaderColumn = -1 Then + Print &quot;Cannot find: &quot; &amp; columnWidth(0) &amp; &quot; in headers&quot; + Exit Sub + End If + if columnWidth(1) = 0 Then + oSheet.getColumns().getByIndex(iHeaderColumn).OptimalWidth = True + Else + oSheet.getColumns().getByIndex(iHeaderColumn).Width = columnWidth(1) + End If + Next +End Sub + +</script:module> +\ No newline at end of file diff --git a/Standard/script.xlb b/Standard/script.xlb @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd"> <library:library xmlns:library="http://openoffice.org/2000/library" library:name="Standard" library:readonly="false" library:passwordprotected="false"> - <library:element library:name="Bharatgas"/> + <library:element library:name="HandyTools"/> + <library:element library:name="CylinderAutomation"/> </library:library> \ No newline at end of file