Thursday, February 12, 2009

OpenOffice Macro

I have a tendency to loose these types of things. So posting here instead of some hard drive that fails down track....

This macro goes into the parameters spreadsheet I have setup and iterates through all sheets and generates necessary records to go into new APM database system I'm building.

I use it for storing all database parameters for a system. This becomes very necessary when there are multiple test environments and you want to roll one out very quickly.
I basically would setup one sheet per parameter table and all parameters are contained within that sheet. The column labels relate to the database table column names, and a little flag tells us if the value is char or int type. With > 180 parameter tables, this makes life a breeze!



Global clipText as String

Sub TestIt()
'insertControlRow
'BuildAPMSQL
'generateInsertsForCurrentSheet
'generateInsertForCurrentRow
GenerateTableDeleteSQL
Dim s as string
Dim t as string
s="Hello'"
t=getCharField(s)
msgbox t
End Sub

Function getCharField(fld$)
Dim tmp$
If IsNull(fld$) Or len(fld$)=0 Then
tmp$=""
Else
tmp$=UCase(fld$)
End If
If tmp$ = "" Or tmp$ = "NULL" Or tmp$ = "(NULL)" Then
getCharField = "NULL"
Else
getCharField = "'" & makeDBSafe(fld$, "'", "''") & "'"
End If
End Function

Function getIntField(field)
Dim tmp As String
tmp = UCase(field)
If tmp = "" Or tmp = "NULL" Or tmp = "(NULL)" Then
getIntField = "NULL"
Else
getIntField = field
End If
End Function

Function makeDBSafe(str$)
dim a
Dim c$
Dim tmp$
For a=1 to len(str$)
c$=Mid(str$,a,1)
If c$="'" Then
tmp$=tmp$ & "''"
Else
tmp$=tmp$ & c$
End If
next
makeDBSafe = tmp$
End Function

Function testMe()
testMe="Hello"
End Function


Function testCell(cell)
testCell="Hello" + cell
End Function

Function ConvertBillCodeToCustomerType(fld$)
dim bcc$
bcc$=mid(fld$,3,1)
If bcc$="C" Then
ConvertBillCodeToCustomerType="NOR"
ElseIf bcc$="S" Then
ConvertBillCodeToCustomerType="STF"
Else
ConvertBillCodeToCustomerType="NULL"
End If
End Function

Function ConvertBillCodeToSubproduct(fld$)
dim ct$
ct$=left(fld$,1)
if ct$="S" Then
ct$="C"
End If
ConvertBillCodeToSubproduct="V" + ct$
End Function

function GetSheetName()
GetSheetName = getCurrentSheet().getName()
end function

function getCurrentSheet()
getCurrentSheet = ThisComponent.getCurrentController.getActiveSheet
end function

function getCurrentRow()
oCell = ThisComponent.getCurrentController().getSelection().getCellByPosition(0,0)
rowInt = oCell.getCellAddress.Row
getCurrentRow = getCurrentSheet().getRows.getByIndex(rowInt)
end function

Function makeCurrentPath()
currentPath = ThisComponent.url
i = len(currentPath)
For n = Len( currentPath ) To 1 Step -1
If Mid( currentPath, n, 1 ) = "/" Then Exit For
Next n
makeCurrentPath = left(currentPath, n)
End Function

function BuildXMLTableDefinitions()
'iterate over all sheets
Dim oSheet As Object
Dim eSheets As Object
Dim oRow as Object
Dim oColumn as Object
Dim textFile as Object

StatusText "Building XML tables now"

eSheets = ThisComponent.getSheets.createEnumeration
f1 = FreeFile()
currentPath=makeCurrentPath() & "tablebuilder.xml"
Open currentPath for output as #f1
print #f1, ""

'Skip the _CTL sheet
While eSheets.hasMoreElements
oSheet = eSheets.nextElement()
'Only non control sheets please :)
if left(oSheet.getName,1) <> "_" Then
StatusText "Generating Table " & oSheet.getName
' here you can work your sheet
print #f1, " "
print #f1, " "
for a = 0 to 50
oCell= oSheet.getCellByPosition(a, 1)
txt = oCell.String
if len(txt) > 0 Then
print #f1, " " & txt & ""
Else
Exit For
End If
next
print #f1, "
"
for b = 1 to 500
if len(oSheet.getCellByPosition(0,b).String)=0 Then Exit For
print #f1, " "
for c = 0 to a
oCell= oSheet.getCellByPosition(c, b)
txt = oCell.String
if len(txt) > 0 Then
print #f1, " " & xmlSafe(txt) & ""
Else
Exit For
End If
next
print #f1, "
"
next


print #f1, "
"
End If
Wend
StatusText "Completed..."
print #f1, "
"
close #f1
msgbox "File is created and is at " & currentPath
end function


function xmlSafe(txt) As String
If txt="(null)" Then
xmlSafe = "NULL"
Exit Function
End If

newTxt = ""
for a=1 to len(txt)
char1 = mid(txt, a, 1)
select case char1
case "<" newTxt = newTxt & "<" case "&" newTxt = newTxt & "&" case else newTxt = newTxt & char1 End Select Next xmlSafe = newTxt end function 'Generates all table deletes 'Does it in reverse order to hopefully ensure all data gets deleted Public function GenerateTableDeleteSQL() Dim oSheet As Object Dim eSheets As Object eSheets = ThisComponent.getSheets.createEnumeration lastNumber = 10 Dim textFile as Object f1 = FreeFile() currentPath=makeCurrentPath() & "fulldeletes.sql" Open currentPath for output as #f1 print #f1, "-- Table Deletion for MAPS WOW Parameter Tables" print #f1, "-- Written by James Bushell" print #f1, "-- Automatically generated (insert date here!)" While eSheets.hasMoreElements oSheet = eSheets.nextElement() If left(oSheet.getName,1) <> "_" Then
orderNumber = oSheet.getCellByPosition(2,0).getString
if orderNumber="" Then orderNumber = lastNumber
lastNumber = val(orderNumber) + 1
print #f1, "DELETE FROM " & oSheet.getName & ";"
End If
Wend
close #f1
StatusText "File now available at " & currentPath
Msgbox "File now available at " & currentPath
End function


'Generates ALL SQL for parametermanager
function BuildAPMSQL()
StatusText "Generating Table/Column definitions for APM"
'iterate over all sheets
Dim oSheet As Object
Dim eSheets As Object
Dim oRow as Object
Dim oColumn as Object
eSheets = ThisComponent.getSheets.createEnumeration
Dim textFile as Object
f1 = FreeFile()
currentPath=makeCurrentPath() & "apmsql.sql"
Open currentPath for output as #f1
print #f1, "-- Application Parameter Manager (APM)"
print #f1, "-- Loader File for MAPS WOW"
print #f1, "-- Written by James Bushell"
print #f1, "-- Automatically generated (insert date here!)"

print #f1,""
print #f1,""
print #f1,"TRUNCATE TABLE table_data;"
print #f1,"TRUNCATE TABLE table_columns;"
print #f1,"TRUNCATE TABLE table_list;"
print #f1,""

x = 0
SystemID = 1 ' This is WOWMAPS as from system_names
'Skip the _CTL sheet
While eSheets.hasMoreElements
oSheet = eSheets.nextElement()
'Only non control sheets please :)
columnNameList=""
if left(oSheet.getName,1) <> "_" Then
statusText "Generating table " & oSheet.getName
x = x + 10
tmp = "INSERT INTO table_list (table_id,system_id, table_name, table_order) VALUES(" & x & "," & SystemID & "," & getCharField(oSheet.getName) & ","
cellVal = oSheet.getCellByPosition(2, 0).String
if (cellVal > "") Then
tmp = tmp & cellVal
Else
tmp = tmp & x 'This is the table order. TODO MAKE IT BETTER!!
End If
tmp = tmp & ");"
print #f1, tmp

hdr="INSERT INTO table_columns (table_id,field_type_id,column_name,column_order) VALUES("
ftr = ");"
for a = 0 to 50
oCell= oSheet.getCellByPosition(a, 2)
txt = oCell.String
if len(txt) > 0 Then
if a > 0 Then columnNameList = columnNameList & ","
columnNameList = columnNameList & txt
tmp=hdr
tmp = tmp & x & "," 'table_id generated
'Now get the control char for type of field
'C=char=1 in apm db
'I=Integer=2 in apm db
oCell = oSheet.getCellByPosition(a, 1)
fieldType = oCell.String
if (fieldType="I") Then
tmp = tmp & "2"
Else
tmp = tmp & "1"
End If
tmp = tmp & "," & getCharField(txt) & ","
tmp = tmp & (a+1)
tmp = tmp & ftr
print #f1, tmp
Else
Exit For
End If
next

'Do the data here

End If
Wend
close #f1
StatusText "Completed..."
msgbox "File is created and is at " & currentPath
end function


rem THis is hardly ever run
private function insertControlRow()
'RUn once code
'iterate over all sheets
Dim oSheet As Object
Dim eSheets As Object
Dim oRow as Object
Dim oColumn as Object
Dim oCell as Object
eSheets = ThisComponent.getSheets.createEnumeration
'Skip the _CTL sheet
x=10
While eSheets.hasMoreElements
oSheet = eSheets.nextElement()
'Only non control sheets please :)
columnNameList=""
if left(oSheet.getName,1) <> "_" Then
'Automatically generate the control lines
if left(oSheet.getCellByPosition(0,0).String,14) <> "LEAVE THIS ROW" Then
oSheet.getRows().insertByIndex(0,2)
End If
oCell = oSheet.getCellByPosition(0,0)
oCell.String = "LEAVE THIS ROW AND THE NEXT ONE ALONE!!!"
oCell = oSheet.getCellByPosition(1,0)
oCell.String = "ORDER"
oCell.CellBackColor = 10040064
oCell = oSheet.getCellByPosition(2,0)
oCell.String = x
oCell.CellBackColor = 10040064
x = x + 10

'Now set all the fields to CHAR
for a = 0 to 50
oCell= oSheet.getCellByPosition(a, 2)
txt = oCell.String
if len(txt) > 0 Then
if oSheet.getCellByPosition(a,1).String="" Then
oSheet.getCellByPosition(a,1).String="C"
end if
Else
Exit For
End If
next
end if
Wend
end function


Rem Builds all of the data into SQL file
Rem ORDER in each sheet (on row 1 col c) is important as is row 2 for C (char) and I (int)
function buildAllDataSQL()
StatusText "Generating data INSERT sql"
'iterate over all sheets
Dim oSheet As Object
Dim eSheets As Object
Dim oRow as Object
Dim oColumn as Object
eSheets = ThisComponent.getSheets.createEnumeration
Dim fileSheets(255)
Dim textFile as Object
f1 = FreeFile()
f2 = FreeFile()
currentPath=makeCurrentPath()
Open currentPath & "mainsql.sql" for output as #f1
print #f1, "-- Application Parameter Manager (APM)"
print #f1, "-- DATA Generation File for MAPS WOW"
print #f1, "-- Written by James Bushell"
print #f1, "-- Automatically generated (insert date here!)"

x = 0
SystemID = 1 ' This is WOWMAPS as from system_names
'Skip the _CTL sheet
While eSheets.hasMoreElements
oSheet = eSheets.nextElement()
'Only non control sheets please :)
columnNameList=""
bRow = true
iRow = 3
lastNumber = 10
if left(oSheet.getName,1) <> "_" Then
StatusText "Working through table [" & oSheet.getName & "]"
orderNumber = oSheet.getCellByPosition(2,0).getString
if orderNumber="" Then orderNumber = lastNumber
lastNumber = val(orderNumber) + 1
fileName = currentPath & format(orderNumber,"00000") & "_" & oSheet.getName & ".sql"
Open fileName for output as #2
fileSheets(x) = fileName

'Build all Column Names
columnNameList = "INSERT INTO " & oSheet.getName & "("
for a = 0 to 50
'Get column name
txt = oSheet.getCellByPosition(a, 2).String
if len(txt) > 0 Then
if a > 0 Then
columnNameList = columnNameList & ","
End If
columnNameList = columnNameList & txt
Else
Exit For
End If
Next
columnNameList = columnNameList & ") VALUES("

while bRow = true
oRow = oSheet.getRows().getByIndex(iRow)
if (oRow.getCellByPosition(0,0).String = "") Then
bRow = false
Else
StatusText "Table [" + oSheet.getName + "] Parsing Row " & iRow
rowData = ""
for a = 0 to 50
oCell= oRow.getCellByPosition(a, 0)
txt = oCell.String
if len(txt) > 0 Then
if a > 0 Then
rowData = rowData & ","
End If
'Now get the control char for type of field
'C=char=1 in apm db
'I=Integer=2 in apm db
oCell = oSheet.getCellByPosition(a, 1)
fieldType = oCell.String
if (fieldType="I") Then
rowData = rowData & GetIntField(txt)
Else
rowData = rowData & GetCharField(txt)
End If
Else
Exit For
End If
next
print #2, columnNameList & rowData & ");"
End If
iRow = iRow + 1
Wend
close #2
'Do the data here
x = x + 1
End If
Wend

StatusText "Sorting generated files"
ShellSort(fileSheets)
for a = lbound(fileSheets) to ubound(filesheets)
if (fileSheets(a) > "") Then
print #f1 ""
Open fileSheets(a) For Input As #2
StatusText "Merging " & fileSheets(a)
Do While NOT EOF(2)
Line Input #2, entry
print #f1, entry
Loop
Close #2
End If
next
close #f1
StatusText "Completed..."
msgbox "File is created and is at " & currentPath & "mainsql.sql"
end function



Private Sub ShellSort(myList())
Dim k1 As Long, k2 As Long, listSize As Long
Dim x1 As Long, isSorted As Boolean
Dim swapping
listSize = UBound(myList()) +1 -LBound(myList())
k1 = Fix(listSize /2)
do while k1 > 0
k2 = UBound(myList()) - k1
isSorted = true
for x1 = LBound(myList()) to k2
if StrComp(myList(x1), myList(x1 +k1), 0) = 1 then
swapping = myList(x1)
myList(x1) = myList(x1 +k1)
myList(x1 +k1) = swapping
isSorted = false
end if
next
if isSorted then
k1 = Fix(k1 /2)
end if
loop
End Sub


Private Function _makeInsertSQLForSheet(oSheet)
'Only non control sheets please :)
columnNameList=""
bRow = true
iRow = 3
numCols = 0
if left(oSheet.getName,1) <> "_" Then
orderNumber = oSheet.getCellByPosition(2,0).getString
if orderNumber="" Then orderNumber = 1
fileName = makeCurrentPath() & format(orderNumber,"00000") & "_" & oSheet.getName & ".sql"
Open fileName for output as #2

'Build all Column Names
columnNameList = "INSERT INTO " & oSheet.getName & "("
for a = 0 to 50
'Get column name
txt = oSheet.getCellByPosition(a, 2).String
if len(txt) > 0 Then
if a > 0 Then
columnNameList = columnNameList & ","
End If
columnNameList = columnNameList & txt
Else
Exit For
End If
Next
numCols = (a-1)
columnNameList = columnNameList & ") VALUES("

while bRow = true
StatusText "Parsing Row " & iRow
oRow = oSheet.getRows().getByIndex(iRow)
if (oRow.getCellByPosition(0,0).String = "") Then
bRow = false
Else
rowData = ""
for a = 0 to numCols
oCell= oRow.getCellByPosition(a, 0)
txt = oCell.String
if len(txt) > 0 Then
if a > 0 Then
rowData = rowData & ","
End If
'Now get the control char for type of field
'C=char=1 in apm db
'I=Integer=2 in apm db
oCell = oSheet.getCellByPosition(a, 1)
fieldType = oCell.String
if (fieldType="I") Then
rowData = rowData & GetIntField(txt)
Else
rowData = rowData & GetCharField(txt)
End If
Else
Exit For
End If
next
print #2, columnNameList & rowData & ");"
End If
iRow = iRow + 1
Wend
close #2
status = "File now available at " & fileName
StatusText status
msgbox status

End If
End Function


Private Function _makeInsertSQLForRow(oSheet, oRow)
'Only non control sheets please :)
columnNameList=""
bRow = true
iRow = 3
numCols = 0
if left(oSheet.getName,1) <> "_" Then
if (oRow.getCellByPosition(0,0).String = "") Then
msgbox "Cannot build this row as theres no data on it!!"
Else
'Build all Column Names
columnNameList = "INSERT INTO " & oSheet.getName & "("
for a = 0 to 50
'Get column name
txt = oSheet.getCellByPosition(a, 2).String
if len(txt) > 0 Then
if a > 0 Then
columnNameList = columnNameList & ","
End If
columnNameList = columnNameList & txt
Else
Exit For
End If
Next
numCols = (a-1)
columnNameList = columnNameList & ") VALUES("

rowData = ""
for a = 0 to numCols
oCell= oRow.getCellByPosition(a, 0)
txt = oCell.String
if len(txt) > 0 Then
if a > 0 Then
rowData = rowData & ","
End If
'Now get the control char for type of field
'C=char=1 in apm db
'I=Integer=2 in apm db
oCell = oSheet.getCellByPosition(a, 1)
fieldType = oCell.String
if (fieldType="I") Then
rowData = rowData & GetIntField(txt)
Else
rowData = rowData & GetCharField(txt)
End If
Else
Exit For
End If
next
_makeInsertSQLForRow = columnNameList & rowData & ");"
StatusText "Row built and available on clipboard"
End If
Else
msgbox "Cannot build row against control sheet!"
End If
End Function

private Function ProgressBar
ProgressBar = ThisComponent.CurrentController.StatusIndicator
End Function


REM display text in status bar
Sub StatusText(sInformation as String)
Dim iLen As Integer
Dim iRest as Integer

iLen = Len(sInformation)
iRest = 270-iLen
ProgressBar.start(sInformation+SPACE(iRest),0)
End Sub

public Function generateInsertsForCurrentSheet()
StatusText "Please wait - generating INSERT file"
_makeInsertSQLForSheet getCurrentSheet()
End Function


public Function generateInsertForCurrentRow()

startRow = ThisComponent.getCurrentController().getSelection().getRangeAddress().startRow
endRow = ThisComponent.getCurrentController().getSelection().getRangeAddress().endRow

Dim fullText, txt

for a = startRow to endRow
StatusText "Please wait - Building row " & a
row = getCurrentSheet().getRows.getByIndex(a)
txt = _makeInsertSQLForRow(getCurrentSheet(), row)
fullText = fullText & txt & chr(10)
next
x = (endRow - startRow) + 1
msgbox x & " row(s) generated and now available on clipboard"
TextToClipboard fullText
End Function


Sub TextToClipboard(cText)
clipText = cText
oClip = createUnoService ("com.sun.star.datatransfer.clipboard.SystemClipboard")
oTRX = createUnoListener("TR_", "com.sun.star.datatransfer.XTransferable")
oClipContents = oClip.setContents(oTRX, null)
End Sub

private Function TR_getTransferData( aFlavor As com.sun.star.datatransfer.DataFlavor ) As Any
If (aFlavor.MimeType = "text/plain;charset=utf-16") Then
TR_getTransferData = clipText
End If
End Function

private Function TR_getTransferDataFlavors() As Any
Dim aF As New com.sun.star.datatransfer.DataFlavor
aF.MimeType = "text/plain;charset=utf-16"
aF.HumanPresentableName = "Unicode-Text"
TR_getTransferDataFlavors = Array(aF)
End Function

private Function TR_isDataFlavorSupported( aFlavor As com.sun.star.datatransfer.DataFlavor ) As Boolean
TR_isDataFlavorSupported = (aFlavor.MimeType = "text/plain;charset=utf-16")
End Function






No comments: