You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

246 lines
7.8 KiB

# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'deck make' or src/make.tcl to update from <pkg>-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 <unspecified>
# @@ 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)}]
#date<sp>H: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