original document (from the French Wiki): [L1 ]
by Miko -- translation by aricb
The Open Office suite is a free alternative to Microsoft Office. It can be controlled by Tcl with the tcom extension.
This code was tested on the following platform: Tcl 8.4, tcom 3.9, Open Office 1.1.4 and Windows XP. On Windows NT4 SP6 with the same components, it doesn't work.
package require tcom set OO [::tcom::ref createobject "com.sun.star.ServiceManager"] set OD [$OO createInstance com.sun.star.frame.Desktop ] set doc [$OD LoadComponentFromUrl private:factory/swriter _blank 0 ""]
This code works with tclsh; however, once "wrapped" with Freewrap, it no longer works. Explanation: the last argument of LoadComponentFromUrl with Delphi is an array of type variant, initialized with a special function... it would be necessary to translate that into Tcl. After several (admittedly empirical) unsuccessful attempts with [list], I finally resigned myself to using Delphi for the part of my program calling OO. Then while searching the internet I find this page: http://www.oooforum.org/forum/viewtopic.phtml?t=9815 with examples for controlling Open Office via COM with different languages, including Tcl. The editor emphasizes the need to have an Open Office document already open, and he uses the following code:
package require tcom array set args {} set objServiceManager [::tcom::ref createobject com.sun.star.ServiceManager] set Stardesktop [$objServiceManager createInstance com.sun.star.frame.Desktop] #Because I was not able to get the correct corresponding object type for a UNO sequence type I commented the loadComponentfromUrl out #set doc [$Stardesktop LoadComponentfromUrl private:factory/swriter _blank 0 "args"] set doc [$Stardesktop getCurrentComponent] set xtext [$doc text] $xtext setString {Hello World}
Oddly, you can see that he had the (judicious) idea to use "array set" to create the last argument of LoadComponentFromUrl. The solution (tested with freewrap and the Calc spreadsheet from OO):
set OO [::tcom::ref createobject "com.sun.star.ServiceManager"] set OD [$OO createInstance com.sun.star.frame.Desktop ] array set arguments {} set doc [$OD LoadComponentFromUrl private:factory/scalc _blank 0 [parray arguments]]
...I had to use parray, which in this case returns nothing, but sometimes nothing doesn't equal nothing (well, okay, an empty string isn't equal to an empty array from a standpoint of Tcl internals, but that doesn't tell me why the first three lines of code work with tclsh and not with freewrap). "array get" might seem more judicious, but causes an error.
Finally, now that the file is on the screen, we can access its objects:
set sheets [$doc Sheets [expr 0]] if [catch {set sheet1 [$sheets GetByName Sheet1]} ] { set sheet1 [$sheets GetByName Sheet1] }
Or (more portable)
set sheet1 [$sheets GetByIndex [expr 0]]
and fill the cells (you have to test the value to be inserted because the access methods for strings and numbers are different)
# cell index is column/line set cell [$sheet1 getCellByPosition [expr 0] [expr 0]] $cell SetString "Long live Tcl" set cell [$sheet1 getCellByPosition [expr 1] [expr 0]] $cell SetValue 2005
It almost makes you regret that there's no COM for Linux, since to control OO in the penguin's realm you have to use Java...
For easy reference, here's the essential code from above, consolidated into one listing:
package require tcom set OO [::tcom::ref createobject "com.sun.star.ServiceManager"] set OD [$OO createInstance com.sun.star.frame.Desktop ] array set arguments {} set doc [$OD LoadComponentFromUrl private:factory/scalc _blank 0 [parray arguments]] set sheets [$doc Sheets [expr 0]] set sheet1 [$sheets GetByIndex [expr 0]] # cell index is column/line set cell [$sheet1 getCellByPosition [expr 0] [expr 0]] $cell SetString "Long live Tcl" set cell [$sheet1 getCellByPosition [expr 1] [expr 0]] $cell SetValue 2005
You can enjoy Google's translation of the original document at [L2 ]
LV See also tcluno, a tcl interface to OpenOffice.org.