diff options
18 files changed, 444 insertions, 261 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/tlcockpit/tlcockpit.sh b/Build/source/texk/texlive/linked_scripts/tlcockpit/tlcockpit.sh index 1b2e8d9cb04..11da62a683b 100755 --- a/Build/source/texk/texlive/linked_scripts/tlcockpit/tlcockpit.sh +++ b/Build/source/texk/texlive/linked_scripts/tlcockpit/tlcockpit.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Public domain. Originally written by Norbert Preining and Karl Berry, 2018-2019. +# Public domain. Originally written by Norbert Preining and Karl Berry, 2018-2020. scriptname=`basename "$0"` javaVersion=$(java -version 2>&1 | head -1) diff --git a/Build/source/texk/texlive/linked_scripts/tlshell/tlshell.tcl b/Build/source/texk/texlive/linked_scripts/tlshell/tlshell.tcl index 24ae2ea74ae..e0e10993713 100755 --- a/Build/source/texk/texlive/linked_scripts/tlshell/tlshell.tcl +++ b/Build/source/texk/texlive/linked_scripts/tlshell/tlshell.tcl @@ -26,7 +26,79 @@ if {$::tcl_platform(platform) ne "windows"} { set ::instroot [exec kpsewhich -var-value=TEXMFROOT] -# declarations and utilities shared with install-tl-gui.tcl +# try to read a configuration variable (gui-lang, tkfontscale) +# from tlmgr config ($TEXMF[SYS]CONFIG/tlmgr/config +# failure results in an empty string. +# this proc will be invoked by tltcl if tlshell is the invoker of tltcl +proc get_config_var {k} { + set v "" + set r [join [list {^\s*} $k {\s*=\s*(\S.*)$}] ""] + foreach tmf {"TEXMFCONFIG" "TEXMFSYSCONFIG"} { + if [catch {exec kpsewhich -var-value $tmf} d] { + break; # apparently there is not yet a TL installation + } + + if [catch {open [file join $d "tlmgr" "config"] r} fid] continue + while 1 { + if [chan eof $fid] { + break + } + if [catch {chan gets $fid} l] break + # we can assume that $k contains no special characters + if [regexp $r $l m v] { + set v [regsub {\s*$} $v ""] + break + } else { + # regexp will have unset v + set v "" + } + } + chan close $fid + if {$v ne ""} break + } + return $v +} + +proc save_config_var {k v} { + if [catch {exec kpsewhich -var-value "TEXMFCONFIG"} d] {return 0} + set d [file join $d "tlmgr"] + if [catch {file mkdir $d}] {return 0} ; # mkdir on existing dir is ok + set fn [file join $d "config"] + set oldlines [list] + set r [join [list {^\s*} $k {\s*=\s*(\S.*)$}] ""] + # read current config file + if [file exists $fn] { + if [catch {open $fn r} fid] {return 0} + set cnt 0 + while 1 { + if [catch {chan gets $fid} l] break + if [chan eof $fid] break + incr cnt + if {! [regexp $r $l]} { + lappend oldlines $l + } + if {$cnt>40} break + } + catch {chan close $fid} + } + lappend oldlines "$k = $v" + if [catch {open $fn w} fid] {return 0} + foreach l $oldlines { + if [catch {puts $fid $l}] { + catch {chan close $fid} + return 0 + } + } + catch {chan close $fid} + return 1 +} + +# tltcl: declarations and utilities shared with install-tl-gui.tcl +# tltcl likes to know who was the invoker +set ::invoker [file tail [info script]] +if [string match -nocase ".tcl" [string range $::invoker end-3 end]] { + set ::invoker [string range $::invoker 0 end-4] +} source [file join $::instroot "tlpkg" "tltcl" "tltcl.tcl"] # now is a good time to ask tlmgr for the _TL_ name of our platform @@ -54,9 +126,6 @@ set ddebug 0 # menus: disable tearoff feature option add *Menu.tearOff 0 -# for busy/idle indicators -set ::busy [__ "Idle"] - proc search_nocase {needle haystack} { if {$needle eq ""} {return -1} if {$haystack eq ""} {return -1} @@ -205,7 +274,44 @@ proc any_message {str type {p "."}} { } } ; # any_message -### enabling and disabling user interaction +##### tl global data ################################################## + +set ::last_cmd "" + +set ::progname [info script] +regexp {^.*[\\/]([^\\/\.]*)(?:\....)?$} $progname dummy ::progname +set ::procid [pid] + +# package repositories +array unset ::repos + +# mirrors: dict of dicts of lists of urls per country per continent +# moved to tltcl.tcl +#set ::mirrors [dict create] + +# dict of (local and global) package dicts +set ::pkgs [dict create] + +# platforms +set ::platforms [dict create] + +set ::have_remote 0 ; # remote packages info not yet loaded +set ::need_update_tlmgr 0 +set ::n_updates 0 +set ::tlshell_updatable 0 + +## package data to be displayed ## + +# sorted display data for packages; package data stored as lists +set ::filtered [dict create] + +# selecting packages for display: status and detail +set ::stat_opt "inst" +set ::dtl_opt "all" +# searching packages for display; also search short descriptions? +set ::search_desc 0 + +### enabling and disabling user interaction based on global data proc selective_dis_enable {} { # disable actions which make no sense at the time @@ -275,43 +381,6 @@ proc total_dis_enable {y_n} { } } ; # total_dis_enable -##### tl global data ################################################## - -set ::last_cmd "" - -set ::progname [info script] -regexp {^.*[\\/]([^\\/\.]*)(?:\....)?$} $progname dummy ::progname -set ::procid [pid] - -# package repositories -array unset ::repos - -# mirrors: dict of dicts of lists of urls per country per continent -# moved to tltcl.tcl -#set ::mirrors [dict create] - -# dict of (local and global) package dicts -set ::pkgs [dict create] - -# platforms -set ::platforms [dict create] - -set ::have_remote 0 ; # remote packages info not yet loaded -set ::need_update_tlmgr 0 -set ::n_updates 0 -set ::tlshell_updatable 0 - -## package data to be displayed ## - -# sorted display data for packages; package data stored as lists -set ::filtered [dict create] - -# selecting packages for display: status and detail -set ::stat_opt "inst" -set ::dtl_opt "all" -# searching packages for display; also search short descriptions? -set ::search_desc 0 - ##### handling tlmgr via pipe and stderr tempfile ##################### set ::prmpt "tlmgr>" @@ -539,8 +608,8 @@ proc run_cmd_waiting {cmd} { # with a virtual repository, which is the combined set of repositories, # with pinning applied if there is more than one repository. # But get_packages_info_remote must invoke -# show_repositories to display updated verification info. -# show_repositories is also invoked by initialize. +# show_repos to display updated verification info. +# show_repos is also invoked by initialize. # get_packages_info_local is invoked only once, at initialization. After # installations and removals, the collected information is updated by @@ -572,6 +641,18 @@ proc is_updatable {nm} { return [expr {$lr > 0 && $rr > 0 && $rr > $lr}] } +proc display_updated_globals {} { + if {$::have_remote && $::need_update_tlmgr} { + .topfll.luptodate configure -text [__ "Needs updating"] + } elseif $::have_remote { + .topfll.luptodate configure -text [__ "Up to date"] + } else { + .topfll.luptodate configure -text [__ "Unknown"] + } + # ... and status of update buttons + selective_dis_enable +} + proc update_globals {} { if {! $::have_remote} return set ::n_updates 0 @@ -582,15 +663,7 @@ proc update_globals {} { set ::tlshell_updatable [is_updatable tlshell] # also update displayed status info - if {$::have_remote && $::need_update_tlmgr} { - .topfll.luptodate configure -text [__ "Needs updating"] - } elseif $::have_remote { - .topfll.luptodate configure -text [__ "Up to date"] - } else { - .topfll.luptodate configure -text [__ "Unknown"] - } - # ... and status of update buttons - selective_dis_enable + display_updated_globals } # The package display treeview widget in the main window has columns @@ -682,9 +755,13 @@ proc collect_filtered {} { dict lappend ::filtered $nm $v dict lappend ::filtered $nm [dict get $pk shortdesc] } - display_packages_info } ; # collect_filtered +proc collect_and_display_filtered {} { + collect_filtered + display_packages_info +} + proc get_platforms {} { # guarantee fresh start foreach k $::platforms {dict unset ::platforms $k} @@ -1061,6 +1138,9 @@ proc set_repos_in_tlmgr {} { }; # set_repos_in_tlmgr proc show_repos {} { + # this proc lists the configured repository/ies + # in the upper left portion of the main window. + # it makes one call to the back end, but no need to go online. set w .toprepo foreach ch [winfo children $w] {destroy $ch} set nms [array names ::repos] @@ -1171,7 +1251,7 @@ proc save_load_repo {} { # reload remote package information set ::have_remote 0 get_packages_info_remote - collect_filtered + collect_and_display_filtered } proc select_mir {m} { @@ -1329,7 +1409,7 @@ if {$::tcl_platform(platform) ne "windows"} { run_cmds $cmds 1 vwait ::done_waiting update_local_revnumbers - collect_filtered + collect_and_display_filtered } ; # platforms_do @@ -1411,7 +1491,7 @@ proc finish_restore {} { # We won't wait for the log dialog to close, but we will # update the packages display in the main window. update_local_revnumbers - collect_filtered + collect_and_display_filtered } ; # finish_restore proc restore_all {} { @@ -1602,7 +1682,7 @@ proc update_tlmgr {} { update_local_revnumbers .topfr.linfra configure -text \ "tlmgr: r[dict get $::pkgs texlive.infra localrev]" - collect_filtered + collect_and_display_filtered } ; # update_tlmgr proc update_all {} { @@ -1628,7 +1708,7 @@ proc update_all {} { vwait ::done_waiting update_local_revnumbers } - collect_filtered + collect_and_display_filtered } ; # update_all ### doing something with some packages @@ -1688,7 +1768,7 @@ proc install_pkgs {sel_opt {pk ""}} { } update_local_revnumbers if {$sel_opt eq "marked"} {mark_all 0} - collect_filtered + collect_and_display_filtered } ; # install_pkgs proc update_pkgs {sel_opt {pk ""}} { @@ -1761,7 +1841,7 @@ proc update_pkgs {sel_opt {pk ""}} { } update_local_revnumbers if {$sel_opt eq "marked"} {mark_all 0} - collect_filtered + collect_and_display_filtered } ; # update_pkgs proc remove_pkgs {sel_opt {pk ""}} { @@ -1822,7 +1902,7 @@ proc remove_pkgs {sel_opt {pk ""}} { } update_local_revnumbers if {$sel_opt eq "marked"} {mark_all 0} - collect_filtered + collect_and_display_filtered } ; # remove_pkgs # restoring packages is a rather different story, controlled by the @@ -1908,46 +1988,25 @@ proc set_paper {p} { run_cmd "paper paper $p" 1 } -proc set_language_no_restart {l} { - set ok 1 - if [catch {exec kpsewhich -var-value "TEXMFCONFIG"} d] {set ok 0} - if $ok { - set d [file join $d "tlmgr"] - if [catch {file mkdir $d}] {set ok 0} - } - set fn [file join $d "config"] - set oldlines [list] - if {$ok && ! [catch {open $fn r} fid]} { - set cnt 0 - while 1 { - if [catch {chan gets $fid} ll] break - if [chan eof $fid] break - incr cnt - if {! [regexp {^\s*gui-lang} $ll]} { - lappend oldlines $ll - } - if {$cnt>20} break - } - catch {chan close $fid} - } - lappend oldlines "gui-lang = $l" - if {$ok && ! [catch {open $fn w} fid]} { - foreach ll $oldlines { - if [catch {puts $fid $ll}] { - set ok 0 - break - } - } - catch {chan close $fid} - } - return $ok -} ; # set_language_no_restart +#### gui options #### proc set_language {l} { - if [set_language_no_restart $l] { - restart_self - } else { - tk_messageBox -message [__ "Cannot set default GUI language"] -icon error + set ::lang $l + load_translations + rebuild_interface + if {! [save_config_var "gui-lang" $::lang]} { + tk_messageBox -message [__"Cannot save language setting"] + } +} + +proc set_fontscale {s} { + set ::tkfontscale $s + redo_fonts + rebuild_interface + if {[dict get $::pkgs texlive.infra localrev] >= 54766} { + if {! [save_config_var "tkfontscale" $::tkfontscale]} { + tk_messageBox -message [__"Cannot save font scale setting"] + } } } @@ -1956,7 +2015,7 @@ proc set_language {l} { # For capturing an external command, we need a separate output channel, # but we reuse ::out_log. # stderr is bundled with stdout so ::err_log should stay empty. -proc read_capt {} { +proc read_capture {} { set l "" ; # will contain the line to be read if {([catch {chan gets $::capt l} len] || [chan eof $::capt])} { catch {chan close $::capt} @@ -1966,7 +2025,7 @@ proc read_capt {} { lappend ::out_log $l log_widget_add $l } -}; # read_capt +}; # read_capture proc run_external {cmd mess} { set ::out_log {} @@ -1982,10 +2041,16 @@ proc run_external {cmd mess} { tk_messageBox -message "Failure to launch $cmd" } chan configure $::capt -buffering line -blocking 0 - chan event $::capt readable read_capt + chan event $::capt readable read_capture log_widget_init } +proc about_cmd {} { + set msg "\u00a9 2017-2020 Siep Kroonenberg\n\n" + append msg [__ "GUI interface for TeX Live Manager\nImplemented in Tcl/Tk"] + tk_messageBox -message $msg +} + proc show_help {} { set ::env(NOPERLDOC) 1 long_message [exec tlmgr --help] ok @@ -2012,7 +2077,7 @@ proc show_help {} { proc try_loading_remote {} { if {[possible_repository $::repos(main)]} { get_packages_info_remote - collect_filtered + collect_and_display_filtered } else { set mes [__ "%s is not a local or remote repository. Please configure a valid repository" $::repos(main)] @@ -2027,9 +2092,6 @@ proc populate_main {} { wm title . "TeX Live Shell" - # width of '0', as a rough estimate of average character width - set ::cw [font measure TkTextFont "0"] - ## menu ## # dummy empty menu to replace the real menu .mn in disabled states. @@ -2049,10 +2111,10 @@ proc populate_main {} { .mn configure -borderwidth 1 .mn configure -background $::default_bg - # plain_unix: avoid a RenderBadPicture error on quitting. - # 'send' changes the shutdown sequence, - # which avoids triggering the bug. - # 'tk appname <something>' restores 'send' and avoids the bug + # plain_unix: avoid a possible RenderBadPicture error on quitting + # when there is a menu. + # 'send' bypasses the bug by changing the shutdown sequence. + # 'tk appname <something>' restores 'send'. bind . <Destroy> { catch {tk appname appname} } @@ -2099,18 +2161,35 @@ proc populate_main {} { if {[llength $::langs] > 1} { incr inx - .mn.opt add cascade -label [__ "GUI language (restarts tlshell)"] \ + .mn.opt add cascade -label [__ "GUI language"] \ -menu .mn.opt.lang menu .mn.opt.lang foreach l [lsort $::langs] { if {$l eq $::lang} { - .mn.opt.lang add command -label "$l *" + set mlabel "$l *" } else { - .mn.opt.lang add command -label "$l" -command "set_language $l" + set mlabel $l } + .mn.opt.lang add command -label $mlabel \ + -command "set_language $l" + } + } + + incr inx + .mn.opt add cascade -label [__ "GUI font scaling"] \ + -menu .mn.opt.fscale + menu .mn.opt.fscale + foreach s {0.5 0.7 1 1.25 1.5 2 3 4 6 8} { + if {$s eq $::tkfontscale} { + set mlabel "$s *" + } else { + set mlabel $s } + .mn.opt.fscale add command -label $mlabel \ + -command "set_fontscale $s" } + if {$::tcl_platform(platform) ne "windows"} { incr inx set ::inx_platforms $inx @@ -2119,10 +2198,7 @@ proc populate_main {} { .mn add cascade -label [__ "Help"] -menu .mn.help -underline 0 menu .mn.help - .mn.help add command -label [__ "About"] -command { - tk_messageBox -message [string cat "\u00a9 2017-2019 Siep Kroonenberg - -" [__ "GUI interface for TeX Live Manager\nImplemented in Tcl/Tk"]]} + .mn.help add command -label [__ "About"] -command about_cmd .mn.help add command -label [__ "tlmgr help"] -command show_help ## menu end @@ -2205,16 +2281,16 @@ proc populate_main {} { # filter on status: inst, all, upd ttk::label .pkfilter.lstat -font TkHeadingFont -text [__ "Status"] ttk::radiobutton .pkfilter.inst -text [__ "Installed"] -value inst \ - -variable ::stat_opt -command collect_filtered + -variable ::stat_opt -command collect_and_display_filtered ttk::radiobutton .pkfilter.alls -text [__ "All"] -value all \ -variable ::stat_opt -command { if {! $::have_remote} get_packages_info_remote - collect_filtered + collect_and_display_filtered } ttk::radiobutton .pkfilter.upd -text [__ "Updatable"] -value upd \ -variable ::stat_opt -command { if {! $::have_remote} get_packages_info_remote - collect_filtered + collect_and_display_filtered } grid .pkfilter.lstat -column 0 -row 0 -sticky w -padx {3 50} pgrid .pkfilter.inst -column 0 -row 1 -sticky w @@ -2224,11 +2300,11 @@ proc populate_main {} { # filter on detail level: all, coll, schm ttk::label .pkfilter.ldtl -font TkHeadingFont -text [__ "Detail >> Global"] ttk::radiobutton .pkfilter.alld -text [__ All] -value all \ - -variable ::dtl_opt -command collect_filtered + -variable ::dtl_opt -command collect_and_display_filtered ttk::radiobutton .pkfilter.coll -text [__ "Collections and schemes"] \ - -value coll -variable ::dtl_opt -command collect_filtered + -value coll -variable ::dtl_opt -command collect_and_display_filtered ttk::radiobutton .pkfilter.schm -text [__ "Only schemes"] -value schm \ - -variable ::dtl_opt -command collect_filtered + -variable ::dtl_opt -command collect_and_display_filtered pgrid .pkfilter.ldtl -column 1 -row 0 -sticky w pgrid .pkfilter.alld -column 1 -row 1 -sticky w pgrid .pkfilter.coll -column 1 -row 2 -sticky w @@ -2320,6 +2396,28 @@ proc populate_main {} { wm state . normal } +# to be invoked at initialization and after a font scaling change +proc rebuild_interface {} { + foreach c [winfo children .] {catch {destroy $c}} + + # for busy/idle indicators + set ::busy [__ "Idle"] + populate_main + # and now redisplay all data + if {$::tcl_platform(platform) eq "windows"} { + .topfr.ladmin configure -text \ + [expr {$::multiuser ? [__ "Multi-user"] : [__ "Single-user"]}] + } + # svns for tlmgr and tlshell + .topfr.linfra configure -text \ + "tlmgr: r[dict get $::pkgs texlive.infra localrev]" + .topfr.lshell configure -text \ + "tlshell: r[dict get $::pkgs tlshell localrev]" + show_repos + display_packages_info + display_updated_globals +} + ##### initialize ###################################################### proc initialize {} { @@ -2367,15 +2465,8 @@ proc initialize {} { set ::flid [open $fname w] } - # languages - set ::langs [list "en"] - foreach l [glob -nocomplain -directory \ - [file join $::instroot "tlpkg" "translations"] *.po] { - lappend ::langs [string range [file tail $l] 0 end-3] - } - # store language in tlmgr configuration - set_language_no_restart $::lang + save_config_var "gui-lang" $::lang # in case we are going to do something with json: # add json subdirectory to auto_path, but at low priority @@ -2401,19 +2492,11 @@ proc initialize {} { foreach l $::out_log { if [regexp {^\s*multiuser\s+([01])\s*$} $l d ::multiuser] break } - .topfr.ladmin configure -text \ - [expr {$::multiuser ? [__ "Multi-user"] : [__ "Single-user"]}] } get_packages_info_local + collect_filtered get_repos_from_tlmgr - show_repos - # svns for tlmgr and tlshell - .topfr.linfra configure -text \ - "tlmgr: r[dict get $::pkgs texlive.infra localrev]" - .topfr.lshell configure -text \ - "tlshell: r[dict get $::pkgs tlshell localrev]" - collect_filtered ; # invokes display_packages_info - selective_dis_enable + rebuild_interface }; # initialize initialize diff --git a/Master/texmf-dist/doc/man/man1/tlcockpit.man1.pdf b/Master/texmf-dist/doc/man/man1/tlcockpit.man1.pdf Binary files differindex 94efaad3be3..5a4884b45e9 100644 --- a/Master/texmf-dist/doc/man/man1/tlcockpit.man1.pdf +++ b/Master/texmf-dist/doc/man/man1/tlcockpit.man1.pdf diff --git a/Master/texmf-dist/doc/support/tlcockpit/ChangeLog b/Master/texmf-dist/doc/support/tlcockpit/ChangeLog index 662d0a6d4c0..498f8099e6c 100644 --- a/Master/texmf-dist/doc/support/tlcockpit/ChangeLog +++ b/Master/texmf-dist/doc/support/tlcockpit/ChangeLog @@ -1,10 +1,86 @@ +2020-04-23 Norbert Preining <norbert@preining.info> + + * Release 1.2 (HEAD -> master) [a35c518] + +2020-04-23 Norbert Preining <norbert@preining.info> + + * update release script [ecd7160] + +2020-04-23 Norbert Preining <norbert@preining.info> + + * update jars [cac100a] + +2020-04-19 Norbert Preining <norbert@preining.info> + + * disable another forced dialog size (origin/master, origin/HEAD) [22ada11] + +2020-04-18 Norbert Preining <norbert@preining.info> + + * update jar (jdk14 from OpenJDK/Debian, jdk8 from Oracle) [38c9dfe] + +2020-04-18 Norbert Preining <norbert@preining.info> + + * update release version number [e2f8707] + +2020-04-10 Norbert Preining <norbert@preining.info> + + * use lfs for storing jar files, update attributes [2e3e78a] + +2020-04-10 Norbert Preining <norbert@preining.info> + + * update jars [7d8c1f9] + +2020-04-10 Norbert Preining <norbert@preining.info> + + * bump jdk8 scala and scalafx versions, bump tlcockpit version [420c7a6] + +2020-04-10 Norbert Preining <norbert@preining.info> + + * do not request 1500 height of dialogs, should auto-size [e3a8d44] + +2020-04-10 Norbert Preining <norbert@preining.info> + + * update scalafx version [d7f57bc] + +2020-04-10 Norbert Preining <norbert@preining.info> + + * update README, bump copyright year to 2020 [7baf6c7] + +2020-04-09 Norbert Preining <norbert@preining.info> + + * use java.specification.version, support single number versions [96ad401] + +2020-04-09 Norbert Preining <norbert@preining.info> + + * build default with JDK14, result runs on JDK11, too [67aa7f2] + +2020-04-09 Norbert Preining <norbert@preining.info> + + * configuration of startup tab via menu and .tlcockpit.conf [f9a3835] + +2020-04-09 Norbert Preining <norbert@preining.info> + + * switch to newer sbt on jdk14 builds, add sbt file for jdk14 [afdf9e1] + +2019-09-30 Norbert Preining <norbert@preining.info> + + * add HiDPI info to README [d0f9a73] + +2019-09-03 Norbert Preining <norbert@preining.info> + + * bump sbt build version to 1.2.8 [48ae3bf] + +2019-07-14 Norbert Preining <norbert@preining.info> + + * update README and app copyright, add explanation about JDKs [0b04518] + 2019-07-11 Norbert Preining <norbert@preining.info> - * Release 1.1 (HEAD -> master) [c62030d] + * Release 1.1 (tag: v1.1) [c62030d] 2019-07-11 Norbert Preining <norbert@preining.info> - * ship both jdk8 and jdk11 jars, wrapper checks version (origin/master, origin/HEAD) [cf285a0] + * ship both jdk8 and jdk11 jars, wrapper checks version [cf285a0] 2019-07-11 Norbert Preining <norbert@preining.info> @@ -168,7 +244,7 @@ 2018-04-08 Norbert Preining <norbert@preining.info> - * update jar and runner to add exec (tag: v0.9) [d8bfe81] + * update jar and runner to add exec [d8bfe81] 2018-04-08 Norbert Preining <norbert@preining.info> diff --git a/Master/texmf-dist/doc/support/tlcockpit/NEWS b/Master/texmf-dist/doc/support/tlcockpit/NEWS index e84482445fe..32620419008 100644 --- a/Master/texmf-dist/doc/support/tlcockpit/NEWS +++ b/Master/texmf-dist/doc/support/tlcockpit/NEWS @@ -1,5 +1,11 @@ NEWS for tlcockpit +version 1.2 (20200419) +---------------------- +- Allow configuration of startup tab from menu, configuration is + saved into ~/.tlcockpit.conf +- build with jdk14 (result still runs on jdk11) + version 1.1 (20190711) ---------------------- - build jdk8 and jdk11 versions - jdk11 includes javafx diff --git a/Master/texmf-dist/doc/support/tlcockpit/README.md b/Master/texmf-dist/doc/support/tlcockpit/README.md index c5b9bbd8d26..cdcf61d6995 100644 --- a/Master/texmf-dist/doc/support/tlcockpit/README.md +++ b/Master/texmf-dist/doc/support/tlcockpit/README.md @@ -27,11 +27,15 @@ Debugging can be enabled by passing the option `-d` or, for more detailed debugg Requirements ------------ -You need at least `tlmgr` from after 2017-11-23, in TeX Live language at least -version 45888 or `texlive.infra`. +Currently TLCockpit is shipped with two jars, one for JDK8 and one for JDK9+. +The JDK8 version does *not* contain the JavaFX as it is normally shipped together +with the JDK. The JDK9+ version contains JavaFX modules and thus should work +without the need for additional installations. -A recent Java (at least Java 8) installation that includes JavaFX is required. If you see -errors like +The default for TLCockpit shell wrapper (used on Unix and Mac) is to check for the +version of Java (using `java -version`) and use the appropriate jar. + +If you are running Java 8 and see the following errors ``` Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.NoClassDefFoundError: javafx/event/EventTarget @@ -44,11 +48,19 @@ that means that the Java installation does not provides JavaFX. On Windows the latest JRE from Oracle include JavaFX. On Linux one might need to install some extra packages (Debian/Ubuntu: openjfx). -With recent release of Java 11 problems are getting worse, since JavaFX is now -separately packaged, and ScalaFX only supports (by now) JavaFX8. That means, for -now it is necessary to have a Java 8 installation. As soon as ScalaFX supports -JavaFX11 we will move to use it. +HiDPI support +------------- +Depending on your JDK version and operating system, Java might not correctly +detect the presence of a HiDPI screen. + +Upgrading to JDK14 should help in this case. +For other versions, you might be able to fix it by setting the environment +variable +``` +export GDK_SCALE=2 +``` +(or even `=3`) might help. Development ----------- @@ -110,10 +122,12 @@ The Tools menu, as well as the expert and debug panes open ![Menu, Expert, Debug](screenshots/tlcockpit-menu-debug-expert.jpg) -License -------- +Copyright and License +--------------------- -GPL3+ +Copyright 2017-2020 Norbert Preining +Licenced under the GNU General Public License, version 3 or any higher version +(GPL3+) Author diff --git a/Master/texmf-dist/scripts/tlcockpit/tlcockpit-jdk8.jar b/Master/texmf-dist/scripts/tlcockpit/tlcockpit-jdk8.jar Binary files differindex 90b12ad2f47..bdcfcb11800 100755 --- a/Master/texmf-dist/scripts/tlcockpit/tlcockpit-jdk8.jar +++ b/Master/texmf-dist/scripts/tlcockpit/tlcockpit-jdk8.jar diff --git a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar Binary files differindex 6a3f93fbebd..091bdf27571 100644 --- a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar +++ b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar diff --git a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.sh b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.sh index 1b2e8d9cb04..11da62a683b 100755 --- a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.sh +++ b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Public domain. Originally written by Norbert Preining and Karl Berry, 2018-2019. +# Public domain. Originally written by Norbert Preining and Karl Berry, 2018-2020. scriptname=`basename "$0"` javaVersion=$(java -version 2>&1 | head -1) diff --git a/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk12 b/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk12 deleted file mode 100644 index 0e31eb34239..00000000000 --- a/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk12 +++ /dev/null @@ -1,55 +0,0 @@ -name := "tlcockpit" - -version := "1.1" - -scalaVersion := "2.12.7" - -val javaVersion:Int = 12 - -libraryDependencies += "io.spray" %% "spray-json" % "1.3.3" -libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2" -libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3" -libraryDependencies += "org.json4s" %% "json4s-native" % "3.6.0-M3" -libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.0-M3" - -// Add dependency on ScalaFX library -// libraryDependencies += "org.scalafx" %% "scalafx" % "11-R16" -libraryDependencies += "org.scalafx" % "scalafx_2.12" % "12.0.1-R17" - -lazy val root = (project in file(".")). - enablePlugins(BuildInfoPlugin). - settings( - buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion, BuildInfoKey(("javaVersion", javaVersion))), - buildInfoPackage := "TLCockpit" - ) - - -// Determine OS version of JavaFX binaries -lazy val osName = System.getProperty("os.name") match { - case n if n.startsWith("Linux") => "linux" - case n if n.startsWith("Mac") => "mac" - case n if n.startsWith("Windows") => "win" - case _ => throw new Exception("Unknown platform!") -} - -lazy val javaFXModules = Seq("base", "controls", "fxml", "graphics", "media", "swing", "web") -libraryDependencies ++= javaFXModules.map( m => - // with this the modules will NOT be included in the fat jar! - // "org.openjfx" % s"javafx-$m" % javaVersion % "provided" classifier osName - "org.openjfx" % s"javafx-$m" % javaVersion.toString classifier osName -) - -assemblyMergeStrategy in assembly := { - case PathList("module-info.class", xs @ _*) => MergeStrategy.discard - case PathList("META-INF", "MANIFEST.MF", xs @ _*) => MergeStrategy.discard - case x => MergeStrategy.first -} - -mainClass in assembly := Some("TLCockpit.ApplicationMain") - -assemblyJarName in assembly := "tlcockpit-jdk12.jar" -assemblyOutputPath in assembly := file("jar/tlcockpit-jdk12.jar") - - -// for scalafx -fork := true diff --git a/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk11 b/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk14 index bf490132f5c..4beec43b953 100644 --- a/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk11 +++ b/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk14 @@ -1,10 +1,10 @@ name := "tlcockpit" -version := "1.1" +version := "1.2" -scalaVersion := "2.12.7" +scalaVersion := "2.12.11" -val javaVersion:Int = 11 +val javaVersion:Int = 14 libraryDependencies += "io.spray" %% "spray-json" % "1.3.3" libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2" @@ -14,7 +14,7 @@ libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.0-M3" // Add dependency on ScalaFX library // libraryDependencies += "org.scalafx" %% "scalafx" % "11-R16" -libraryDependencies += "org.scalafx" % "scalafx_2.12" % "12.0.1-R17" +libraryDependencies += "org.scalafx" % "scalafx_2.12" % "12.0.2-R18" lazy val root = (project in file(".")). enablePlugins(BuildInfoPlugin). @@ -47,8 +47,8 @@ assemblyMergeStrategy in assembly := { mainClass in assembly := Some("TLCockpit.ApplicationMain") -assemblyJarName in assembly := "tlcockpit-jdk11.jar" -assemblyOutputPath in assembly := file("jar/tlcockpit-jdk11.jar") +assemblyJarName in assembly := "tlcockpit.jar" +assemblyOutputPath in assembly := file("jar/tlcockpit.jar") // for scalafx diff --git a/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk8 b/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk8 index ac19d090776..026ba15e18a 100644 --- a/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk8 +++ b/Master/texmf-dist/source/support/tlcockpit/build.sbt-jdk8 @@ -1,12 +1,12 @@ name := "tlcockpit" -version := "1.1" +version := "1.2" -scalaVersion := "2.12.7" +scalaVersion := "2.12.11" val javaVersion:Int = 8 -libraryDependencies += "org.scalafx" %% "scalafx" % "8.0.181-R13" +libraryDependencies += "org.scalafx" %% "scalafx" % "8.0.192-R14" libraryDependencies += "io.spray" %% "spray-json" % "1.3.3" libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2" libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3" diff --git a/Master/texmf-dist/source/support/tlcockpit/project/build.properties b/Master/texmf-dist/source/support/tlcockpit/project/build.properties index 091249b92ed..77ee500d9ba 100644 --- a/Master/texmf-dist/source/support/tlcockpit/project/build.properties +++ b/Master/texmf-dist/source/support/tlcockpit/project/build.properties @@ -1 +1 @@ -sbt.version = 1.2.6 +sbt.version = 1.3.9 diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala index 4574ac4966e..1864c8ab217 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala @@ -47,6 +47,10 @@ import scalafx.event.ActionEvent import scalafx.collections.ObservableBuffer import scalafx.collections.ObservableMap +// configuration file handling support +import java.util.Properties +import java.io.{ File, FileOutputStream, FileInputStream } + // JSON support - important load TLPackageJsonProtocol later! import spray.json._ import TeXLive.JsonProtocol._ @@ -88,47 +92,50 @@ object ApplicationMain extends JFXApp with LazyLogging { logger.trace("starting program tlcockpit") - val javaVersion = System.getProperty("java.version") + val javaVersion = System.getProperty("java.specification.version") val javaVersionSplit: Array[String] = javaVersion.split('.') logger.debug(s"Got javaVersion ${javaVersion}") - if (javaVersionSplit.length == 1) { - logger.warn(s"Cannot find Java version from ${javaVersion}, continuing anyway!") - } else { - val major = toInt(javaVersionSplit(0)) - val minor = toInt(javaVersionSplit(1)) - major match { - case Some(i) => - if (major.get == 1) { - minor match { - case Some(j) => - if (minor.get < 8) { - logger.error(s"Java version ${javaVersion} too old, need >= 1.8, terminating!") - Platform.exit() - sys.exit(1) - } else if (minor.get == 8) { - if (BuildInfo.javaVersion != 8) { - logger.warn(s"Build and run versions disagree: build: ${BuildInfo.javaVersion}, run: ${major.get}.${minor.get}, trying anyway!") - } + val major = toInt(javaVersionSplit(0)) + major match { + case Some(i) => + if (major.get == 1) { + val minor = toInt(javaVersionSplit(1)) + minor match { + case Some(j) => + if (minor.get < 8) { + logger.error(s"Java version ${javaVersion} too old, need >= 1.8, terminating!") + Platform.exit() + sys.exit(1) + } else if (minor.get == 8) { + if (BuildInfo.javaVersion != 8) { + logger.warn(s"Build and run versions disagree: build: ${BuildInfo.javaVersion}, run: ${major.get}.${minor.get}, trying anyway!") } - case None => - logger.warn(s"Cannot find Java version from ${javaVersion}, continuing anyway!") - } - } else { - if (major.get > 9) { - if (major.get != BuildInfo.javaVersion) { - logger.warn(s"Build and run versions disagree: build: ${BuildInfo.javaVersion}, run: ${major.get}, trying anyway!") } - } else { - logger.warn(s"Strange version number, please report: ${javaVersion}, continuing anyway!") + case None => + logger.warn(s"Cannot find Java version from ${javaVersion}, continuing anyway!") + } + } else { + if (major.get > 9) { + if (major.get != BuildInfo.javaVersion) { + logger.warn(s"Build and run versions disagree: build: ${BuildInfo.javaVersion}, run: ${major.get}, trying anyway!") } + } else { + logger.warn(s"Strange version number, please report: ${javaVersion}, continuing anyway!") } - case None => - logger.warn(s"Cannot find Java version from ${javaVersion}, continuing anyway!") - } - // in all other cases just hope it is fine - logger.info(s"Running on Java Version ${javaVersion}") + } + case None => + logger.warn(s"Cannot find Java version from ${javaVersion}, continuing anyway!") } + logger.info(s"Running on Java Version ${javaVersion}") + + val userHomeDirectory = System.getProperty("user.home") + val confPath = userHomeDirectory + "/.tlcockpit.conf" + val props = new Properties() + val propsFile = new File(confPath) + if (propsFile.exists()) { + props.load(new FileInputStream(propsFile)) + } var tlmgrBusy = BooleanProperty(false) @@ -362,7 +369,7 @@ object ApplicationMain extends JFXApp with LazyLogging { title = "About TLCockpit" graphic = new ImageView(logoImage) headerText = "TLCockpit version " + version + "\n\nManage your TeX Live with speed!" - contentText = "Copyright 2017-2018 Norbert Preining\nLicense: GPL3+\nSources: https://github.com/TeX-Live/tlcockpit" + contentText = "Copyright 2017-2020 Norbert Preining\nLicense: GPL3+\nSources: https://github.com/TeX-Live/tlcockpit" }.showAndWait() } @@ -1068,10 +1075,39 @@ tlmgr> }) } + def save_properties(): Unit = { + props.store(new FileOutputStream(confPath), null) + } + val StartTabPkgs = new RadioMenuItem("Packages") { + onAction = (ae) => { + props.setProperty("StartupTab", "packages") + save_properties() + } + } + val StartTabUpds = new RadioMenuItem("Updates") { + onAction = (ae) => { + props.setProperty("StartupTab","updates") + save_properties() + } + } + val StartTabBcks = new RadioMenuItem("Backups") { + onAction = (ae) => { + props.setProperty("StartupTab","backups") + save_properties() + } + } + + val startupTabMenu: Menu = new Menu("Startup Tab") { + val foo = new ToggleGroup + foo.toggles = Seq(StartTabPkgs, StartTabUpds, StartTabBcks) + items = List(StartTabPkgs, StartTabUpds, StartTabBcks) + } + val optionsMenu: Menu = new Menu("Options") { items = List( new MenuItem("General ...") { onAction = (ae) => callback_general_options() }, new MenuItem("Paper ...") { onAction = (ae) => callback_paper() }, + startupTabMenu /* new MenuItem("Platforms ...") { disable = true; onAction = (ae) => not_implemented_info() }, new SeparatorMenuItem, new CheckMenuItem("Expert options") { disable = true }, @@ -1415,6 +1451,27 @@ tlmgr> stage.width = 800 + val selectedTab = props.getOrDefault("StartupTab", "packages") + StartTabPkgs.selected = true + StartTabUpds.selected = false + StartTabBcks.selected = false + var StartupTab = 0 + selectedTab match { + case "packages" => {} + case "updates" => { + StartTabPkgs.selected = false + StartTabUpds.selected = true + StartupTab = 1 + } + case "backups" => { + StartTabPkgs.selected = false + StartTabBcks.selected = true + StartupTab = 2 + } + case _ => { + logger.warn(s"Unrecognized setting for StartupTab in config file: $selectedTab") + } + } var currentPromise = Promise[(String,Array[String])]() val pendingJobs = scala.collection.mutable.Queue[(String,(String, Array[String]) => Unit)]() @@ -1567,6 +1624,7 @@ tlmgr> logger.debug("Before loading tlpdb") load_tlpdb_update_pkgs_view_no_json() logger.debug("after loading tlpdb") + pkgstabs.selectionModel().select(StartupTab) }) } diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/LocationDialog.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/LocationDialog.scala index 647e0cc0389..2a45fb3db51 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/LocationDialog.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/LocationDialog.scala @@ -109,7 +109,7 @@ class LocationDialog(locs: Map[String,String]) extends LazyLogging { grid.columnConstraints = Seq(new ColumnConstraints(100, 100, 200), new ColumnConstraints(250, 250, 5000, Priority.Always, HPos.LEFT, true)) dialog.dialogPane().content = grid dialog.width = 500 - dialog.height = 1500 + // dialog.height = 1500 dialog.resultConverter = dialogButton => if (dialogButton == ButtonType.OK) { diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/OptionsDialog.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/OptionsDialog.scala index 52a9d5d0ce1..3e23270d95b 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/OptionsDialog.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/OptionsDialog.scala @@ -109,7 +109,8 @@ class OptionsDialog(opts: List[TLOption]) extends LazyLogging { grid.columnConstraints = Seq(new ColumnConstraints(300, 300, 500), new ColumnConstraints(200, 200, 5000, Priority.Always, HPos.LEFT, true)) dialog.dialogPane().content = grid dialog.width = 500 - dialog.height = 1500 + // This seems to be necessary for some old versions of ScalaFX or JavaFX or Java?? + // dialog.height = 1500 dialog.resultConverter = dialogButton => if (dialogButton == ButtonType.OK) { diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PaperDialog.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PaperDialog.scala index 3d7a2e84031..cb3e28907ca 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PaperDialog.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PaperDialog.scala @@ -64,7 +64,7 @@ class PaperDialog(paperconf: Map[String, TLPaperConf]) extends LazyLogging { grid.columnConstraints = Seq(new ColumnConstraints(100, 100, 150), new ColumnConstraints(150, 150, 5000, Priority.Always, HPos.LEFT, true)) dialog.dialogPane().content = grid dialog.width = 300 - dialog.height = 1500 + // dialog.height = 1500 dialog.resultConverter = dialogButton => if (dialogButton == ButtonType.OK) diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PkgInfoDialog.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PkgInfoDialog.scala index 89ba164de20..fbea1ecd62d 100644 --- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PkgInfoDialog.scala +++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/PkgInfoDialog.scala @@ -116,7 +116,7 @@ class PkgInfoDialog(tlp: TLPackage) extends Dialog { grid.columnConstraints = Seq(new ColumnConstraints(100, 200, 200), new ColumnConstraints(100, 400, 5000, Priority.Always, HPos.LEFT, true)) dialog.dialogPane().content = grid dialog.width = 600 - dialog.height = 1500 + // dialog.height = 1500 // dialog def showAndWait(): Unit = this.dialog.showAndWait() |