// Although most code from WIT.COM Inc is under the GPL // This code is more generic because it must be able // to be used in any GUI plugin package tree import ( "fmt" "time" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/guipb" "go.wit.com/log" "go.wit.com/widget" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/timestamppb" ) func (me *TreeInfo) doTable(a widget.Action) { if a.TablePB == nil { log.Log(TREE, "tree: action didn't have a Table PB") return } pb := guipb.NewTables() if err := pb.Unmarshal(a.TablePB); err != nil { log.Info("unmarshal error", err, "data len =", len(a.TablePB)) return } log.Info("tree.doTables() start. # of tables:", len(pb.Tables)) all := pb.All() for all.Scan() { t := all.Next() // for i, o := range t.Order { // log.Info("got order:", t.Title, i, o) // } // dumpTable(t) // me.ShowTable(t) // log.Info("TREE FOUND TABLE UUID", t.Uuid) for i, ot := range me.currentTables { // log.Info("TREE already has UUID", i, ot.Uuid) if t.Uuid == ot.Uuid { log.Log(TREE, "TREE found UUID! update table here", i, ot.Uuid) if ot.Grid == nil { log.Log(TREE, "TREE found UUID! ot.grid.Id = nil. need to find grid id here") return } else { log.Log(TREE, "TREE found UUID! grid.Id =", ot.Grid.Id) t.Grid = ot.Grid } if t.Grid == nil { log.Log(TREE, "TREE found UUID! grid.Id = nil. need to find grid id here") return } log.Log(TREE, "TREE found UUID! update table here", i, ot.Uuid, "grid.Id =", t.Grid.Id) me.updateTable(t) return } } me.currentTables = append(me.currentTables, t) if t.Grid == nil { log.Log(TREEWARN, "new table error: grid.Id = nil need to set grid id here") } else { // log.Info("NEW TREE: grid.Id =", t.Grid.Id) } me.makeTable(t) } } func (grid *Node) makeGridLabel(pb *guipb.Widget, w int, h int) *Node { a := new(widget.Action) a.WidgetType = widget.Label a.WidgetId = int(pb.Id) a.ParentId = grid.WidgetId a.State.Enable = true a.State.Label = pb.Name a.State.AtW = w a.State.AtH = h a.State.GridOffset.X = w a.State.GridOffset.Y = h // log.Info("makeGridLabel()", a.State) return addNode(a) } func (grid *Node) makeGridButton(pb *guipb.Widget, w int, h int) *Node { a := new(widget.Action) a.WidgetType = widget.Button a.WidgetId = int(pb.Id) a.ParentId = grid.WidgetId a.State.Enable = true a.State.Label = pb.Name a.State.AtW = w a.State.AtH = h a.State.GridOffset.X = w a.State.GridOffset.Y = h // log.Info("makeGridLabel()", a.State) return addNode(a) } func (me *TreeInfo) updateTable(t *guipb.Table) { grid := FindWidgetId(int(t.Grid.Id)) if grid == nil { log.Info("tree: updateTable() failed to make grid") return } // delete the existing table me.DeleteNode(grid) // remake the table me.Add(grid) var h int = 0 var w int = 0 for _, name := range t.Order { // log.Info("got order:", t.Title, name) if me.addTableRow(t, grid, name, w) { // log.Info("tree:row() COLUMN GOOD", t.Title, name, w, h) } else { log.Info("tree:row() COLOMN FAIL", t.Title, name, w, h) } w += 1 } } /* func (me *TreeInfo) updateRow(t *guipb.Table, name string) { for _, r := range t.StringRows { if name == r.Header.Name { // debugging code // id := r.Header.Id // n := treeRoot.FindWidgetId(int(id)) // if n == nil { // log.Info("could not find widget id", id) // } log.Info("tree.updateRow(string)", r.Header, "len =", len(r.Widgets)) // if r.Header.Name == "Hostname" { // } // log.Info("tree.updateRow() found Hostnames", r.Vals) for i, v := range r.Vals { // log.Info("tree: Hostname Widget", i, v, w.Name) w := r.Widgets[i] if v != w.Name { log.Info("tree: need to update:", i, v, "vs", w.Name, w.Id) n := treeRoot.FindWidgetId(int(w.Id)) if n == nil { log.Info("tree.TableUpdate() err n == nil ", w.Id, w.Name) continue } me.SetText(n, v) } if r.Header.Name == "CurrentBranchName" { log.Info("tree: check:", i, v, "vs", w.Name, w.Id) } } return } } for _, r := range t.TimeRows { if name != r.Header.Name { continue } log.Info("tree.updateRow(time)", r.Header, "len =", len(r.Widgets)) for i, _ := range r.Vals { // log.Info("tree: Hostname Widget", i, v, w.Name) w := r.Widgets[i] n := treeRoot.FindWidgetId(int(w.Id)) if n == nil { log.Info("tree.TableUpdate() err n == nil ", w.Id, w.Name) continue } msg, err := anypb.UnmarshalNew(w.Val, proto.UnmarshalOptions{}) if err != nil { log.Fatalf("failed to unmarshal: %v", err) } switch v := msg.(type) { case *timestamppb.Timestamp: me.SetText(n, shell.FormatDuration(time.Since(v.AsTime()))) default: me.SetText(n, fmt.Sprintf("%v", v)) } } return } } */ func (me *TreeInfo) makeTable(t *guipb.Table) { var grid *Node if t.Parent != nil { a := new(widget.Action) a.WidgetType = widget.Grid a.WidgetId = int(t.Grid.Id) a.ParentId = int(t.Parent.Id) a.State.Enable = true grid = addNode(a) } if grid == nil { log.Log(TREEWARN, "tree: makeTable() failed to make grid") return } me.Add(grid) // log.Info("tree: makeTable() finished add win & grid") var h int = 0 var w int = 0 for _, name := range t.Order { // log.Info("got order:", t.Title, name) if me.addTableRow(t, grid, name, w) { // log.Info("tree:row() COLUMN GOOD", t.Title, name, w, h) } else { log.Log(TREEWARN, "tree:row() COLOMN FAIL", t.Title, name, w, h) } w += 1 } } func (me *TreeInfo) addTableRow(t *guipb.Table, grid *Node, name string, w int) bool { var h int = 0 for _, r := range t.StringRows { if name != r.Header.Name { // log.Info("skip string row:", r.Header.Name, "!=", name) continue } // log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h) head := grid.makeGridLabel(r.Header, w, h) me.Add(head) h += 1 for _, v := range r.Widgets { // log.Info("tree: Add()ing to grid here", v.Id, v.Name, w, h) lab := grid.makeGridLabel(v, w, h) me.Add(lab) h += 1 } return true } for _, r := range t.ButtonRows { if name != r.Header.Name { // log.Info("skip string row:", r.Header.Name, "!=", name) continue } // log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h) head := grid.makeGridLabel(r.Header, w, h) me.Add(head) h += 1 for _, v := range r.Widgets { // log.Info("tree: Add()ing to grid here", v.Id, v.Name, w, h) lab := grid.makeGridButton(v, w, h) me.Add(lab) h += 1 } return true } for _, r := range t.IntRows { if name != r.Header.Name { // log.Info("skip sint row:", r.Header.Name, "!=", name) continue } // log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h) head := grid.makeGridLabel(r.Header, w, h) me.Add(head) h += 1 for _, v := range r.Widgets { v.Name = fmt.Sprintf("%d", v.Size) // log.Info("tree: Add()ing to grid here", v.Id, v.Name, w, h) lab := grid.makeGridLabel(v, w, h) me.Add(lab) h += 1 } return true } for _, r := range t.TimeRows { if name != r.Header.Name { // log.Info("skip sint row:", r.Header.Name, "!=", name) continue } // log.Info("tree: Add()ing to grid here", r.Header.Id, r.Header.Name, w, h) head := grid.makeGridLabel(r.Header, w, h) me.Add(head) h += 1 for _, widg := range r.Widgets { msg, err := anypb.UnmarshalNew(widg.Val, proto.UnmarshalOptions{}) if err != nil { log.Fatalf("failed to unmarshal: %v", err) } switch v := msg.(type) { case *timestamppb.Timestamp: // fmt.Println("Unpacked Timestamp:", shell.FormatDuration(time.Since(v.AsTime()))) widg.Name = shell.FormatDuration(time.Since(v.AsTime())) default: fmt.Println("Unknown type:", v) widg.Name = fmt.Sprintf("%v", v) } // log.Info("tree: Add()ing to grid here", widg.Id, widg.Name, w, h) lab := grid.makeGridLabel(widg, w, h) me.Add(lab) h += 1 } return true } return false } func dumpTable(t *guipb.Table) { for i, o := range t.Order { log.Info("got order:", t.Title, i, o) } for i, r := range t.StringRows { log.Info("got string row:", t.Title, i, r.Header.Name, r.Vals) for _, v := range r.Widgets { log.Info("tree: got string widget:", v.Id, v.Name) } } for i, r := range t.IntRows { log.Info("got int row:", t.Title, i, r.Header.Name, r.Vals) for _, v := range r.Widgets { log.Info("tree: got int widget:", v.Id, v.Size) } } } type TreeTable struct { PB *guipb.Table /* hostnames []string columns []*gui.NodeColumn order []*gui.NodeColumn */ }