diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/grid/lib/srvbrowse.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/grid/lib/srvbrowse.b')
| -rw-r--r-- | appl/grid/lib/srvbrowse.b | 719 |
1 files changed, 719 insertions, 0 deletions
diff --git a/appl/grid/lib/srvbrowse.b b/appl/grid/lib/srvbrowse.b new file mode 100644 index 00000000..eec8f56e --- /dev/null +++ b/appl/grid/lib/srvbrowse.b @@ -0,0 +1,719 @@ +implement Srvbrowse; + +# +# Copyright © 2003 Vita Nuova Holdings Limited. All rights reserved. +# + + +include "sys.m"; + sys : Sys; +include "draw.m"; + draw: Draw; + Rect: import draw; +include "tk.m"; + tk: Tk; +include "tkclient.m"; + tkclient: Tkclient; +include "grid/srvbrowse.m"; +include "registries.m"; + registries: Registries; + Registry, Attributes, Service: import registries; + +init() +{ + sys = load Sys Sys->PATH; + if (sys == nil) + badmod(Sys->PATH); + draw = load Draw Draw->PATH; + if (draw == nil) + badmod(Draw->PATH); + tk = load Tk Tk->PATH; + if (tk == nil) + badmod(Tk->PATH); + tkclient = load Tkclient Tkclient->PATH; + if (tkclient == nil) + badmod(Tkclient->PATH); + tkclient->init(); + registries = load Registries Registries->PATH; + if (registries == nil) + badmod(Registries->PATH); + registries->init(); + reg = Registry.new("/mnt/registry"); + if (reg == nil) { + reg = Registry.connect(nil, nil, nil); + if (reg == nil) + error("Could not find registry"); + } + qids = array[511] of { * => "" }; +} + +reg : ref Registry; +qids : array of string; + +# Qid stuff is a bit rubbish at the mo but waiting for registries to change: +# currently address is unique but will not be in the future so waiting +# for another id to uniquely identify a resource + +addqid(srvc: ref Service): int +{ + addr := srvc.addr; + qid := addr2qid(addr); + for (;;) { + if (qids[qid] == nil) + break; + else if (qids[qid] == addr) + return qid; + qid++; + if (qid >= len qids) + qid = 0; + } + qids[qid] = addr; +# sys->print("adding %s (%s) to %d\n",srvc.attrs.get("resource"), addr, qid); + return qid; +} + +getqid(srvc: ref Service): string +{ + addr := srvc.addr; + qid := addr2qid(addr); + startqid := qid; + for (;;) { + if (qids[qid] == addr) + return string qid; + qid++; + if (qid == startqid) + break; + if (qid >= len qids) + qid = 0; + } + return nil; +} + +addr2qid(addr: string): int +{ + qid := 0; + # assume addr starts 'tcp!...' + for (i := 4; i < len addr; i++) { + qid += addr[i] * 2**(i%10); + qid = qid % len qids; + } + return qid; +} + +addservice(srvc: ref Service) +{ + services = srvc :: services; + addqid(srvc); +} + +find(filter: list of list of (string, string)): list of ref Service +{ + lsrv : list of ref Service = nil; + if (filter == nil) + (lsrv, nil) = reg.services(); + else { + for (; filter != nil; filter = tl filter) { + attr := hd filter; + (s, err) := reg.find(attr); + for (; s != nil; s = tl s) + lsrv = hd s :: lsrv; + } + } + return sortservices(lsrv); +} + +refreshservices(filter: list of list of (string, string)) +{ + services = find(filter); +} + +servicepath2Service(path, qid: string): list of ref Service +{ + srvl : list of ref Service = nil; + (nil, lst) := sys->tokenize(path, "/"); + pname: string; + l := len lst; + if (l < 2 || l > 3) + return nil; + presource := hd tl lst; + if (l == 3) + pname = hd tl tl lst; + + for (tmpl := services; tmpl != nil; tmpl = tl tmpl) { + srvc := hd tmpl; + (resource, name) := getresname(srvc); + if (l == 2) { + if (resource == presource) + srvl = srvc :: srvl; + } + else if (l == 3) { + if (resource == presource) { + if (name == pname && qid == getqid(srvc)) { + srvl = srvc :: srvl; + break; + } + } + } + } + return srvl; +} + +servicepath2Dir(path: string, qid: int): (array of ref sys->Dir, int) +{ + # sys->print("srvcPath2Dir: '%s' %d\n",path, qid); + res : list of (string, string) = nil; + (nil, lst) := sys->tokenize(path, "/"); + presource, pname: string; + pattrib := 0; + l := len lst; + if (l > 1) + presource = hd tl lst; + if (l > 2) + pname = hd tl tl lst; + if (l == 4 && hd tl tl tl lst == "attributes") + pattrib = 1; + for (tmpl := services; tmpl != nil; tmpl = tl tmpl) { + srvc := hd tmpl; + (resource, name) := getresname(srvc); + if (l == 1) { + if (!isin(res, resource)) + res = (resource, nil) :: res; + } + else if (l == 2) { + if (resource == presource) + res = (name, string getqid(srvc)) :: res; + } + else if (l == 3) { + if (resource == presource && name == pname) { + if (qid == int getqid(srvc)) { + if (srvc.addr[0] == '@') + res = (srvc.addr[1:], string getqid(srvc)) :: res; + else { + if (srvc.attrs != nil) + res = ("attributes", string getqid(srvc)) :: res; + res = ("address:\0"+srvc.addr+"}", string getqid(srvc)) :: res; + } + break; + } + } + } + else if (l == 4) { + if (resource == presource && name == pname && pattrib) { + if (qid == int getqid(srvc)) { + for (tmpl2 := srvc.attrs.attrs; tmpl2 != nil; tmpl2 = tl tmpl2) { + (attrib, val) := hd tmpl2; + if (attrib != "name" && attrib != "resource") + res = (attrib+":\0"+val, string getqid(srvc)) :: res; + } + break; + } + } + } + } + resa := array [len res] of ref sys->Dir; + i := len resa - 1; + for (; res != nil; res = tl res) { + dir : sys->Dir; + qid: string; + (dir.name, qid) = hd res; + if (l < 3 || dir.name == "attributes") + dir.mode = 8r777 | sys->DMDIR; + else + dir.mode = 8r777; + if (qid != nil) + dir.qid.path = big qid; + resa[i--] = ref dir; + } + dups := 0; + if (l >= 2) + dups = 1; + return (resa, dups); +} + +isin(l: list of (string, string), s: string): int +{ + for (; l != nil; l = tl l) + if ((hd l).t0 == s) + return 1; + return 0; +} + +getresname(srvc: ref Service): (string, string) +{ + resource := srvc.attrs.get("resource"); + if (resource == nil) + resource = "Other"; + name := srvc.attrs.get("name"); + if (name == nil) + name = "?????"; + return (resource,name); +} + +badmod(path: string) +{ + sys->print("Srvbrowse: failed to load: %s\n",path); + exit; +} + +sortservices(lsrv: list of ref Service): list of ref Service +{ + a := array[len lsrv] of ref Service; + i := 0; + for (; lsrv != nil; lsrv = tl lsrv) { + addqid(hd lsrv); + a[i++] = hd lsrv; + } + heapsort(a); + lsrvsorted: list of ref Service = nil; + for (i = len a - 1; i >= 0; i--) + lsrvsorted = a[i] :: lsrvsorted; + return lsrvsorted; +} + + +heapsort(a: array of ref Service) +{ + for (i := (len a / 2) - 1; i >= 0; i--) + movedownheap(a, i, len a - 1); + + for (i = len a - 1; i > 0; i--) { + tmp := a[0]; + a[0] = a[i]; + a[i] = tmp; + movedownheap(a, 0, i - 1); + } +} + +movedownheap(a: array of ref Service, root, end: int) +{ + max: int; + while (2*root <= end) { + r2 := root * 2; + if (2*root == end || comp(a[r2], a[r2+1]) == GT) + max = r2; + else + max = r2 + 1; + + if (comp(a[root], a[max]) == LT) { + tmp := a[root]; + a[root] = a[max]; + a[max] = tmp; + root = max; + } + else + break; + } +} + +LT: con -1; +EQ: con 0; +GT: con 1; + +comp(a1, a2: ref Service): int +{ + (resource1, name1) := getresname(a1); + (resource2, name2) := getresname(a2); + if (resource1 < resource2) + return LT; + if (resource1 > resource2) + return GT; + if (name1 < name2) + return LT; + if (name1 > name2) + return GT; + return EQ; +} + +error(e: string) +{ + sys->fprint(sys->fildes(2), "Srvbrowse: %s\n", e); + raise "fail:error"; +} + +searchscr := array[] of { + "frame .f", + "scrollbar .f.sy -command {.f.c yview}", + "scrollbar .f.sx -command {.f.c xview} -orient horizontal", + "canvas .f.c -yscrollcommand {.f.sy set} -xscrollcommand {.f.sx set} -bg white -width 414 -borderwidth 2 -relief sunken -height 180 -xscrollincrement 10 -yscrollincrement 19", + "grid .f.sy -row 0 -column 0 -sticky ns -rowspan 2", + "grid .f.sx -row 1 -column 1 -sticky ew", + "grid .f.c -row 0 -column 1", + "pack .f -fill both -expand 1 ; pack propagate . 0; update", +}; + +SEARCH, RESULTS: con iota; + +searchwin(ctxt: ref Draw->Context, chanout: chan of string, filter: list of list of (string, string)) +{ + (top, titlebar) := tkclient->toplevel(ctxt,"","Search", tkclient->Appl); + butchan := chan of string; + tk->namechan(top, butchan, "butchan"); + tkcmds(top, searchscr); + makesearchframe(top); + flid := setframe(top, ".fsearch", nil); + selected := ""; + lresults : list of ref Service = nil; + resultstart := 0; + resize(top, 368,220); + maxresults := getmaxresults(top); + currmode := SEARCH; + tkclient->onscreen(top, nil); + tkclient->startinput(top, "kbd"::"ptr"::nil); + + main: for (;;) { + alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + inp := <-butchan => + (nil, lst) := sys->tokenize(inp, " "); + case hd lst { + "key" => + s := " "; + id := hd tl lst; + nv := hd tl tl lst; + tkp : string; + if (id != "-1") + tkp = ".fsearch.ea"+nv+id; + else + tkp = ".fsearch.e"+nv; + char := int hd tl tl tl lst; + s[0] = char; + if (char == '\n' || char == '\t') { + newtkp := ".fsearch"; + if (nv == "n") + newtkp += ".eav"+id; + else if (nv == "v") { + newid := string ((int id)+1); + e := tk->cmd(top, ".fsearch.ean"+newid+" cget -width"); + if (e == "" || e[0] == '!') { + insertattribrow(top); + newtkp += ".ean"+newid; + } + else + newtkp += ".ean"+newid; + } + focus(top, newtkp); + } + else { + tkcmd(top, tkp+" insert insert {"+s+"}"); + tkcmd(top, tkp+" see "+tkcmd(top, tkp+" index insert")); + } + "go" => + lresults = search(top, filter); + resultstart = 0; + makeresultsframe(top, lresults, 0, maxresults); + selected = nil; + flid = setframe(top, ".fresults", flid); + currmode = RESULTS; + if (chanout != nil) + chanout <-= "search search"; + "prev" => + selected = nil; + resultstart -= maxresults; + if (resultstart < 0) + resultstart = 0; + makeresultsframe(top, lresults, resultstart, maxresults); + flid = setframe(top, ".fresults", flid); + "next" => + selected = nil; + if (resultstart < 0) + resultstart = 0; + resultstart += maxresults; + if (resultstart >= len lresults) + resultstart -= maxresults; + makeresultsframe(top, lresults, resultstart, maxresults); + flid = setframe(top, ".fresults", flid); + "backto" => + flid = setframe(top, ".fsearch", flid); + tkcmd(top, ".f.c see 0 "+tkcmd(top, ".fsearch cget -height")); + currmode = SEARCH; + "new" => + resetsearchscr(top); + tkcmd(top, ".f.c see 0 0"); + setscrollr(top, ".fsearch"); + "select" => + if (selected != nil) + tkcmd(top, selected+" configure -bg white"); + if (selected == hd tl lst) + selected = nil; + else { + selected = hd tl lst; + tkcmd(top, hd tl lst+" configure -bg #5555FF"); + if (chanout != nil) + chanout <-= "search select " + + tkcmd(top, selected+" cget -text") + " " + hd tl tl lst; + } + } + tkcmd(top, "update"); + title := <-top.ctxt.ctl or + title = <-top.wreq or + title = <-titlebar => + if (title == "exit" || title == "ok") + break main; + e := tkclient->wmctl(top, title); + if (e == nil && title[0] == '!') { + (nil, lst) := sys->tokenize(title, " \t\n"); + if (len lst >= 2 && hd lst == "!size" && hd tl lst == ".") { + resize(top, -1,-1); + maxresults = getmaxresults(top); + if (currmode == RESULTS) { + makeresultsframe(top, lresults, resultstart, maxresults); + flid = setframe(top, ".fresults", flid); + tkcmd(top, "update"); + } + } + } + } + } + +} + +getmaxresults(top: ref Tk->Toplevel): int +{ + val := ((int tkcmd(top, ".f.c cget -height")) - 65)/17; + if (val < 1) + return 1; + return val; +} + +setframe(top: ref Tk->Toplevel, f, oldflid: string): string +{ + if (oldflid != nil) + tkcmd(top, ".f.c delete " + oldflid); + newflid := tkcmd(top, ".f.c create window 0 0 -window "+f+" -anchor nw"); + setscrollr(top, f); + return newflid; +} + +setscrollr(top: ref Tk->Toplevel, f: string) +{ + h := tkcmd(top, f+" cget -height"); + w := tkcmd(top, f+" cget -width"); + tkcmd(top, ".f.c configure -scrollregion {0 0 "+w+" "+h+"}"); +} + +resize(top: ref Tk->Toplevel, width, height: int) +{ + if (width == -1) { + width = int tkcmd(top, ". cget -width"); + height = int tkcmd(top, ". cget -height"); + } + else + tkcmd(top, sys->sprint(". configure -width %d -height %d", width, height)); + htitle := int tkcmd(top, ".f cget -acty") - int tkcmd(top, ". cget -acty"); + height -= htitle; + ws := int tkcmd(top, ".f.sy cget -width"); + hs := int tkcmd(top, ".f.sx cget -height"); + + tkcmd(top, ".f.c configure -width "+string (width - ws - 8)+ + " -height "+string (height - hs - 8)); + + tkcmd(top, "update"); +} + +makesearchframe(top: ref Tk->Toplevel) +{ + font := " -font /fonts/charon/plain.normal.font"; + fontb := " -font /fonts/charon/bold.normal.font"; + f := ".fsearch"; + + tkcmd(top, "frame "+f+" -bg white"); + tkcmd(top, "label "+f+".l -text {Search for Resource Attributes} -bg white" + fontb); + tkcmd(top, "grid "+f+".l -row 0 -column 0 -columnspan 3 -sticky nw"); + + tkcmd(top, "grid rowconfigure "+f+" 0 -minsize 30"); + tkcmd(top, "frame "+f+".fgo -bg white"); + tkcmd(top, "button "+f+".bs -text {Search} -command {send butchan go} "+font); + tkcmd(top, "button "+f+".bc -text {Clear} -command {send butchan new} "+font); + tkcmd(top, "grid "+f+".bs -row 3 -column 0 -sticky e -padx 2 -pady 5"); + tkcmd(top, "grid "+f+".bc -row 3 -column 1 -sticky w -pady 5"); + + tkcmd(top, "label "+f+".la1 -text {name} -bg white "+fontb); + tkcmd(top, "label "+f+".la2 -text {value} -bg white "+fontb); + + tkcmd(top, "grid "+f+".la1 "+f+".la2 -row 1"); + + insertattribrow(top); +} + +insertattribrow(top: ref Tk->Toplevel) +{ + (n, nil) := sys->tokenize(tkcmd(top, "grid slaves .fsearch -column 1"), " \t\n"); + row := string (n); + sn := string (n - 2); + fsn := ".fsearch.ean"+sn; + fsv := ".fsearch.eav"+sn; + font := " -font /fonts/charon/plain.normal.font"; + tkcmd(top, "entry "+fsn+" -width 170 -borderwidth 0 "+font); + tkcmd(top, "bind "+fsn+" <Key> {send butchan key "+sn+" n %s}"); + tkcmd(top, "entry "+fsv+" -width 170 -borderwidth 0 "+font); + tkcmd(top, "bind "+fsv+" <Key> {send butchan key "+sn+" v %s}"); + tkcmd(top, "grid rowinsert .fsearch "+row); + tkcmd(top, "grid "+fsn+" -column 0 -row "+row+" -sticky w -pady 1 -padx 2"); + tkcmd(top, "grid "+fsv+" -column 1 -row "+row+" -sticky w -pady 1"); + setscrollr(top, ".fsearch"); +} + +min(a,b: int): int +{ + if (a < b) + return a; + return b; +} + +max(a,b: int): int +{ + if (a > b) + return a; + return b; +} + +makeresultsframe(top: ref Tk->Toplevel, lsrv: list of ref Service, resultstart, maxresults: int) +{ + font := " -font /fonts/charon/plain.normal.font"; + fontb := " -font /fonts/charon/bold.normal.font"; + f := ".fresults"; + nresults := len lsrv; + row := 0; + n := 0; + tk->cmd(top, "destroy "+f); + tkcmd(top, "frame "+f+" -bg white"); + title := "Search Results"; + if (nresults > 0) { + from := resultstart+1; + too := min(resultstart+maxresults, nresults); + if (from == too) + title += sys->sprint(" (displaying match %d of %d)", from, nresults); + else + title += sys->sprint(" (displaying matches %d - %d of %d)", from, too, nresults); + } + tkcmd(top, "label "+f+".l -text {"+title+"} -bg white -anchor w" + fontb); + w1 := int tkcmd(top, f+".l cget -width"); + w2 := int tkcmd(top, ".f.c cget -width"); + tkcmd(top, f+".l configure -width "+string max(w1,w2)); + tkcmd(top, "grid "+f+".l -row 0 -column 0 -columnspan 3 -sticky nw"); + + tkcmd(top, "grid rowconfigure "+f+" 0 -minsize 30"); + tkcmd(top, "frame "+f+".f -bg white"); + for (; lsrv != nil; lsrv = tl lsrv) { + if (n >= resultstart && n < resultstart + maxresults) { + srvc := hd lsrv; + (resource, name) := getresname(srvc); + qid := getqid(srvc); + if (qid == nil) + qid = string addqid(srvc); + label := f+".f.lQ"+qid; + tkcmd(top, "label "+label+" -bg white -text {services/"+ + resource+"/"+name+"/}"+font); + tkcmd(top, "grid "+label+" -row "+string row+" -column 0 -sticky w"); + tkcmd(top, "bind "+label+" <Button-1> {send butchan select "+label+" "+qid+"}"); + row++; + } + n++; + } + if (nresults == 0) { + tkcmd(top, "label "+f+".f.l0 -bg white -text {No matches found}"+font); + tkcmd(top, "grid "+f+".f.l0 -row 0 -column 0 -columnspan 3 -sticky w"); + } + else { + tkcmd(top, "button "+f+".bprev -text {<<} "+ + "-command {send butchan prev}"+font); + if (resultstart == 0) + tkcmd(top, f+".bprev configure -state disabled"); + tkcmd(top, "button "+f+".bnext -text {>>} "+ + "-command {send butchan next}"+font); + if (resultstart + maxresults >= nresults) + tkcmd(top, f+".bnext configure -state disabled"); + tkcmd(top, "grid "+f+".bprev -column 0 -row 2 -padx 5 -pady 5"); + tkcmd(top, "grid "+f+".bnext -column 2 -row 2 -padx 5 -pady 5"); + } + tkcmd(top, "grid "+f+".f -row 1 -column 0 -columnspan 3 -sticky nw"); + tkcmd(top, "grid rowconfigure "+f+" 1 -minsize "+string (maxresults*17)); + tkcmd(top, "button "+f+".bsearch -text {Back to Search} "+ + "-command {send butchan backto}"+font); + tkcmd(top, "grid "+f+".bsearch -column 1 -row 2 -padx 5 -pady 5"); +} + +focus(top: ref Tk->Toplevel, newtkp: string) +{ + tkcmd(top, "focus "+newtkp); + x1 := int tkcmd(top, newtkp + " cget -actx") + - int tkcmd(top, ".fsearch cget -actx"); + y1 := int tkcmd(top, newtkp + " cget -acty") + - int tkcmd(top, ".fsearch cget -acty"); + x2 := x1 + int tkcmd(top, newtkp + " cget -width"); + y2 := y1 + int tkcmd(top, newtkp + " cget -height") + 45; + tkcmd(top, sys->sprint(".f.c see %d %d %d %d", x1,y1-30,x2,y2)); +} + +search(top: ref Tk->Toplevel, filter: list of list of (string, string)): list of ref Service +{ + searchattrib: list of (string, string) = nil; + (n, nil) := sys->tokenize(tkcmd(top, "grid slaves .fsearch -column 0"), " \t\n"); + for (i := 0; i < n - 3; i++) { + attrib := tkcmd(top, ".fsearch.ean"+string i+" get"); + val := tkcmd(top, ".fsearch.eav"+string i+" get"); + if (val == nil) + val = "*"; + if (attrib != nil) + searchattrib = (attrib, val) :: searchattrib; + } + tmp : list of list of (string, string) = nil; + for (; filter != nil; filter = tl filter) { + l := hd filter; + for (tmp2 := searchattrib; tmp2 != nil; tmp2 = tl tmp2) + l = hd tmp2 :: l; + tmp = l :: tmp; + } + filter = tmp; + if (filter == nil) + filter = searchattrib :: nil; + return find(filter); +} + +getitem(l : list of (string, ref Service), testid: string): ref Service +{ + for (; l != nil; l = tl l) { + (id, srvc) := hd l; + if (testid == id) + return srvc; + } + return nil; +} + +delitem(l : list of (string, ref Service), testid: string): list of (string, ref Service) +{ + l2 : list of (string, ref Service) = nil; + for (; l != nil; l = tl l) { + (id, srvc) := hd l; + if (testid != id) + l2 = (id, srvc) :: l2; + } + return l2; +} + +resetsearchscr(top: ref Tk->Toplevel) +{ + (n, nil) := sys->tokenize(tkcmd(top, "grid slaves .fsearch -column 1"), " \t\n"); + for (i := 1; i < n - 2; i++) + tkcmd(top, "destroy .fsearch.ean"+string i+" .fsearch.eav"+string i); + s := " delete 0 end"; + tkcmd(top, ".fsearch.ean0"+s); + tkcmd(top, ".fsearch.eav0"+s); +} + +tkcmd(top: ref Tk->Toplevel, cmd: string): string +{ + e := tk->cmd(top, cmd); + if (e != "" && e[0] == '!') + sys->print("Tk error: '%s': %s\n",cmd,e); + return e; +} + +tkcmds(top: ref Tk->Toplevel, a: array of string) +{ + for (j := 0; j < len a; j++) + tkcmd(top, a[j]); +} |
