%%% %%% Author: %%% Leif Kornstaedt <kornstae@ps.uni-sb.de> %%% %%% Copyright: %%% Leif Kornstaedt, 1998 %%% %%% Last change: %%% $Date: 1999-10-15 14:29:40 +0200 (Fri, 15 Oct 1999) $ by $Author: kornstae $ %%% $Revision: 12184 $ %%% %%% This file is part of Mozart, an implementation of Oz 3: %%% http://www.mozart-oz.org %%% %%% See the file "LICENSE" or %%% http://www.mozart-oz.org/LICENSE.html %%% for information on usage and redistribution %%% of this file, and for a DISCLAIMER OF ALL %%% WARRANTIES. %%% functor import Tk(toplevel action frame label entry listbox scrollbar addYScrollbar button text send batch return returnInt isColor) TkTools(images menubar error dialog) Open(file) NetDictionary('class' defaultServer: DEFAULT_SERVER defaultPort: DEFAULT_PORT) export 'class': TkDictionary require DemoUrls(image) at '../DemoUrls.ozf' prepare FixedFont = '8x13' BoldFixedFont = '8x13bold' BoldFont = '-*-helvetica-bold-r-normal--*-120-*-*-*-*-*-*' NormalFont = '-*-helvetica-medium-r-normal--*-120-*-*-*-*-*-*' ServerWidth = 20 IPad = 4 TextBackground = c(239 239 239) WordWidth = 42 ButtonPad = 10 ListHeight = 8 ScrollBorder = 1 ScrollWidth = 12 LogWidth = 40 LogHeight = 4 Pad = 0 %% The following databases and strategies are always available. DEFAULT_DATABASES = ['*'#'All' '!'#'First with matches'] DEFAULT_STRATEGIES = ['.'#'Default' 'exact'#'Match words exactly' 'prefix'#'Match prefixes'] fun {FormatDBs DBs DatabaseNames} {FoldR DBs fun {$ DB In} {CondSelect DatabaseNames DB DB}# case In of unit then "" else ', '#In end end unit} end fun {Clean S} {FoldR S fun {$ C In} if C =< & then case In of & |_ then In else & |In end else C|In end end nil} end define Images = {TkTools.images [DemoUrls.image#'dict-client/dict.gif']} proc {SetMinsize W} {Tk.send update(idletasks)} {Tk.send wm(minsize W {Tk.returnInt winfo(reqwidth W)} {Tk.returnInt winfo(reqheight W)})} end %% %% Dialog to Enter a Server Address and Port %% class ServerDialog meth init(Master Server Port Connect) proc {DoConnect} Server Port in {ServerEntry tkReturn(get ?Server)} {PortEntry tkReturn(get ?Port)} if {String.isInt Port} then {Toplevel tkClose()} {Connect Server {String.toInt Port}} else {New TkTools.error tkInit(master: Toplevel text: 'The port must be given as a number.') _} end end Toplevel = {New Tk.toplevel tkInit(parent: Master title: 'Choose Server' 'class': 'OzTools' highlightthickness: 0 withdraw: true)} {Toplevel tkBind(event: '<Escape>' action: Toplevel#tkClose())} Frame1 = {New Tk.frame tkInit(parent: Toplevel highlightthickness: 0 borderwidth: 1 relief: raised)} ServerLabel = {New Tk.label tkInit(parent: Frame1 font: BoldFont text: 'Server: ')} ServerEntry = {New Tk.entry tkInit(parent: Frame1 font: FixedFont width: ServerWidth background: TextBackground borderwidth: 1)} {ServerEntry tkBind(event: '<Return>' action: DoConnect)} {ServerEntry tk(insert 'end' case Server of unit then DEFAULT_SERVER else Server end)} PortLabel = {New Tk.label tkInit(parent: Frame1 font: BoldFont text: 'Port: ')} PortEntry = {New Tk.entry tkInit(parent: Frame1 font: FixedFont width: ServerWidth background: TextBackground borderwidth: 1)} {PortEntry tkBind(event: '<Return>' action: DoConnect)} {PortEntry tk(insert 'end' case Port of unit then DEFAULT_PORT else Port end)} Frame2 = {New Tk.frame tkInit(parent: Toplevel highlightthickness: 0 borderwidth: 1 relief: raised)} ConnectButton = {New Tk.button tkInit(parent: Frame2 text: 'Connect' action: DoConnect)} CloseButton = {New Tk.button tkInit(parent: Frame2 text: 'Cancel' action: Toplevel#tkClose())} in {Tk.batch [pack(Frame1 side: top expand: true fill: both ipadx: IPad ipady: IPad) pack(Frame2 side: top expand: true fill: both ipadx: IPad ipady: IPad) grid(ServerLabel row: 0 column: 0 sticky: w) grid(ServerEntry row: 0 column: 1) grid(PortLabel row: 1 column: 0 sticky: w) grid(PortEntry row: 1 column: 1) pack(ConnectButton CloseButton side: left expand: true) focus(ServerEntry)]} {SetMinsize Toplevel} {Tk.send wm(deiconify Toplevel)} end end %% %% A Simple Information Display Window %% class InformationWindow feat toplevel text status attr Withdrawn: true meth init(Master Title cursor: Cursor <= xterm status: Status <= false) self.toplevel = {New Tk.toplevel tkInit(parent: Master title: Title 'class': 'OzTools' highlightthickness: 0 withdraw: true)} Menu = {TkTools.menubar self.toplevel self.toplevel [menubutton(text: 'File' feature: file menu: [command(label: 'Save as ...' action: self#SaveAs()) separator command(label: 'Close window' key: ctrl(x) action: self#close())]) menubutton(text: 'Edit' feature: edit menu: [command(label: 'Select all' action: self#SelectAll())])] nil} self.text = {New Tk.text tkInit(parent: self.toplevel cursor: Cursor font: FixedFont background: TextBackground state: disabled)} {self.text tk(tag configure titleTag font: BoldFixedFont)} Scrollbar = {New Tk.scrollbar tkInit(parent: self.toplevel borderwidth: ScrollBorder width: ScrollWidth)} {Tk.addYScrollbar self.text Scrollbar} if Status then self.status = {New Tk.text tkInit(parent: self.toplevel cursor: left_ptr border: 0 wrap: none font: NormalFont width: 0 height: 1 state: disabled)} else self.status = unit end in {Tk.batch grid(columnconfigure self.toplevel 0 weight: 1)| grid(rowconfigure self.toplevel 1 weight: 1)| grid(Menu row: 0 column: 0 columnspan: 2 sticky: nsew)| grid(self.text row: 1 column: 0 sticky: nsew)| grid(Scrollbar row: 1 column: 1 sticky: nsew)| if Status then [grid(self.status row: 2 column: 0 columnspan: 2 sticky: nsew)] else nil end} {SetMinsize self.toplevel} end meth append(VS Tag <= unit) try {Tk.batch [o(self.text configure state: normal) case Tag of unit then o(self.text insert 'end' VS) else o(self.text insert 'end' VS Tag) end o(self.text configure state: disabled)]} if @Withdrawn then {Tk.send wm(deiconify self.toplevel)} Withdrawn <- false end catch _ then skip % window already closed end end meth status(VS) if @Withdrawn then {Tk.send wm(deiconify self.toplevel)} Withdrawn <- false end {Tk.batch [o(self.status configure state: normal) o(self.status delete p(1 0) 'end') o(self.status insert 'end' VS) o(self.status configure state: disabled)]} end meth close() {self.toplevel tkClose()} end meth SaveAs() FileName in FileName = {Tk.return tk_getSaveFile(parent: self.toplevel title: 'Save Text' filetypes: q(q('All Files' '*')))} if FileName == "" then skip else File in File = {New Open.file init(name: FileName flags: [write create truncate])} {File write(vs: {self.text tkReturn(get p(1 0) 'end' $)})} {File close()} end end meth SelectAll() {self.text tk(tag add 'sel' p(1 0) 'end')} end end %% %% A Window to Display Definitions %% class DefinitionWindow from InformationWindow attr tagNumber inTag tagText feat action meth init(Master Action) self.action = Action tagNumber <- 0 inTag <- 0 tagText <- "" InformationWindow, init(Master 'Definitions' status: true) end meth append(Definition) case Definition of definition(word: Word db: _ dbname: DBName body: Body) then InformationWindow, append(Word#', '#DBName#'\n' titleTag) DefinitionWindow, AppendLines(nil#'\n'#Body) InformationWindow, append('\n\n') end end meth AppendLines(VS) case VS of V#'\n'#Rest then V2 in V2 = V#'\n' DefinitionWindow, AppendWithHyperLinks({VirtualString.toString V2}) DefinitionWindow, AppendLines(Rest) else DefinitionWindow, AppendWithHyperLinks({VirtualString.toString VS}) end end meth AppendWithHyperLinks(S) S1 S2 in {List.takeDropWhile S fun {$ C} C \= &{ andthen C \= &} end ?S1 ?S2} if @inTag > 0 then InformationWindow, append(S1 @tagNumber) tagText <- @tagText#S1 else InformationWindow, append(S1) end case S2 of C|Cr then case C of &{ then inTag <- @inTag + 1 {self.text tk(tag configure @tagNumber underline: true)} if Tk.isColor then {self.text tk(tag configure @tagNumber foreground: blue)} end [] &} then inTag <- {Max @inTag - 1 0} if @inTag == 0 then Text Action in Text = {Clean {VirtualString.toString (tagText <- "")}} Action = {New Tk.action tkInit(parent: self.text action: proc {$} {self.action Text} end)} {self.text tk(tag bind @tagNumber '<1>' Action)} tagText <- "" tagNumber <- @tagNumber + 1 end end DefinitionWindow, AppendWithHyperLinks(Cr) [] nil then skip end end end %% %% A Window to Display Matches %% class MatchWindow from InformationWindow feat action attr TagIndex: 0 meth init(Master Action) self.action = Action InformationWindow, init(Master 'Matches' cursor: left_ptr status: true) end meth append(Match Databases) case Match of DB#Word then N Action in N = @TagIndex + 1 TagIndex <- N InformationWindow, append(Word#', '#{CondSelect Databases {String.toAtom DB} DB}#'\n' N) Action = {New Tk.action tkInit(parent: self.text action: proc {$} DBs in DBs = [{String.toAtom DB}] {self.action Word DBs} end)} {self.text tk(tag bind N '<1>' Action)} end end end %% %% The Main Interaction Window %% class TkDictionary feat closed Toplevel WordEntry DatabasesList DatabaseIndices StrategiesList StrategyIndices StatusText LogText NetDict attr CurrentServer: unit CurrentPort: unit Databases: unit Strategies: unit meth init(Server <= DEFAULT_SERVER Port <= DEFAULT_PORT) NetMessages NetPort = {NewPort NetMessages} Messages P = {NewPort Messages} self.Toplevel = {New Tk.toplevel tkInit(title: 'Dictionary Client' 'class': 'OzTools' delete: P#close() withdraw: true)} %% Menubar Menu = {TkTools.menubar self.Toplevel self.Toplevel [menubutton(text: 'Server' menu: [command(label: 'Open ...' key: ctrl(o) action: P#ServerOpen(NetPort)) separator command(label: 'Status' key: ctrl(s) action: P#ServerStatus(NetPort)) command(label: 'Information ...' action: P#ServerInfo(NetPort)) separator command(label: 'Close' key: ctrl(x) action: P#close())]) menubutton(text: 'Database' menu: [command(label: 'Information ...' action: P#ShowInfo(NetPort))])] [menubutton(text: 'Help' menu: [command(label: 'About ...' action: P#About())])]} %% Frames Frame1 Frame2L Frame2R Frame3 Frame4 {ForAll [Frame1 Frame2L Frame2R Frame3 Frame4] fun {$} {New Tk.frame tkInit(parent: self.Toplevel highlightthickness: 0 borderwidth: 1 relief: raised)} end} %% Contents of Frame1 WordLabel = {New Tk.label tkInit(parent: Frame1 font: BoldFont text: 'Word')} self.WordEntry = {New Tk.entry tkInit(parent: Frame1 font: FixedFont width: WordWidth background: TextBackground borderwidth: 1)} {self.WordEntry tkBind(event: '<Return>' action: P#GetDefinitions(NetPort))} {self.WordEntry tkBind(event: '<Meta-Return>' action: P#GetMatches(NetPort))} WordButtonsFrame = {New Tk.frame tkInit(parent: Frame1 highlightthickness: 0)} DefineButton = {New Tk.button tkInit(parent: WordButtonsFrame text: 'Lookup' action: P#GetDefinitions(NetPort))} MatchButton = {New Tk.button tkInit(parent: WordButtonsFrame text: 'Match' action: P#GetMatches(NetPort))} %% Contents of Frame2L DatabasesLabel = {New Tk.label tkInit(parent: Frame2L font: BoldFont text: 'Databases')} DatabasesListFrame = {New Tk.frame tkInit(parent: Frame2L highlightthickness: 0)} self.DatabasesList = {New Tk.listbox tkInit(parent: DatabasesListFrame selectmode: extended exportselection: false background: TextBackground height: ListHeight borderwidth: 1)} self.DatabaseIndices = {NewDictionary} DatabasesScrollbar = {New Tk.scrollbar tkInit(parent: DatabasesListFrame borderwidth: ScrollBorder width: ScrollWidth)} {Tk.addYScrollbar self.DatabasesList DatabasesScrollbar} UpdateDatabasesButton = {New Tk.button tkInit(parent: Frame2L text: 'Update List' action: P#UpdateDatabases(NetPort))} %% Contents of Frame2R StrategiesLabel = {New Tk.label tkInit(parent: Frame2R font: BoldFont text: 'Strategies')} StrategiesListFrame = {New Tk.frame tkInit(parent: Frame2R highlightthicknes: 0)} self.StrategiesList = {New Tk.listbox tkInit(parent: StrategiesListFrame selectmode: browse exportselection: false background: TextBackground height: ListHeight borderwidth: 1)} self.StrategyIndices = {NewDictionary} StrategiesScrollbar = {New Tk.scrollbar tkInit(parent: StrategiesListFrame borderwidth: ScrollBorder width: ScrollWidth)} {Tk.addYScrollbar self.StrategiesList StrategiesScrollbar} UpdateStrategiesButton = {New Tk.button tkInit(parent: Frame2R text: 'Update List' action: P#UpdateStrategies(NetPort))} %% Contents of Frame3 LogLabel = {New Tk.label tkInit(parent: Frame3 font: BoldFont text: 'Log')} LogTextFrame = {New Tk.frame tkInit(parent: Frame3 highlightthicknes: 0)} self.LogText = {New Tk.text tkInit(parent: LogTextFrame wrap: word font: FixedFont background: TextBackground width: LogWidth height: LogHeight state: disabled)} LogScrollbar = {New Tk.scrollbar tkInit(parent: LogTextFrame borderwidth: ScrollBorder width: ScrollWidth)} {Tk.addYScrollbar self.LogText LogScrollbar} %% Contents of Frame4 self.StatusText = {New Tk.text tkInit(parent: Frame4 cursor: left_ptr border: 0 wrap: none font: NormalFont width: 0 height: 1 state: disabled)} in {Tk.batch [grid(columnconfigure self.Toplevel 0 weight: 1) grid(columnconfigure self.Toplevel 1 weight: 1) grid(rowconfigure self.Toplevel 2 weight: 1) grid(rowconfigure self.Toplevel 3 weight: 1) grid(Menu row: 0 column: 0 columnspan: 2 sticky: nsew) grid(Frame1 row: 1 column: 0 columnspan: 2 sticky: nsew) grid(Frame2L row: 2 column: 0 sticky: nsew) grid(Frame2R row: 2 column: 1 sticky: nsew) grid(Frame3 row: 3 column: 0 columnspan: 2 sticky: nsew) grid(Frame4 row: 4 column: 0 columnspan: 2 sticky: nsew) pack(WordLabel padx: Pad pady: Pad side: top) pack(self.WordEntry padx: Pad pady: Pad side: top fill: x) pack(WordButtonsFrame padx: Pad pady: Pad side: top) pack(DefineButton MatchButton side: left padx: ButtonPad) pack(DatabasesLabel padx: Pad pady: Pad side: top) pack(DatabasesListFrame padx: Pad pady: Pad side: top expand: true fill: both) pack(UpdateDatabasesButton padx: Pad pady: Pad side: top) pack(self.DatabasesList side: left expand: true fill: both) pack(DatabasesScrollbar side: left fill: y) pack(StrategiesLabel padx: Pad pady: Pad side: top) pack(StrategiesListFrame padx: Pad pady: Pad side: top expand: true fill: both) pack(UpdateStrategiesButton padx: Pad pady: Pad side: top) pack(self.StrategiesList side: left expand: true fill: both) pack(StrategiesScrollbar side: left fill: y) pack(LogLabel padx: Pad pady: Pad side: top) pack(LogTextFrame padx: Pad pady: Pad side: top expand: true fill: both) pack(self.LogText side: left expand: true fill: both) pack(LogScrollbar side: left fill: y) pack(self.StatusText padx: Pad pady: Pad fill: x) focus(self.WordEntry)]} {SetMinsize self.Toplevel} {Tk.send wm(deiconify self.Toplevel)} self.NetDict = {New NetDictionary.'class' init()} TkDictionary, Connect(NetPort Server Port) thread TkDictionary, NetServe(NetMessages) end thread TkDictionary, Serve(Messages) end end meth close() try {self.NetDict close()} catch E then TkDictionary, HandleException(E) end {self.Toplevel tkClose()} self.closed = unit end meth Serve(Ms) case Ms of M|Mr then TkDictionary, M TkDictionary, Serve(Mr) end end meth ServerOpen(NetPort) {New ServerDialog init(self.Toplevel @CurrentServer @CurrentPort proc {$ S P} TkDictionary, Connect(NetPort S P) end) _} end meth Connect(NetPort Server Port) TkDictionary, SetDatabases(DEFAULT_DATABASES) TkDictionary, SetStrategies(DEFAULT_STRATEGIES) TkDictionary, Log('Connect to '#Server#' on port '#Port) {Send NetPort connect(Server Port)} end meth ServerStatus(NetPort) TkDictionary, Log('Request server status') {Send NetPort serverStatus()} end meth ServerInfo(NetPort) TkDictionary, Log('Request server information') {Send NetPort serverInfo()} end meth ShowInfo(NetPort) DBs in DBs = {Filter TkDictionary, SelectedDatabases($) fun {$ DB} DB \= '!' andthen DB \= '*' end} if DBs \= nil then TkDictionary, Log('Request information on: '# {FormatDBs DBs @Databases}) {Send NetPort showInfo(DBs)} else {New TkTools.error tkInit(master: self.Toplevel text: 'Select a non-generic database first.') _} end end meth About() Dialog = {New TkTools.dialog tkInit(master: self.Toplevel root: pointer title: 'About Dictionary Client' buttons: ['Ok'#tkClose] default: 1 focus: 1 pack: false)} Icon = {New Tk.label tkInit(parent: Dialog image: Images.dict)} Title = {New Tk.label tkInit(parent: Dialog text: 'Dictionary Client')} Author = {New Tk.label tkInit(parent: Dialog text: ('Programming Systems Lab\n'# 'Universität des Saarlandes\n'# 'Contact: Leif Kornstaedt\n'# '<kornstae@ps.uni-sb.de>'))} in {Tk.batch [grid(Icon row: 0 column: 0 padx: 4 pady: 4) grid(Title row: 0 column: 1 padx: 4 pady: 4) grid(Author row: 1 column: 0 columnspan: 2 padx: 8 pady: 8)]} {Dialog tkPack()} end meth GetDefinitions(NetPort) Word DBs in {self.WordEntry tkReturn(get ?Word)} TkDictionary, SelectedDatabases(?DBs) if Word \= "" andthen DBs \= nil then TkDictionary, Log('Look up `'#Word#'\' in: '# {FormatDBs DBs @Databases}) {Send NetPort getDefinitions(Word DBs NetPort)} end end meth GetMatches(NetPort) Word DBs Strategy in {self.WordEntry tkReturn(get ?Word)} TkDictionary, SelectedDatabases(?DBs) TkDictionary, SelectedStrategy(?Strategy) if Word \= "" andthen DBs \= nil then TkDictionary, Log('Match `'#Word#'\' in: '# {FormatDBs DBs @Databases}# ' using: '#@Strategies.Strategy) {Send NetPort getMatches(Word DBs Strategy NetPort)} end end meth Lookup(Word DB NetPort) {Send NetPort getDefinitions(Word [DB] NetPort)} end meth UpdateDatabases(NetPort) TkDictionary, Log('Update databases') {Send NetPort updateDatabases()} end meth UpdateStrategies(NetPort) TkDictionary, Log('Update strategies') {Send NetPort updateStrategies()} end meth Log(VS) {Tk.batch [o(self.LogText configure state: normal) o(self.LogText insert 'end' VS#'\n') o(self.LogText configure state: disabled) o(self.LogText see 'end')]} end meth NetServe(Ms) case Ms of M|Mr then case M of connect(Server Port) then VS in VS = 'Connecting to '#Server#' on port '#Port#' ...' TkDictionary, Status(VS) try {self.NetDict connect(Server Port)} CurrentServer <- Server CurrentPort <- Port TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end [] serverStatus() then TkDictionary, Status('Requesting server status ...') try TkDictionary, Status({self.NetDict status($)}) catch E then TkDictionary, HandleException(E) end [] serverInfo() then VS in VS = 'Requesting server information ...' TkDictionary, Status(VS) try W in W = {New InformationWindow init(self.Toplevel 'Server Information')} {W append({self.NetDict showServer($)})} TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end [] showInfo(DBs) then VS in VS = ('Request information on: '#{FormatDBs DBs @Databases}# ' ...') TkDictionary, Status(VS) try {ForAll DBs proc {$ DB} W in W = {New InformationWindow init(self.Toplevel 'Database Information')} {W append({self.NetDict showInfo(DB $)})} end} TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end [] getDefinitions(Word DBs NetPort) then VS in VS = ('Looking up `'#Word#'\' in: '#{FormatDBs DBs @Databases}# ' ...') TkDictionary, Status(VS) try T Action W TotalCount in T = {Thread.this} proc {Action Word} TkDictionary, Log('Look up `'#Word#'\' in: '# {FormatDBs DBs @Databases}) {Send NetPort getDefinitions(Word DBs NetPort)} end W = {New DefinitionWindow init(self.Toplevel Action)} TotalCount = {NewCell 0} {ForAll DBs proc {$ DB} Count Res in thread try {self.NetDict 'define'(Word db: DB count: ?Count ?Res)} catch E then {Thread.injectException T E} end end if Count > 0 then Got ToGet in Got = {Access TotalCount} ToGet = Got + Count {Assign TotalCount ToGet} {W status('Retrieved '#Got#'; found '#ToGet)} {List.forAllInd Res proc {$ I Definition} {W status('Retrieved '#Got + I#'; found '#ToGet)} {W append(Definition)} end} end end} {W status('Total: '#{Access TotalCount})} if {Access TotalCount} == 0 then {New TkTools.error tkInit(master: self.Toplevel text: 'No matches for `'#Word#'\' found.') _} {W close()} end TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end [] getMatches(Word DBs Strategy NetPort) then VS in VS = ('Matching `'#Word#'\' in: '#{FormatDBs DBs @Databases}# ' using: '#@Strategies.Strategy#' ...') TkDictionary, Status(VS) try Action W TotalCount in proc {Action Word DBs} TkDictionary, Log('Look up `'#Word#'\' in: '# {FormatDBs DBs @Databases}) {Send NetPort getDefinitions(Word DBs NetPort)} end W = {New MatchWindow init(self.Toplevel Action)} TotalCount = {NewCell 0} {ForAll DBs proc {$ DB} Count Res in {self.NetDict match(Word db: DB strategy: Strategy count: ?Count ?Res)} if Count > 0 then Got ToGet in Got = {Access TotalCount} ToGet = Got + Count {Assign TotalCount ToGet} {W status('Retrieving '#Got#'; found '#ToGet)} {List.forAllInd Res proc {$ I Match} {W status('Retrieved '#Got + I#'; found '#ToGet)} {W append(Match @Databases)} end} end end} {W status('Total: '#{Access TotalCount})} if {Access TotalCount} == 0 then {New TkTools.error tkInit(master: self.Toplevel text: 'No matches for `'#Word#'\' found.') _} {W close()} end TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end [] updateDatabases() then VS in VS = 'Requesting database information ...' TkDictionary, Status(VS) try TkDictionary, SetDatabases({Append DEFAULT_DATABASES {Map {self.NetDict showDatabases($)} fun {$ DB#DBName} {String.toAtom DB}#DBName end}}) TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end [] updateStrategies() then VS in VS = 'Requesting strategy information ...' TkDictionary, Status(VS) try TkDictionary, SetStrategies('.'#'Default'| {Map {self.NetDict showStrategies($)} fun {$ Strat#StrategyName} {String.toAtom Strat}#StrategyName end}) TkDictionary, Status(VS#' done') catch E then TkDictionary, HandleException(E) end end TkDictionary, NetServe(Mr) end end meth HandleException(E) case E of system(os(os _ 110 ...) ...) then TkDictionary, Status('Connection timed out') elseof system(os(os _ 111 ...) ...) then TkDictionary, Status('Connection refused') elseof error(netdict(unexpectedResponse _ N Response) ...) then if N == unit orelse N < 500 then {Raise E} else TkDictionary, Status('Server error: '#Response) end elseof error(netdict(serverClosed Reason) ...) then TkDictionary, Status('Connection closed'# case Reason of unit then "" else ': '#Reason end) elseof error(netdict(notConnected) ...) then TkDictionary, Status('Not connected') else {Raise E} end end meth Status(VS) {Tk.batch [o(self.StatusText configure state: normal) o(self.StatusText delete p(1 0) 'end') o(self.StatusText insert 'end' VS) o(self.StatusText configure state: disabled)]} end meth SetDatabases(Pairs) Databases <- {List.toRecord databases Pairs} {self.DatabasesList tk(delete 0 'end')} {Dictionary.removeAll self.DatabaseIndices} {List.forAllInd Pairs proc {$ I DB#DatabaseName} {self.DatabasesList tk(insert 'end' DatabaseName)} {Dictionary.put self.DatabaseIndices I - 1 DB} end} {self.DatabasesList tk(selection set 0)} end meth SelectedDatabases($) {Map {self.DatabasesList tkReturnListInt(curselection $)} fun {$ I} {Dictionary.get self.DatabaseIndices I} end} end meth SetStrategies(Pairs) Strategies <- {List.toRecord strategies Pairs} {self.StrategiesList tk(delete 0 'end')} {Dictionary.removeAll self.StrategyIndices} {List.forAllInd Pairs proc {$ I Strategy#StrategyName} {self.StrategiesList tk(insert 'end' StrategyName)} {Dictionary.put self.StrategyIndices I - 1 Strategy} end} {self.StrategiesList tk(selection set 0)} end meth SelectedStrategy($) {Dictionary.get self.StrategyIndices {self.StrategiesList tkReturnListInt(curselection $)}.1} end end end