summaryrefslogtreecommitdiff
path: root/Master
diff options
context:
space:
mode:
authorNorbert Preining <preining@logic.at>2017-10-09 11:39:12 +0000
committerNorbert Preining <preining@logic.at>2017-10-09 11:39:12 +0000
commita3166ea3984c2b59336e0f029b4c796ff232c0b4 (patch)
tree38c396cfd703b108a9cba936dcda6e498f326c84 /Master
parentf98358a539d3082c37f3d10d7b1ae19f60d9dd84 (diff)
new tlcockpit
git-svn-id: svn://tug.org/texlive/trunk@45504 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r--Master/texmf-dist/doc/support/tlcockpit/NEWS11
-rw-r--r--Master/texmf-dist/doc/support/tlcockpit/screenshots/pkg-details.pngbin64148 -> 155022 bytes
-rw-r--r--Master/texmf-dist/scripts/tlcockpit/tlcockpit.jarbin11667993 -> 11688515 bytes
-rw-r--r--Master/texmf-dist/source/support/tlcockpit/build.sbt2
-rw-r--r--Master/texmf-dist/source/support/tlcockpit/src/main/scala/TLCockpit/ApplicationMain.scala340
-rw-r--r--Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsInfo.scala8
-rw-r--r--Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsTools.scala40
-rw-r--r--Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TLUpdate.scala2
-rw-r--r--Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala8
9 files changed, 308 insertions, 103 deletions
diff --git a/Master/texmf-dist/doc/support/tlcockpit/NEWS b/Master/texmf-dist/doc/support/tlcockpit/NEWS
new file mode 100644
index 00000000000..c1dca4d41ad
--- /dev/null
+++ b/Master/texmf-dist/doc/support/tlcockpit/NEWS
@@ -0,0 +1,11 @@
+NEWS for tlcockpit
+
+version 0.5
+-----------
+- better pkg info display
+- try to open doc files from pkg info window
+- dynamic updates of the update screen during updates
+
+version 0.4
+-----------
+First half-way usable version
diff --git a/Master/texmf-dist/doc/support/tlcockpit/screenshots/pkg-details.png b/Master/texmf-dist/doc/support/tlcockpit/screenshots/pkg-details.png
index 3bdbec16eb5..0b385b81169 100644
--- a/Master/texmf-dist/doc/support/tlcockpit/screenshots/pkg-details.png
+++ b/Master/texmf-dist/doc/support/tlcockpit/screenshots/pkg-details.png
Binary files differ
diff --git a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar
index 844cae67c47..ac6b87c2777 100644
--- a/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar
+++ b/Master/texmf-dist/scripts/tlcockpit/tlcockpit.jar
Binary files differ
diff --git a/Master/texmf-dist/source/support/tlcockpit/build.sbt b/Master/texmf-dist/source/support/tlcockpit/build.sbt
index e125b4563d0..a054c933ca8 100644
--- a/Master/texmf-dist/source/support/tlcockpit/build.sbt
+++ b/Master/texmf-dist/source/support/tlcockpit/build.sbt
@@ -1,6 +1,6 @@
name := "tlcockpit"
-version := "0.4"
+version := "0.5"
scalaVersion := "2.12.3"
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 3caada0d9ea..d7b7162107e 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
@@ -6,20 +6,34 @@
package TLCockpit
+import javafx.collections.ObservableList
+import javafx.scene.control
+
import TLCockpit.ApplicationMain.getClass
-import TeXLive.{TLBackup, TLPackage, TLUpdate, TlmgrProcess}
+import TeXLive._
+// import java.io.File
+import scalafx.beans.property.StringProperty
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.{Future, SyncVar}
import scala.concurrent.ExecutionContext.Implicits.global
+// import scala.reflect.io
+// import scala.reflect.io.File
import scala.util.{Failure, Success}
+import scalafx.beans.property.ObjectProperty
import scalafx.geometry.{HPos, Pos, VPos}
+import scalafx.scene.Cursor
import scalafx.scene.control.Alert.AlertType
import scalafx.scene.image.{Image, ImageView}
-import scalafx.scene.input.{KeyCode, KeyEvent}
+import scalafx.scene.input.{KeyCode, KeyEvent, MouseEvent}
+import scalafx.scene.paint.Color
// needed see https://github.com/scalafx/scalafx/issues/137
import scalafx.scene.control.TableColumn._
+import scalafx.scene.control.TreeTableColumn._
+import scalafx.scene.control.TreeItem
import scalafx.scene.control.Menu._
+import scalafx.scene.control.cell._
+import scalafx.scene.text.Text
import scalafx.Includes._
import scalafx.application.{JFXApp, Platform}
import scalafx.application.JFXApp.PrimaryStage
@@ -32,8 +46,13 @@ import scala.sys.process._
import scalafx.collections.ObservableBuffer
import scalafx.collections.ObservableMap
+// import java.awt.Desktop
+
// TODO TreeTableView indentation is lazy
-// TODO pkg info - access to doc files
+// TODO pkg info - allow opening (maybe preview) of doc files
+// use WebView and pdf.js: https://stackoverflow.com/questions/18207116/displaying-pdf-in-javafx
+// see https://github.com/scalafx/scalafx-ensemble/blob/master/src/main/scala/scalafx/ensemble/example/web/EnsembleWebView.scala
+// TODO better layout of pkg info
object ApplicationMain extends JFXApp {
@@ -47,9 +66,9 @@ object ApplicationMain extends JFXApp {
val iconImage = new Image(getClass.getResourceAsStream("tlcockpit-48.jpg"))
val logoImage = new Image(getClass.getResourceAsStream("tlcockpit-128.jpg"))
- val pkgs = ObservableMap[String, TLPackage]()
- val upds = ObservableMap[String, TLUpdate]()
- val bkps = ObservableMap[String, Map[String,TLBackup]]() // pkgname -> (version -> TLBackup)*
+ val pkgs: ObservableMap[String, TLPackage] = ObservableMap[String, TLPackage]()
+ val upds: ObservableMap[String, TLUpdate] = ObservableMap[String, TLUpdate]()
+ val bkps: ObservableMap[String, Map[String, TLBackup]] = ObservableMap[String, Map[String,TLBackup]]() // pkgname -> (version -> TLBackup)*
val errorText: ObservableBuffer[String] = ObservableBuffer[String]()
val outputText: ObservableBuffer[String] = ObservableBuffer[String]()
@@ -120,7 +139,7 @@ object ApplicationMain extends JFXApp {
(s: String) => {
// errorText.clear()
errorText.append(s)
- if (s != "") {
+ if (s.trim != "") {
outerrpane.expanded = true
outerrtabs.selectionModel().select(1)
}
@@ -175,7 +194,7 @@ object ApplicationMain extends JFXApp {
}.showAndWait()
}
- val OutputBuffer = ObservableBuffer[String]()
+ val OutputBuffer: ObservableBuffer[String] = ObservableBuffer[String]()
var OutputBufferIndex:Int = 0
val OutputFlushLines = 100
OutputBuffer.onChange {
@@ -242,23 +261,49 @@ object ApplicationMain extends JFXApp {
}
def callback_update(s: String): Unit = {
+ var prevUpdName = ""
+ var prevUpdPkg = new TLUpdate("","","","","","")
lineUpdateFunc = (l:String) => {
// println("line update: " + l + "=")
l match {
case u if u.startsWith("location-url") => None
case u if u.startsWith("total-bytes") => None
case u if u.startsWith("end-of-header") => None
- case u if u.startsWith("end-of-updates") => None
+ // case u if u.startsWith("end-of-updates") => None
case u if u == "OK" => None
case u if u.startsWith("tlmgr>") => None
case u =>
- val foo = parse_one_update_line(l)
- upds.remove(foo.name.value)
- val op = pkgs(foo.name.value)
- pkgs(foo.name.value) = new TLPackage(foo.name.value, op.rrev.value.toString, op.rrev.value.toString, foo.shortdesc.value, op.size.value.toString, "Installed")
- Platform.runLater {
- trigger_update("upds")
- trigger_update("pkgs")
+ if (prevUpdName != "") {
+ // println("Removing " + prevUpdName + " from list!")
+ upds.remove(prevUpdName)
+ val op = pkgs(prevUpdName)
+ pkgs(prevUpdName) = new TLPackage(prevUpdPkg.name.value, op.rrev.value.toString, op.rrev.value.toString,
+ prevUpdPkg.shortdesc.value, op.size.value.toString, "Installed")
+ Platform.runLater {
+ trigger_update("upds")
+ trigger_update("pkgs")
+ }
+ }
+ if (u.startsWith("end-of-updates")) {
+ // nothing to be done, all has been done above
+ // println("got end of updates")
+ } else {
+ // println("getting update line")
+ val foo = parse_one_update_line(l)
+ val pkgname = foo.name.value
+ val PkgTreeItemOption = updateTable.root.value.children.find(_.value.value.name.value == pkgname)
+ PkgTreeItemOption match {
+ case Some(p) =>
+ prevUpdName = pkgname
+ prevUpdPkg = p.getValue
+ // println("Setting status to Updating ... for " + pkgname)
+ prevUpdPkg.status = StringProperty("Updating ...")
+ Platform.runLater {
+ // println("calling updateTable refresh")
+ updateTable.refresh()
+ }
+ case None => println("Very strange: Cannot find TreeItem for upd package" + pkgname)
+ }
}
}
}
@@ -484,7 +529,7 @@ object ApplicationMain extends JFXApp {
def callback_show_pkg_info(pkg: String): Unit = {
- tlmgr_async_command(s"info $pkg", pkginfo => {
+ tlmgr_async_command(s"info --list $pkg", pkginfo => {
// need to call runLater to go back to main thread!
Platform.runLater {
val dialog = new Dialog() {
@@ -500,20 +545,180 @@ object ApplicationMain extends JFXApp {
padding = Insets(20)
}
var crow = 0
+ val runFiles = ArrayBuffer[String]()
+ val docFiles = ArrayBuffer[String]()
+ val binFiles = ArrayBuffer[String]()
+ val srcFiles = ArrayBuffer[String]()
+ var whichFiles = "run" // we assume run files if not found!
pkginfo.foreach((line: String) => {
- val keyval = line.split(":", 2).map(_.trim)
- if (keyval.length == 2) {
- val keylabel = new Label(keyval(0))
- val vallabel = new Label(keyval(1))
- vallabel.wrapText = true
- grid.add(keylabel, 0, crow)
- grid.add(vallabel, 1, crow)
- crow += 1
+ if (line.startsWith(" ")) {
+ // files are listed with two spaces in the beginning
+ whichFiles match {
+ case "run" => runFiles += line.trim
+ case "doc" => docFiles += line.trim
+ case "bin" => binFiles += line.trim
+ case "src" => srcFiles += line.trim
+ case _ => println("Don't know what to do?!?!")
+ }
+ } else {
+ val keyval = line.split(":", 2).map(_.trim)
+ whichFiles = if (keyval(0).startsWith("run files")) "run" else
+ if (keyval(0).startsWith("doc files")) "doc" else
+ if (keyval(0).startsWith("source files")) "src" else
+ if (keyval(0).startsWith("bin files (all platforms)")) "bin" else
+ "unknown"
+ if (keyval.length == 2) {
+ if (keyval(0) == "doc files" || keyval(0) == "source files" || keyval(0) == "run files" ||
+ keyval(0).startsWith("bin files (all platforms)") || keyval(0).startsWith("Included files, by type")) {
+ // do nothing
+ } else {
+ val keylabel = new Label(keyval(0))
+ val vallabel = new Label(keyval(1))
+ vallabel.wrapText = true
+ grid.add(keylabel, 0, crow)
+ grid.add(vallabel, 1, crow)
+ crow += 1
+ }
+ }
}
})
+ // add files section
+ if (runFiles.nonEmpty) {
+ grid.add(new Label("run files"), 0, crow)
+ grid.add(new Label(runFiles.mkString("\n")) { wrapText = true },1, crow)
+ crow += 1
+ }
+ if (docFiles.nonEmpty) {
+ grid.add(new Label("doc files"), 0, crow)
+ val vb = new VBox()
+ vb.children = docFiles.map { f =>
+ val fields = f.split(" ")
+ new Label(fields(0)) {
+ textFill = Color.Blue
+ onMouseClicked = { me: MouseEvent =>
+ println("Do something with " + fields(0))
+ // TODO while does gio return immediately on bash prompt but not here?
+ // ("gio open " + tlmgr.tlroot + "/" + fields(0)).!
+ //Desktop.getDesktop().open((tlmgr.tlroot + "/" + fields(0)))
+ OsTools.openFile(tlmgr.tlroot + "/" + fields(0))
+ println("done")
+ }
+ cursor = Cursor.Hand
+ }
+ }
+ //grid.add(new Label(docFiles.mkString("\n")) { wrapText = true },1, crow)
+ grid.add(vb,1,crow)
+ crow += 1
+ }
+ if (srcFiles.nonEmpty) {
+ grid.add(new Label("src files"), 0, crow)
+ grid.add(new Label(srcFiles.mkString("\n")) { wrapText = true },1, crow)
+ crow += 1
+ }
+ if (binFiles.nonEmpty) {
+ grid.add(new Label("bin files"), 0, crow)
+ grid.add(new Label(binFiles.mkString("\n")) { wrapText = true },1, crow)
+ crow += 1
+ }
grid.columnConstraints = Seq(new ColumnConstraints(100, 150, 200), new ColumnConstraints(100, 300, 5000, Priority.Always, new HPos(HPos.Left), true))
dialog.dialogPane().content = grid
- dialog.width = 500
+ // dialog.width = 500
+ // dialog.height = 800
+ dialog.showAndWait()
+ }
+ })
+ }
+ def callback_show_pkg_info_dev(pkg: String): Unit = {
+ tlmgr_async_command(s"info --list $pkg", pkginfo => {
+ // need to call runLater to go back to main thread!
+ Platform.runLater {
+ val dialog = new Dialog() {
+ initOwner(stage)
+ title = s"Package Information for $pkg"
+ // headerText = s"Package Information for $pkg"
+ resizable = true
+ }
+ dialog.dialogPane().buttonTypes = Seq(ButtonType.OK)
+ val keyCol = new TreeTableColumn[(String,String), String] {
+ text = "Package"
+ cellValueFactory = { p => StringProperty(p.value.value.value._1) }
+ }
+ val valCol = new TreeTableColumn[(String,String), String] {
+ text = pkg
+ cellValueFactory = { p => StringProperty(p.value.value.value._2) }
+ }
+ val infoTable = new TreeTableView[(String, String)](
+ new TreeItem[(String, String)](("","")) {
+ expanded = false
+ }) {
+ columns ++= List(keyCol, valCol)
+ }
+ valCol.prefWidth.bind(infoTable.width - keyCol.width - 15)
+ infoTable.prefHeight = 300
+ infoTable.vgrow = Priority.Always
+ infoTable.showRoot = false
+ infoTable.fixedCellSize = Region.USE_COMPUTED_SIZE
+ val runFiles = ArrayBuffer[String]()
+ val docFiles = ArrayBuffer[String]()
+ val binFiles = ArrayBuffer[String]()
+ val srcFiles = ArrayBuffer[String]()
+ val kids = ArrayBuffer[TreeItem[(String,String)]]()
+ var whichFiles = "run" // we assume run files if not found!
+ pkginfo.foreach((line: String) => {
+ if (line.startsWith(" ")) {
+ // files are listed with two spaces in the beginning
+ whichFiles match {
+ case "run" => runFiles += line.trim
+ case "doc" => docFiles += line.trim
+ case "bin" => binFiles += line.trim
+ case "src" => srcFiles += line.trim
+ case _ => println("Don't know what to do?!?!")
+ }
+ } else {
+ val keyval = line.split(":", 2).map(_.trim)
+ whichFiles = if (keyval(0).startsWith("run files")) "run" else
+ if (keyval(0).startsWith("doc files")) "doc" else
+ if (keyval(0).startsWith("source files")) "src" else
+ if (keyval(0).startsWith("bin files (all platforms)")) "bin" else
+ "unknown"
+ if (keyval.length == 2) {
+ if (keyval(0) == "doc files" || keyval(0) == "source files" || keyval(0) == "run files" ||
+ keyval(0).startsWith("bin files (all platforms)")) {
+ // do nothing
+ } else {
+ kids += new TreeItem[(String,String)]((keyval(0), keyval(1)))
+ }
+ }
+ }
+ })
+ // add files section
+ if (docFiles.nonEmpty) {
+ kids += new TreeItem[(String,String)](("Doc files","")) {
+ children = docFiles.map { p => new TreeItem[(String,String)](("",p)) }
+ }
+ }
+ if (runFiles.nonEmpty) {
+ kids += new TreeItem[(String,String)](("Run files","")) {
+ children = runFiles.map { p => new TreeItem[(String,String)](("",p)) }
+ }
+ }
+ if (srcFiles.nonEmpty) {
+ kids += new TreeItem[(String,String)](("Source files","")) {
+ children = srcFiles.map { p => new TreeItem[(String,String)](("",p)) }
+ }
+ }
+ if (binFiles.nonEmpty) {
+ kids += new TreeItem[(String,String)](("Bin files","")) {
+ children = binFiles.map { p => new TreeItem[(String,String)](("",p)) }
+ }
+ }
+ infoTable.root = new TreeItem[(String, String)](("","")) {
+ expanded = true
+ children = kids
+ }
+ dialog.dialogPane().content = infoTable
+ // dialog.width = 500
+ // dialog.height = 800
dialog.showAndWait()
}
})
@@ -533,7 +738,7 @@ object ApplicationMain extends JFXApp {
f"${fileSize/Math.pow(1024, digitGroup)}%3.1f ${units(digitGroup)}"
}
- val mainMenu = new Menu("TLCockpit") {
+ val mainMenu: Menu = new Menu("TLCockpit") {
items = List(
update_all_menu,
update_self_menu,
@@ -571,33 +776,18 @@ object ApplicationMain extends JFXApp {
onAction = (ae: ActionEvent) => callback_quit()
})
}
- val optionsMenu = new Menu("Options") {
- items = List(
- new MenuItem("General ...") {
- disable = true; onAction = (ae) => not_implemented_info()
- },
- new MenuItem("Paper ...") {
- disable = true; onAction = (ae) => not_implemented_info()
- },
- new MenuItem("Platforms ...") {
- disable = true; onAction = (ae) => not_implemented_info()
- },
+ val optionsMenu: Menu = new Menu("Options") {
+ items = List( new MenuItem("General ...") { disable = true; onAction = (ae) => not_implemented_info() },
+ new MenuItem("Paper ...") { disable = true; onAction = (ae) => not_implemented_info() },
+ new MenuItem("Platforms ...") { disable = true; onAction = (ae) => not_implemented_info() },
new SeparatorMenuItem,
- new CheckMenuItem("Expert options") {
- disable = true
- },
- new CheckMenuItem("Enable debugging options") {
- disable = true
- },
- new CheckMenuItem("Disable auto-install of new packages") {
- disable = true
- },
- new CheckMenuItem("Disable auto-removal of server-deleted packages") {
- disable = true
- }
+ new CheckMenuItem("Expert options") { disable = true },
+ new CheckMenuItem("Enable debugging options") { disable = true },
+ new CheckMenuItem("Disable auto-install of new packages") { disable = true },
+ new CheckMenuItem("Disable auto-removal of server-deleted packages") { disable = true }
)
}
- val helpMenu = new Menu("Help") {
+ val helpMenu: Menu = new Menu("Help") {
items = List(
/*
new MenuItem("Manual") {
@@ -609,10 +799,10 @@ object ApplicationMain extends JFXApp {
},
)
}
- val statusMenu = new Menu("Status: Idle") {
+ val statusMenu: Menu = new Menu("Status: Idle") {
disable = true
}
- val expertPane = new TitledPane {
+ val expertPane: TitledPane = new TitledPane {
text = "Experts only"
collapsible = true
expanded = false
@@ -630,31 +820,11 @@ object ApplicationMain extends JFXApp {
onAction = (event: ActionEvent) => callback_run_cmdline()
}
)
- },
- /* new HBox {
- spacing = 10
- children = List(
- new Button {
- text = "Show updates"
- onAction = (e: ActionEvent) => callback_show_updates()
- },
- new Button {
- text = "Show installed"
- onAction = (e: ActionEvent) => callback_show_installed()
- },
- new Button {
- text = "Show all"
- onAction = (e: ActionEvent) => callback_show_all()
- },
- update_self_button,
- update_all_button
- )
}
- */
)
}
}
- val updateTable = {
+ val updateTable: TreeTableView[TLUpdate] = {
val colName = new TreeTableColumn[TLUpdate, String] {
text = "Package"
cellValueFactory = { _.value.value.value.name }
@@ -720,24 +890,12 @@ object ApplicationMain extends JFXApp {
}
table
}
- val packageTable = {
+ val packageTable: TreeTableView[TLPackage] = {
val colName = new TreeTableColumn[TLPackage, String] {
text = "Package"
cellValueFactory = { _.value.value.value.name }
prefWidth = 150
}
- /*
- val colLRev = new TableColumn[TLPackage, String] {
- text = "Local rev"
- cellValueFactory = { _.value.lrev }
- prefWidth = 100
- }
- val colRRev = new TableColumn[TLPackage, String] {
- text = "Remote rev"
- cellValueFactory = { _.value.rrev }
- prefWidth = 100
- }
- */
val colDesc = new TreeTableColumn[TLPackage, String] {
text = "Description"
cellValueFactory = { _.value.value.value.shortdesc }
@@ -776,7 +934,7 @@ object ApplicationMain extends JFXApp {
}
table
}
- val backupTable = {
+ val backupTable: TreeTableView[TLBackup] = {
val colName = new TreeTableColumn[TLBackup, String] {
text = "Package"
cellValueFactory = { _.value.value.value.name }
@@ -817,7 +975,7 @@ object ApplicationMain extends JFXApp {
}
table
}
- val pkgstabs = new TabPane {
+ val pkgstabs: TabPane = new TabPane {
minWidth = 400
vgrow = Priority.Always
tabs = Seq(
@@ -850,7 +1008,7 @@ object ApplicationMain extends JFXApp {
}
}
)
- val menuBar = new MenuBar {
+ val menuBar: MenuBar = new MenuBar {
useSystemMenuBar = true
// menus.addAll(mainMenu, optionsMenu, helpMenu)
menus.addAll(mainMenu, statusMenu)
@@ -899,7 +1057,7 @@ object ApplicationMain extends JFXApp {
}
*/
- var lineUpdateFunc = { (l: String) => } // println(s"DEBUG: got ==$l== from tlmgr") }
+ var lineUpdateFunc: String => Unit = { (l: String) => } // println(s"DEBUG: got ==$l== from tlmgr") }
val bar = Future {
while (true) {
diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsInfo.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsInfo.scala
deleted file mode 100644
index 3b5ad20864f..00000000000
--- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsInfo.scala
+++ /dev/null
@@ -1,8 +0,0 @@
-package TeXLive
-
-object OsInfo {
- val OS = System.getProperty("os.name")
- def isWindows: Boolean = {
- OS.startsWith("Windows")
- }
-}
diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsTools.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsTools.scala
new file mode 100644
index 00000000000..38d0c334d99
--- /dev/null
+++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/OsTools.scala
@@ -0,0 +1,40 @@
+package TeXLive
+
+import scala.concurrent.Future
+import scala.concurrent.ExecutionContext.Implicits.global
+import sys.process._
+
+object OsTools {
+ val OS = System.getProperty("os.name").map(_.toLower)
+ def isWindows: Boolean = {
+ OS.startsWith("windows")
+ }
+ def isApple: Boolean = {
+ OS.startsWith("mac os")
+ }
+ def isUnix: Boolean = {
+ !(isWindows || isApple)
+ }
+
+ def openFileCmd(f: String): Seq[String] = {
+ val absf = new java.io.File(f).getCanonicalPath
+ if (isWindows) {
+ Seq("cmd", "start", absf)
+ } else if (isApple) {
+ Seq("open", absf)
+ } else {
+ Seq("xdg-open", absf)
+ }
+ }
+
+ def openFile(f: String): Unit = {
+ val cmd = openFileCmd(f)
+ val bar = Future {
+ try {
+ cmd.!
+ } catch {
+ case e: Exception => println("Cannot run command: " + cmd + " -- " + e + "\n")
+ }
+ }
+ }
+}
diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TLUpdate.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TLUpdate.scala
index 427ad722ceb..43623a523dd 100644
--- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TLUpdate.scala
+++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TLUpdate.scala
@@ -5,7 +5,7 @@ import scalafx.beans.property.{ObjectProperty, StringProperty}
// Note!!! we have to use ObjectProperty[Int] here instead of IntegerProperty
// since IntegerProperty does NOT implement Observable[Int,Int]
// see https://github.com/scalafx/scalafx/issues/243
-case class TLUpdate(name: StringProperty, status: StringProperty, lrev: StringProperty, rrev: StringProperty,
+case class TLUpdate(name: StringProperty, var status: StringProperty, lrev: StringProperty, rrev: StringProperty,
shortdesc: StringProperty, size: StringProperty) {
def this(_name: String, _status: String, _lrev: String, _rrev: String, _shortdesc: String, _size: String) =
this(
diff --git a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala
index c65058e169a..33c76d6708c 100644
--- a/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala
+++ b/Master/texmf-dist/source/support/tlcockpit/src/main/scala/TeXLive/TlmgrProcess.scala
@@ -2,17 +2,21 @@ package TeXLive
import java.io._
-import OsInfo._
+import OsTools._
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.SyncVar
-import scala.sys.process.{Process, ProcessBuilder, ProcessIO}
+// import scala.sys.process.{Process, ProcessBuilder, ProcessIO}
+import scala.sys.process._
class TlmgrProcess(updout: Array[String] => Unit, upderr: String => Unit, updline: String => Unit) {
val inputString = new SyncVar[String] // used for the tlmgr process input
val outputString = new SyncVar[String] // used for the tlmgr process output
val errorBuffer: StringBuffer = new StringBuffer() // buffer used for both tmgr process error console AND logging
+ val tlroot = "kpsewhich -var-value SELFAUTOPARENT".!!.trim
+ // println("tlroot ==" + tlroot + "==")
+
// set in only one place, in the main thread
var process: Process = _
var lastInput: String = ""