I need two, simple LibreOffice macros that I am then going to run in sequential order. These macros are the following: 1. A macro that sets the 11 column widths of all 20 of my sheets to: (inches) 10.5, 4.5, 10.5, 2.25, 2.25, 8.75, 2.25, 2.25, 2.25, 8.75, 12 2. Sorts each of the columns named below by "ascending", and in the same order that they are listed, and does this for each of the twenty total sheets: 1: "doc[].string_full_row" 2: "doc[].string_page_num" 3: "json_filename" 4: "doc[].string_raw" 3. The 3rd macro then needs to order all 20 of the sheet columns in the following sequential order by column names (left to right starting at index 0 and ordered by the column names): doc[].string_group_n doc[].string_group_type doc[].string_raw doc[].string_norm doc[].string_id doc[].string_full_row doc[].string_full_row_id doc[].string_page_num doc[].string_num_pages json_filename doc[].string_source_url 4. Needs to then output all 20 of the table sheets as csv type files into a directory and where it names the csv file base names using the sheet names, and where it outputs the csv files as the same format/settings provided to you in the image "csv_file_output_settings.png" Option Explicit '-------------------------------------------- ' Macro #1 ' Sets first 11 columns (A:K) widths on every sheet ' Widths are given in inches and converted to 1/100 mm (UNO unit). '-------------------------------------------- Sub Set_Column_Widths_All_Sheets() Dim widthsInches(10) As Double widthsInches(0) = 10.5 widthsInches(1) = 4.5 widthsInches(2) = 10.5 widthsInches(3) = 2.25 widthsInches(4) = 2.25 widthsInches(5) = 8.75 widthsInches(6) = 2.25 widthsInches(7) = 2.25 widthsInches(8) = 2.25 widthsInches(9) = 8.75 widthsInches(10) = 12 Dim widths(10) As Long Dim i As Long For i = 0 To 10 ' 1 inch = 25.4 mm = 2540 (1/100 mm) widths(i) = CLng(widthsInches(i) * 2540) Next i Dim oDoc As Object, oSheets As Object, oSheet As Object Dim s As Long, oCols As Object, c As Long oDoc = ThisComponent oSheets = oDoc.Sheets For s = 0 To oSheets.getCount() - 1 oSheet = oSheets.getByIndex(s) oCols = oSheet.getColumns() ' Set A..K (0..10) For c = 0 To 10 oCols.getByIndex(c).Width = widths(c) Next c Next s End Sub '-------------------------------------------- ' Macro #2 ' Sorts each sheet by these headers (ascending) in this order: ' 1) doc[].string_full_row ' 2) doc[].string_page_num ' 3) json_filename ' 4) doc[].string_raw ' ' It sorts the entire used area on each sheet and treats row 1 as header. '-------------------------------------------- Sub Sort_All_Sheets_By_Headers_Ascending() Dim oDoc As Object, oSheets As Object, oSheet As Object Dim s As Long Dim logMsg As String oDoc = ThisComponent oSheets = oDoc.Sheets For s = 0 To oSheets.getCount() - 1 oSheet = oSheets.getByIndex(s) If Not Sort_One_Sheet_By_Headers(oSheet) Then logMsg = logMsg & oSheet.Name & Chr(10) End If Next s If logMsg <> "" Then MsgBox "Sort skipped on these sheets (missing one or more required headers in Row 1):" & Chr(10) & Chr(10) & logMsg, 48, "Sort Report" End If End Sub ' Returns True if sorted, False if skipped (missing headers or empty) Private Function Sort_One_Sheet_By_Headers(oSheet As Object) As Boolean Sort_One_Sheet_By_Headers = False Dim oCursor As Object, addr As Object oCursor = oSheet.createCursor() oCursor.gotoStartOfUsedArea(False) oCursor.gotoEndOfUsedArea(True) addr = oCursor.RangeAddress If addr.EndRow < 1 Then Exit Function ' no data rows (only header or empty) Dim lastCol As Long, lastRow As Long lastCol = addr.EndColumn lastRow = addr.EndRow Dim headers(3) As String headers(0) = "doc[].string_full_row" headers(1) = "doc[].string_page_num" headers(2) = "json_filename" headers(3) = "doc[].string_raw" Dim idx(3) As Long Dim i As Long For i = 0 To 3 idx(i) = Find_Header_Column_Index(oSheet, headers(i), lastCol) If idx(i) < 0 Then Exit Function ' required header not found Next i Dim oRange As Object oRange = oSheet.getCellRangeByPosition(0, 0, lastCol, lastRow) Dim oSortDesc As Variant oSortDesc = oRange.createSortDescriptor(True) SetSortProperty oSortDesc, "SortByRows", True SetSortProperty oSortDesc, "ContainsHeader", True Dim sortFields(3) As New com.sun.star.util.SortField For i = 0 To 3 sortFields(i).Field = idx(i) sortFields(i).SortAscending = True sortFields(i).FieldType = com.sun.star.util.SortFieldType.COLUMN Next i SetSortProperty oSortDesc, "SortFields", sortFields() oRange.Sort(oSortDesc) Sort_One_Sheet_By_Headers = True End Function ' Looks for exact match in Row 1 (row index 0) Private Function Find_Header_Column_Index(oSheet As Object, headerText As String, maxCol As Long) As Long Dim c As Long Dim v As String For c = 0 To maxCol v = Trim(CStr(oSheet.getCellByPosition(c, 0).String)) If v = headerText Then Find_Header_Column_Index = c Exit Function End If Next c Find_Header_Column_Index = -1 End Function ' Helper: set/create a property in a SortDescriptor array Private Sub SetSortProperty(ByRef props As Variant, ByVal propName As String, ByVal propValue As Variant) Dim i As Long For i = LBound(props) To UBound(props) If props(i).Name = propName Then props(i).Value = propValue Exit Sub End If Next i Dim n As Long n = UBound(props) + 1 ReDim Preserve props(n) props(n) = CreateUnoStruct("com.sun.star.beans.PropertyValue") props(n).Name = propName props(n).Value = propValue End Sub Option Explicit '======================== ' 3) Reorder columns by header names (A..K) '======================== Sub Reorder_Columns_All_Sheets_By_Header_Names() Dim desired(10) As String desired(0) = "doc[].string_group_n" desired(1) = "doc[].string_group_type" desired(2) = "doc[].string_raw" desired(3) = "doc[].string_norm" desired(4) = "doc[].string_id" desired(5) = "doc[].string_full_row" desired(6) = "doc[].string_full_row_id" desired(7) = "doc[].string_page_num" desired(8) = "doc[].string_num_pages" desired(9) = "json_filename" desired(10) = "doc[].string_source_url" Dim oDoc As Object, oSheets As Object, oSheet As Object Dim s As Long, maxSheets As Long Dim skipped As String oDoc = ThisComponent oSheets = oDoc.Sheets maxSheets = oSheets.getCount() If maxSheets > 20 Then maxSheets = 20 For s = 0 To maxSheets - 1 oSheet = oSheets.getByIndex(s) If Not Reorder_One_Sheet_By_Headers(oSheet, desired()) Then skipped = skipped & oSheet.Name & Chr(10) End If Next s If skipped <> "" Then MsgBox "Reorder skipped on these sheets (missing one or more required headers in Row 1):" & Chr(10) & Chr(10) & skipped, 48, "Reorder Report" End If End Sub Private Function Reorder_One_Sheet_By_Headers(oSheet As Object, desired() As String) As Boolean Reorder_One_Sheet_By_Headers = False Dim oCursor As Object, addr As Object oCursor = oSheet.createCursor() oCursor.gotoStartOfUsedArea(False) oCursor.gotoEndOfUsedArea(True) addr = oCursor.RangeAddress Dim lastRow As Long, lastCol As Long lastRow = addr.EndRow lastCol = addr.EndColumn If lastRow < 0 Then Exit Function ' Find current column indices for each desired header (exact match in Row 1) Dim srcIdx(10) As Long Dim i As Long For i = 0 To 10 srcIdx(i) = Find_Header_Column_Index(oSheet, desired(i), lastCol) If srcIdx(i) < 0 Then Exit Function Next i ' Choose a temp area safely to the right Dim tempStart As Long tempStart = lastCol + 2 ' Copy each desired column to temp columns in desired order For i = 0 To 10 CopyColumnRange oSheet, srcIdx(i), tempStart + i, lastRow Next i ' Copy temp columns back into A..K For i = 0 To 10 CopyColumnRange oSheet, tempStart + i, i, lastRow Next i ' Clear temp columns (so we don't leave duplicates) Dim tempRange As Object tempRange = oSheet.getCellRangeByPosition(tempStart, 0, tempStart + 10, lastRow) tempRange.clearContents(1023) ' everything Reorder_One_Sheet_By_Headers = True End Function ' Copies a full column range (row 0..lastRow) from srcCol to dstCol. ' Uses copyRange to preserve formulas + formatting when present. Private Sub CopyColumnRange(oSheet As Object, srcCol As Long, dstCol As Long, lastRow As Long) Dim srcAddr As New com.sun.star.table.CellRangeAddress srcAddr.Sheet = oSheet.RangeAddress.Sheet srcAddr.StartColumn = srcCol srcAddr.EndColumn = srcCol srcAddr.StartRow = 0 srcAddr.EndRow = lastRow Dim dstCell As New com.sun.star.table.CellAddress dstCell.Sheet = oSheet.RangeAddress.Sheet dstCell.Column = dstCol dstCell.Row = 0 oSheet.copyRange(dstCell, srcAddr) End Sub ' Exact match search in Row 1 (row index 0) Private Function Find_Header_Column_Index(oSheet As Object, headerText As String, maxCol As Long) As Long Dim c As Long, v As String For c = 0 To maxCol v = Trim(CStr(oSheet.getCellByPosition(c, 0).String)) If v = headerText Then Find_Header_Column_Index = c Exit Function End If Next c Find_Header_Column_Index = -1 End Function '======================== ' 4) Export each sheet to CSV with your settings '======================== Sub Export_All_Sheets_To_CSVs_UTF8_Comma_Quoted_AsShown() Dim outDir As String outDir = PickOutputFolder() If outDir = "" Then Exit Sub Dim oDoc As Object, oSheets As Object, oController As Object Dim s As Long, maxSheets As Long Dim sheet As Object, fileURL As String, filePath As String, baseName As String oDoc = ThisComponent oSheets = oDoc.Sheets oController = oDoc.CurrentController maxSheets = oSheets.getCount() If maxSheets > 20 Then maxSheets = 20 ' CSV filter options (per LibreOffice CSV filter tokens): ' 1=44 (comma), 2=34 (double quote), 3=76 (UTF-8), 4=1, 5=1, 6=0, ' 7=false (Quote all text cells OFF), 8=true (numbers stored as numbers), ' 9=true (Save cell contents as shown ON), 10=false (Export formulas OFF) ' Token mapping documented by LibreOffice Help. :contentReference[oaicite:1]{index=1} Dim csvOptions As String csvOptions = "44,34,76,1,1,0,false,true,true,false" Dim props(1) As New com.sun.star.beans.PropertyValue props(0).Name = "FilterName" props(0).Value = "Text - txt - csv (StarCalc)" props(1).Name = "FilterOptions" props(1).Value = csvOptions For s = 0 To maxSheets - 1 sheet = oSheets.getByIndex(s) oController.setActiveSheet(sheet) baseName = SanitizeFileName(sheet.Name) filePath = outDir & "/" & baseName & ".csv" fileURL = ConvertToURL(filePath) oDoc.storeToURL(fileURL, props()) Next s MsgBox "Exported " & maxSheets & " sheet(s) to:" & Chr(10) & outDir, 64, "