sourcecamembert::ProcessManager.fan

// History:
//  Dec 19 13 tcolar Creation
//

using fwt
using gfx

**
** ProcessManager
**
class ProcessManager
{
  [Int:Proc] procs := [:]
  Int id := 0

  Window window

  new make()
  {
    table := Table
    {
      model = ProcTableModel(this)
    }
    window = Window
    {
      size = Size(1000,400)
      title = "Processes"
      EdgePane
      {
        top = EdgePane
        {
          it.left = Button
          {
            text = "Refresh"
            onAction.add |evt| {table.refreshAll}
          }
          it.right = Button
          {
            text = "Kill selected"
            onAction.add |evt| {
              if(table.selected.size > 0)
              {
                id := table.model.text(0, table.selected[0]).toInt
                kill(id)
                table.refreshAll
              }
            }
          }
        }
        center = table
      },
    }
  }

  ** Register a process
  ** If there is an existing process with the exact same command then we kill it first
  Int register(Process p, Str name := ""){
    procs.each |proc, id|
    {
      if(proc.p.command.toStr == p.command.toStr){
        kill(id)
      }
    }

    id++
    procs[id] = Proc(p, name)
    return id
  }

  Void unregister(Int id){
    procs.remove(id)
  }

  Void kill(Int id)
  {
    if(procs.containsKey(id))
    {
      Sys.log.info("Killing procss ${procs[id]}")
      procs[id].p.kill
      procs.remove(id)
    }
  }

  Void show()
  {
    window.open
  }
}

class ProcTableModel : TableModel{
  ProcessManager p

  override Int numCols := 4
  new make(ProcessManager p){
    this.p = p;
  }

  override Str header(Int col){
    switch(col)
    {
      case 0:
        return "Id"
      case 1:
        return "Name"
      case 2:
        return "Runtime"
      default:
        return "Command"
    }
  }

  override Str text(Int col, Int row){
    id := p.procs.keys[row]
    proc := p.procs[id]
    switch(col)
    {
      case 0:
        return "$id"
      case 1:
        return proc.name
      case 2:
        return (DateTime.now - proc.started).toSec.toStr + " sec"
      default:
        return proc.p.command.toStr
    }
  }

  override Int numRows()
  {
    return p.procs.size
  }
}

class Proc
{
  Process p
  Str name
  DateTime started

  new make(Process p, Str name)
  {
    this.p = p
    this.name = name
    this.started = DateTime.now
  }

  override Str toStr()
  {
    return "$name $p.command.toStr"
  }
}