# -*- tcl -*- # Maintenance Instruction: leave the 999999.xxx.x as is and use 'deck make' or src/make.tcl to update from -buildversion.txt # # Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. # Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository. # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # (C) 2023 # # @@ Meta Begin # Application winlibreoffice 999999.0a1.0 # Meta platform tcl # Meta license # @@ Meta End # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Requirements ##e.g package require frobz package require uri ;#tcllib #windows? REVIEW - can we provide a common api for other platforms with only script? tcluno instead? if {"windows" eq $::tcl_platform(platform)} { if {[catch {package require twapi}]} { puts stderr "Twapi package required for winlibreoffice to function" puts stderr "Minimal functionality - only some utils may work" } } else { puts stderr "Package requires twapi. No current equivalent on non-windows platform. Try tcluno http://sf.net/projets/tcluno " puts stderr "Minimal functionality - only some utils may work" } # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ namespace eval winlibreoffice { #--- #todo: investigate tcluno package http://sf.net/projects/tcluno #CPlusPlus - platforms? #--- # #enable 1 variable datebase "1899-12-30" ;#libreoffice default in options->LibreOfifce Calc->Calculate #variable datebase "1900-01-01" ;#StarCalc 1.0 #variable datebase "1904-01-01" ;# ??? #sometimes a com object may support $obj -print #see also # $obj -destroy # $obj Quit # $collection -iterate ?options? varname script variable uno "" ;# service manager object variable psm "" ;# process service manager # -- --- --- --- # libreoffice functions proc getServiceManager {} { variable uno if {$uno eq ""} { set uno [twapi::comobj com.sun.star.ServiceManager] } return $uno } #uno getAvailableServiceNames #e.g com.sun.star.beans.Introspection # com.sun.star.ucb.SimpleFileAccess proc createUnoService {objname} { [getProcessServiceManager] createInstance $objname } proc getProcessServiceManager {} { variable psm if {$psm eq ""} { set svcmgr [getServiceManager] #set psm [$svcmgr getProcessServiceManager] #seems to be same object? - it has createInstance anyway REVIEW set psm $svcmgr } return $psm } #what does libreoffice accept for this fun.. local file paths only? proc convertToUrl {fpath} { if {![string match "file:/*" $fpath]} { # this turns //server/blah to file:////server/blah - which is probably nonsense set fpath [uri::join scheme file path $fpath] } return $fpath } #this proc convertFromUrl {fileuri} { if {[string match "file:/*" $fileuri]} { set finfo [uri::split $fileuri] if {"windows" eq $::tcl_platform(platform)} { if {[dict exists $finfo host]} { return "//${host}${path}" } else { #the leading slash in path indicates a local path and we strip on windows set p [dict get $finfo path] if {[string index $p 0] eq "/"} { set p [string range $p 1 end] } return $p } } else { if {[dict exists $finfo host]} { #?? review - how are file uris to other hosts handled? error "convertFromUrl doesn't handle non-local file uris on this platform" } else { return [dict get $finfo path] } } } } # -- --- --- --- # custom functions proc get_desktop {} { set uno [getServiceManager] set ctx [$uno getPropertyValue "DefaultContext"] set dt [$ctx getByName /singletons/com.sun.star.frame.theDesktop] #$dt setName odk_officedev_desk #$dt getName return $dt } proc blankdoc {{type scalc}} { set known_types [list scalc swriter simpress sdraw smath] if {$type ni $known_types} { puts stderr "Warning: unknown type $type. (known types: $known_types) will try anyway - private:factory/$type" } set dt [get_desktop] set doc [$dt loadComponentFromUrl "private:factory/$type" "_blank" 0 ""] ;#doesn't work without final param - empty string seems to work puts "doc title: [$doc Title]" return $doc } proc file_open_dialog {{title "pick a libreoffice file"}} { set filepicker [createUnoService "com.sun.star.ui.dialogs.FilePicker"] $filepicker Title $title set result [$filepicker Execute] if {$result} { #set files [$filepicker getSelectedFiles] # -iterate ? # return files(0) ? #e.g file:///C:/Users/sleek/test.txt return [$filepicker getFiles] } else { return "" } } #todo oo interface? proc calcdoc_sheets_by_index {doc idx} { set sheets [$doc getSheets] set s [$sheets getByIndex $idx] puts stdout "Sheet: [$s getName]" return $s } proc calcsheet_cell_range_by_name {sheet rangename} { return [$sheet getCellRangeByName $rangename] ;#e.g A1 } proc calccell_setString {cell str} { $cell setString $str } proc calccell_setValue {cell value} { $cell setValue $value } proc calccell_setPropertyValue {cell propset} { $cell setPropertyValue {*}$propset #e.g "NumberFormat" 49 # YYYY-MM-DD } #a hack #return libreoffice date in days since 1899.. proc date_from_clockseconds_approx {cs} { variable datebase set tbase [clock scan $datebase] package require punk::timeinterval set diff [punk::timeinterval::difference $tbase $cs] set Y [dict get $diff years] set M [dict get $diff months] set D [dict get $diff days] set yeardays [expr 365.25 * $Y] set monthdays [expr 30.437 * $M] #yes.. this is horrible.. just a test really - but gets in the ballpark. return [expr int($yeardays + $monthdays + $D)] } #time is represented on a scale of 0 to 1 6:00am = 0.25 (24/4) proc date_from_clockseconds {cs} { puts stderr "unimplemented" } #see also: https://wiki.tcl-lang.org/page/Tcom+examples+for+Microsoft+Outlook # this also uses days since 1899 (but 31 dec?) and uses a fixed base_offset of 36526 (for 2000-01-01) - this might be a better approach than using punk::timeinterval anyway # it seems to match libreoffice very closely (if not exact?) REVIEW # wher val is days since 1899 proc msdate_to_iso {val} { set base_ticks [clock scan 20000101] set base_offset 36526;# days since 31. Dec 1899, ARRRGGHHHHH set offset [expr {int($val)-$base_offset}] set clkdate [clock scan "$offset days" -base $base_ticks] set isodate [clock format $clkdate -format %Y%m%d] set fhours [expr {24.0*($val-int($val))}] set hours [expr {int($fhours)}] set mins [expr {int(($fhours-$hours)*60)}] #dateH:m is valid iso but not if space replaced with T - then would need seconds too return "${isodate} $hours:$mins" } } # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ ## Ready package provide winlibreoffice [namespace eval winlibreoffice { variable version set version 999999.0a1.0 }] return