1# gui.py
2#
3# main openipmi GUI handling
4#
5# Author: MontaVista Software, Inc.
6#         Corey Minyard <minyard@mvista.com>
7#         source@mvista.com
8#
9# Copyright 2005 MontaVista Software Inc.
10#
11#  This program is free software; you can redistribute it and/or
12#  modify it under the terms of the GNU Lesser General Public License
13#  as published by the Free Software Foundation; either version 2 of
14#  the License, or (at your option) any later version.
15#
16#
17#  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20#  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22#  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23#  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24#  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25#  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26#  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28#  You should have received a copy of the GNU Lesser General Public
29#  License along with this program; if not, write to the Free
30#  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31#
32try:
33    import Tix
34except:
35    import tkinter
36    from tkinter import tix as Tix
37
38import OpenIPMI
39from openipmigui import _saveprefs
40from openipmigui import _oi_logging
41from openipmigui import gui_domainDialog
42from openipmigui import gui_errstr
43from openipmigui import gui_cmdwin
44from openipmigui import gui_list
45from openipmigui import gui_popup
46from openipmigui import gui_winsys
47
48init_treenamewidth = 150
49init_sashposition = 400
50init_isashposition = 300
51init_bsashposition = 350
52init_windowwidth = 800
53init_windowheight = 700
54init_logevents = False
55init_fullevents = False
56init_impt_objs = [ ]
57
58refresh_timer_time = 10000
59
60class IPMITreeDummyItem:
61    def __init__(self, treestr):
62        self.treestr = treestr
63        return
64
65    pass
66
67class IPMICloser:
68    def __init__(self, ui, count):
69        self.ui = ui
70        self.count = count
71        return
72
73    def domain_cb(self, domain):
74        domain.close(self)
75        return
76
77    def domain_close_done_cb(self):
78        self.count = self.count - 1
79        return
80
81    def wait_done(self):
82        while (self.count > 0):
83            OpenIPMI.wait_io(1000)
84            pass
85        self.ui.mainhandler.init_history = self.ui.cmdwindow.history
86        return
87
88    pass
89
90class ImptObj:
91    def __init__(self, gui, type, name, obj):
92        self.gui = gui
93        self.type = type
94        self.name = name
95        self.obj = obj
96        return
97
98    def HandleMenu(self, event, key, point):
99        data = self.obj
100        if (data != None) and (hasattr(data, "HandleMenu")):
101            data.HandleMenu(event)
102            pass
103        else:
104            menul = [ [ "Remove from watch values", self.remove_impt ] ]
105            gui_popup.popup(self.gui, event, menul)
106        return
107
108    def remove_impt(self, event):
109        self.gui.remove_impt_data(self)
110        return
111
112    pass
113
114class IPMIGUI(Tix.Frame):
115    def __init__(self, top, mainhandler):
116        Tix.Frame.__init__(self, top, bd=2, relief=Tix.RAISED)
117
118        self.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
119
120        self.top = top
121
122        self.mainhandler = mainhandler
123
124        self.inactive_style = Tix.DisplayStyle(Tix.TEXT, fg="dark grey",
125                                               selectforeground="dark grey",
126                                               selectbackground="beige",
127                                               refwindow=top)
128        self.active_style = Tix.DisplayStyle(Tix.TEXT, fg="black",
129                                             selectforeground="black",
130                                             selectbackground="beige",
131                                             refwindow=top)
132        self.critical_style = Tix.DisplayStyle(Tix.TEXT, fg="blue",
133                                               selectforeground="blue",
134                                               selectbackground="beige",
135                                               refwindow=top)
136        self.severe_style = Tix.DisplayStyle(Tix.TEXT, fg="red",
137                                             selectforeground="red",
138                                             selectbackground="beige",
139                                             refwindow=top)
140        self.warn_style = Tix.DisplayStyle(Tix.TEXT, fg="burlywood4",
141                                           selectforeground="burlywood4",
142                                           selectbackground="beige",
143                                           refwindow=top)
144
145        self.logeventsv = Tix.IntVar()
146        self.logeventsv.set(init_logevents)
147        self.logevents = init_logevents
148        self.fulleventsv = Tix.IntVar()
149        self.fulleventsv.set(init_fullevents)
150        OpenIPMI.cmdlang_set_evinfo(self.fulleventsv.get())
151
152        fileb = Tix.Menubutton(self, text="File", underline=0, takefocus=0)
153        filemenu = Tix.Menu(fileb, tearoff=0)
154        fileb["menu"] = filemenu
155        filemenu.add_command(label="Exit", underline=1, accelerator="Ctrl+Q",
156                             command = lambda self=self: self.quit() )
157        top.bind_all("<Control-Q>", self.quit)
158        top.bind_all("<Control-q>", self.quit)
159        filemenu.add_command(label="Open Domain", underline=1,
160                             accelerator="Ctrl+O",
161                             command = lambda self=self: self.openDomain() )
162        top.bind_all("<Control-O>", self.openDomain)
163        top.bind_all("<Control-o>", self.openDomain)
164        filemenu.add_command(label="Save Prefs", underline=1,
165                             accelerator="Ctrl+S",
166                             command = lambda self=self: self.savePrefs() )
167        top.bind_all("<Control-S>", self.savePrefs)
168        top.bind_all("<Control-s>", self.savePrefs)
169
170        viewb = Tix.Menubutton(self, text="View", underline=0, takefocus=0)
171        viewmenu = Tix.Menu(viewb, tearoff=0)
172        viewb["menu"] = viewmenu
173        viewmenu.add_command(label="Expand All", underline=1,
174                             accelerator="Ctrl+E",
175                             command = lambda self=self: self.ExpandAll() )
176        top.bind_all("<Control-E>", self.ExpandAll)
177        top.bind_all("<Control-e>", self.ExpandAll)
178        viewmenu.add_command(label="Collapse All", underline=1,
179                             accelerator="Ctrl+C",
180                             command = lambda self=self: self.CollapseAll() )
181        top.bind_all("<Control-C>", self.CollapseAll)
182        top.bind_all("<Control-c>", self.CollapseAll)
183
184        setb = Tix.Menubutton(self, text="Settings", underline=0, takefocus=0)
185        viewmenu = Tix.Menu(setb, tearoff=0)
186        setb["menu"] = viewmenu
187        viewmenu.add_checkbutton(label="Enable Events", underline=0,
188                                 command=lambda w=self: w.EnableEvents(),
189                                 variable=self.logeventsv)
190        viewmenu.add_checkbutton(label="Full Event Info", underline=0,
191                                 command=lambda w=self: w.FullEventInfo(),
192                                 variable=self.fulleventsv)
193
194        vpane = Tix.PanedWindow(self, orientation="vertical",
195                                width=init_windowwidth,
196                                height=init_windowheight)
197        self.vpane = vpane
198        objevpane = vpane.add("objectsevents", size=init_sashposition)
199        imptobjpane = vpane.add("importantobjects",
200                                size = init_isashposition - init_sashposition)
201        cmdpane = vpane.add("command")
202        hpane = Tix.PanedWindow(objevpane, orientation="horizontal")
203        self.hpane = hpane
204        objpane = hpane.add("objects", size=init_bsashposition)
205        evpane = hpane.add("events")
206
207        self.tree = Tix.Tree(objpane, options="hlist.columns 2")
208        # FIXME: This doesn't work, and I don't know why
209        self.tree.hlist.configure(selectbackground="beige")
210        self.tree.hlist.add("D", itemtype=Tix.TEXT, text="Domains")
211        self.tree.setmode("D", "none")
212        self.treedata = { }
213        self.treedata["D"] = IPMITreeDummyItem("D")
214        self.setup_item("D", active=True)
215        self.tree.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
216        self.tree.hlist.bind("<Button-3>", self.TreeMenu)
217
218        self.tree.hlist.bind("<MouseWheel>", self.Wheel)
219        if (gui_winsys.winsys == "x11"):
220            self.tree.hlist.bind("<Button-4>", self.ButtonUp)
221            self.tree.hlist.bind("<Button-5>", self.ButtonDown)
222            pass
223
224        self.numloglines = 1
225        self.maxloglines = 1000
226        self.logwindow = Tix.ScrolledText(evpane)
227        self.logwindow.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
228        self.logwindow.text.insert("end", "GUI Log Window")
229
230        self.imptobjs = gui_list.SubList(imptobjpane,
231                                         ( ("Type", 50),
232                                           ("Name", 200),
233                                           ("Data", 200) ),
234                                         options=("hlist.header 1"
235                                                  + " hlist.itemtype text"
236                                                  + " hlist.columns 3"
237                                                  + " hlist.selectForeground black"
238                                                  + " hlist.selectBackground beige"),
239                                         width=0, height=0)
240        self.imptobjs.pack(fill=Tix.BOTH, expand=1)
241
242        self.errstr = gui_errstr.ErrStr(cmdpane)
243        self.errstr.pack(side=Tix.TOP, fill=Tix.X, expand=1)
244
245        self.cmdwindow = gui_cmdwin.CommandWindow(cmdpane, self)
246        self.cmdwindow.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
247
248        hpane.pack(side=Tix.TOP, fill=Tix.BOTH, expand=1)
249
250        vpane.pack(side=Tix.BOTTOM, fill=Tix.BOTH, expand=1)
251        fileb.pack(side=Tix.LEFT)
252        viewb.pack(side=Tix.LEFT)
253        setb.pack(side=Tix.LEFT)
254
255        self.itemval = 0
256
257        self.in_destroy = False
258
259        self.bind("<Destroy>", self.OnDestroy)
260
261        self.impt_objs = { }
262        self.impt_objs["control"] = { }
263        self.impt_objs["sensor"] = { }
264        self.impt_objs["entity"] = { }
265
266        self.last_scan = None
267        self.timer_timeout_ms = 200
268        top.after(self.timer_timeout_ms, self.Timeout)
269
270        for i in init_impt_objs:
271            self.add_impt_data(i[0], i[1])
272            pass
273        return
274
275    def Wheel(self, event):
276        self.tree.hlist.yview("scroll", -int(event.delta / 20), "units")
277        return
278
279    def ButtonUp(self, event):
280        event.delta = 120
281        self.Wheel(event);
282        return
283
284    def ButtonDown(self, event):
285        event.delta = -120
286        self.Wheel(event);
287        return
288
289    def ReportError(self, str):
290        if (self.in_destroy):
291            return
292        self.errstr.SetError(str)
293        return
294
295    def find_impt_data(self, type, name):
296        s = self.impt_objs[type]
297        if name in s:
298            return s[name]
299        return None
300
301    def add_impt_data(self, type, name, obj=None):
302        if name in self.impt_objs[type]:
303            return
304        i = ImptObj(self, type, name, obj)
305        self.impt_objs[type][name] = i
306        i.key = self.imptobjs.Append(type, (name, ""), data=i)
307        if (obj != None):
308            obj.impt_data = i;
309            self.setup_impt_data(obj.impt_data, obj)
310            pass
311        else:
312            self.imptobjs.SetColumnStyle(i.key, 0, self.inactive_style)
313        return
314
315    def setup_impt_data(self, data, obj):
316        data.obj = obj
317        self.set_impt_active_change(obj)
318        self.imptobjs.SetColumnStyle(obj.impt_data.key, 0, self.active_style)
319        self.set_impt_data_text(obj)
320        return
321
322    def cleanup_impt_data(self, obj):
323        self.imptobjs.SetColumnStyle(obj.impt_data.key, 1,
324                                     self.inactive_style)
325        self.imptobjs.SetColumnStyle(obj.impt_data.key, 0, self.inactive_style)
326        self.imptobjs.SetColumn(obj.impt_data.key, 2, "")
327        obj.impt_data.obj = None
328        return
329
330    def set_impt_style(self, obj, style):
331        self.imptobjs.SetColumnStyle(obj.impt_data.key, 1, style)
332        return
333
334    def set_impt_active_change(self, obj):
335        if (obj.active):
336            self.imptobjs.SetColumnStyle(obj.impt_data.key, 1,
337                                         self.active_style)
338            pass
339        else:
340            self.imptobjs.SetColumnStyle(obj.impt_data.key, 1,
341                                         self.inactive_style)
342            pass
343        return
344
345    def set_impt_data_text(self, obj):
346        if (obj.itemvalue != None):
347            self.imptobjs.SetColumn(obj.impt_data.key, 2, obj.itemvalue)
348            pass
349        else:
350            self.imptobjs.SetColumn(obj.impt_data.key, 2, "")
351            pass
352        return
353
354    def remove_impt_data(self, data):
355        obj = data.obj
356        self.imptobjs.DelItem(data.key);
357        del self.impt_objs[data.type][data.name]
358        if (obj != None):
359            obj.impt_data = None
360            pass
361        return
362
363    def Timeout(self):
364        if (self.in_destroy):
365            return
366        callcount = 0
367        checkcount = 0
368        if (self.last_scan != None):
369            next = self.last_scan
370        else:
371            # Scan important objects first
372            next = self.tree.hlist.info_next("D")
373            for i in self.impt_objs.values():
374                for j in i.values():
375                    if (j.obj != None) and hasattr(j.obj, "DoUpdate"):
376                        callcount = callcount + 1
377                        j.obj.DoUpdate()
378                        pass
379                    checkcount = checkcount + 1
380                    pass
381                pass
382            pass
383        while (callcount < 100) and (checkcount < 1000) and (next != ""):
384            if (self.tree.hlist.info_hidden(next) == "1"):
385                # Not on the screen, ignore it
386                next = self.tree.hlist.info_next(next)
387                continue
388            data = self.treedata[next]
389            if (data != None) and (hasattr(data, "DoUpdate")):
390                callcount = callcount + 1
391                data.DoUpdate()
392                pass
393            next = self.tree.hlist.info_next(next)
394            checkcount = checkcount + 1
395            pass
396
397        if (next != ""):
398            self.last_scan = next
399            self.top.after(self.timer_timeout_ms, self.Timeout)
400        else:
401            self.last_scan = None
402            self.top.after(refresh_timer_time, self.Timeout)
403            pass
404
405        return
406
407    def quit(self, event=None):
408        self.mainhandler.destroy()
409        return
410
411    def OnDestroy(self, event):
412        self.in_destroy = True
413        self.closecount = len(self.mainhandler.domains)
414        closer = IPMICloser(self, self.closecount)
415        ds = list(self.mainhandler.domains.values())
416        for v in ds:
417            v.domain_id.to_domain(closer)
418            pass
419        closer.wait_done()
420        return
421
422    def openDomain(self, event=None):
423        dialog = gui_domainDialog.OpenDomainDialog(self.mainhandler)
424        return
425
426    def savePrefs(self, event=None):
427        self.mainhandler.savePrefs()
428        return
429
430    def ExpandItem(self, item):
431        children = self.tree.hlist.info_children(item)
432        for child in children:
433            self.tree.open(child)
434            self.ExpandItem(child)
435            pass
436        return
437
438    def ExpandAll(self, event=None):
439        self.tree.open("D")
440        self.ExpandItem("D")
441        return
442
443    def CollapseItem(self, item):
444        children = self.tree.hlist.info_children(item)
445        for child in children:
446            self.tree.close(child)
447            self.ExpandItem(child)
448            pass
449        return
450
451    def CollapseAll(self, event=None):
452        self.CollapseItem("D")
453        return
454
455    def EnableEvents(self, event=None):
456        self.logevents = self.logeventsv.get() != 0
457        print("logevents = " + str(self.logevents))
458        return
459
460    def FullEventInfo(self, event=None):
461        print("fullevents = " + str(self.fulleventsv.get()))
462        OpenIPMI.cmdlang_set_evinfo(self.fulleventsv.get())
463        return
464
465    def new_log(self, log):
466        if (self.in_destroy):
467            return
468        # If we are at the bottom, then scroll the window, otherwise
469        # don't do any scrolling
470        (top, bottom) = self.logwindow.text.yview()
471        doscroll = bottom == 1.0
472        self.numloglines += log.count("\n") + 1
473        self.logwindow.text.insert("end", "\n" + log)
474        overrun = self.numloglines - self.maxloglines
475        if (overrun > 0):
476            self.logwindow.text.delete("1.0", str(overrun+1)+".0")
477            self.numloglines -= overrun
478            pass
479        if (doscroll):
480            self.logwindow.text.see("end")
481        return
482
483    def setup_item(self, item, active=False, type = None):
484        data = self.treedata[item]
485        data.active = active
486        data.num_warning = 0
487        data.num_severe = 0
488        data.num_critical = 0
489        data.itemvalue = None
490        if (type != None):
491            data.impt_data = self.find_impt_data(type, data.name_str)
492            if (data.impt_data != None):
493                self.setup_impt_data(data.impt_data, data)
494                pass
495            pass
496        else:
497            data.impt_data = None
498            pass
499        self.tree.hlist.item_create(item, 1, itemtype=Tix.TEXT, text="",
500                                    style=self.active_style)
501        if (not active):
502            self.tree.hlist.item_configure(item, 0, style=self.inactive_style)
503            pass
504        else:
505            self.tree.hlist.item_configure(item, 0, style=self.active_style)
506            pass
507        return
508
509    def cleanup_item(self, item):
510        if (self.in_destroy):
511            return
512        data = self.treedata[item]
513        if (data == None):
514            return
515        if (data.impt_data != None):
516            self.cleanup_impt_data(data)
517            pass
518        parent = self.parent_item(item)
519        if (parent == None):
520            return
521        while (data.num_warning > 0):
522            data.num_warning = data.num_warning - 1;
523            self.decr_item_warning(parent);
524            pass
525        while (data.num_severe > 0):
526            data.num_severe = data.num_severe - 1;
527            self.decr_item_severe(parent);
528            pass
529        while (data.num_critical > 0):
530            data.num_critical = data.num_critical - 1;
531            self.decr_item_critical(parent);
532            pass
533        return
534
535    def add_domain(self, d):
536        if (self.in_destroy):
537            return
538        d.name_str = str(d)
539        item = "D." + str(self.itemval)
540        self.itemval += 1
541        d.treeroot = item
542        self.tree.hlist.add(d.treeroot, itemtype=Tix.TEXT, text=d.name_str)
543        self.tree.setmode(d.treeroot, "open")
544        self.tree.close(d.treeroot)
545        self.treedata[d.treeroot] = d
546        self.setup_item(d.treeroot, active=True)
547
548        lstr = d.treeroot + ".E"
549        self.tree.hlist.add(lstr, itemtype=Tix.TEXT, text="Entities")
550        self.tree.setmode(lstr, "none")
551        self.tree.close(lstr)
552        self.tree.hlist.hide_entry(lstr)
553        self.treedata[lstr] = IPMITreeDummyItem(lstr)
554        self.setup_item(lstr, active=True)
555
556        lstr = d.treeroot + ".M"
557        self.tree.hlist.add(lstr, itemtype=Tix.TEXT, text="MCs")
558        self.tree.setmode(lstr, "none")
559        self.tree.close(lstr)
560        self.tree.hlist.hide_entry(lstr)
561        self.treedata[lstr] = IPMITreeDummyItem(lstr)
562        self.setup_item(lstr, active=True)
563
564        lstr = d.treeroot + ".C"
565        self.tree.hlist.add(lstr, itemtype=Tix.TEXT, text="Connections")
566        self.tree.setmode(lstr, "none")
567        self.tree.close(lstr)
568        self.tree.hlist.hide_entry(lstr)
569        self.treedata[lstr] = IPMITreeDummyItem(lstr)
570        self.setup_item(lstr, active=True)
571
572        return
573
574    def item_sethide(self, parent, item):
575        mode = self.tree.getmode(parent)
576        if (mode == "open"):
577            self.tree.hlist.hide_entry(item)
578        elif (mode == "close"):
579            pass
580        else:
581            self.tree.setmode(parent, "open")
582            self.tree.hlist.hide_entry(item)
583            pass
584        return
585
586    def prepend_item(self, o, name, value, data=None):
587        if (self.in_destroy):
588            return
589        item = o.treeroot + '.' + str(self.itemval)
590        if (data == None):
591            data = IPMITreeDummyItem(item)
592            pass
593        data.name_str = name
594        self.itemval += 1
595        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=name + ":", at=0)
596        mode = self.tree.getmode(o.treeroot)
597        self.item_sethide(o.treeroot, item)
598        if (value == None):
599            self.tree.hlist.item_create(item, 1, itemtype=Tix.TEXT, text="",
600                                        style=self.active_style)
601            self.tree.hlist.item_configure(item, 0, style=self.inactive_style)
602        else:
603            self.tree.hlist.item_create(item, 1, itemtype=Tix.TEXT, text=value,
604                                        style=self.active_style)
605            self.tree.hlist.item_configure(item, 0, style=self.active_style)
606            pass
607        self.treedata[item] = data
608        return item
609
610    def append_item(self, o, name, value, data=None, parent=None):
611        if (self.in_destroy):
612            return
613        if (parent == None):
614            parent = o.treeroot
615            pass
616        item = parent + '.' + str(self.itemval)
617        if (data == None):
618            data = IPMITreeDummyItem(item)
619            pass
620        data.name_str = name
621        self.itemval += 1
622        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=name + ":")
623        mode = self.tree.getmode(parent)
624        if (mode == "open"):
625            self.tree.hlist.hide_entry(item)
626        elif (mode == "close"):
627            pass
628        else:
629            self.tree.setmode(parent, "open")
630            self.tree.hlist.hide_entry(item)
631            pass
632        if (value == None):
633            self.tree.hlist.item_create(item, 1, itemtype=Tix.TEXT, text="",
634                                        style=self.active_style)
635            self.tree.hlist.item_configure(item, 0, style=self.inactive_style)
636        else:
637            self.tree.hlist.item_create(item, 1, itemtype=Tix.TEXT, text=value,
638                                        style=self.active_style)
639            self.tree.hlist.item_configure(item, 0, style=self.active_style)
640            pass
641        self.treedata[item] = data
642        return item
643
644    def set_item_text(self, item, value):
645        if (self.in_destroy):
646            return
647        data = self.treedata[item]
648        data.itemvalue = value
649        if (hasattr(data, "impt_data") and (data.impt_data != None)):
650            self.set_impt_data_text(data)
651            pass
652        if (value == None):
653            self.tree.hlist.item_configure(item, 1, text="")
654            self.tree.hlist.item_configure(item, 0, style=self.inactive_style)
655            pass
656        else:
657            self.tree.hlist.item_configure(item, 1, text=value)
658            if (hasattr(data, "active")):
659                if (data.active):
660                    self.set_item_color(item)
661                    pass
662                pass
663            else:
664                self.tree.hlist.item_configure(item, 0, style=self.active_style)
665                pass
666            pass
667        return
668
669    def set_item_inactive(self, item):
670        if (self.in_destroy):
671            return
672        data = self.treedata[item]
673        data.active = False
674        if (hasattr(data, "impt_data") and (data.impt_data != None)):
675            self.set_impt_active_change(data)
676            pass
677        self.tree.hlist.item_configure(item, 0, style=self.inactive_style)
678        return
679
680    def set_item_active(self, item):
681        if (self.in_destroy):
682            return
683        data = self.treedata[item]
684        data.active = True
685        self.set_item_color(item)
686        return
687
688    def parent_item(self, item):
689        idx = item.rfind(".")
690        if (idx == -1):
691            return None
692        return item[0:idx]
693
694    def set_item_color(self, item):
695        data = self.treedata[item]
696        if (data.num_critical > 0):
697            style = self.critical_style
698        elif (data.num_severe > 0):
699            style=self.severe_style
700        elif (data.num_warning > 0):
701            style=self.warn_style
702        else:
703            style=self.active_style
704            pass
705        if (hasattr(data, "impt_data") and (data.impt_data != None)):
706            self.set_impt_style(data, style)
707            pass
708        self.tree.hlist.item_configure(item, 0, style=style)
709        return
710
711    def incr_item_warning(self, item):
712        if (self.in_destroy):
713            return
714        data = self.treedata[item]
715        if (data == None):
716            return
717        parent = self.parent_item(item)
718        if (parent != None):
719           self.incr_item_warning(parent);
720           pass
721        data.num_warning = data.num_warning + 1
722        if (not data.active):
723            return
724        if (data.num_critical > 0):
725            return
726        if (data.num_severe > 0):
727            return
728        if (data.num_warning == 1):
729            self.tree.hlist.item_configure(item, 0, style=self.warn_style)
730            pass
731        return
732
733    def decr_item_warning(self, item):
734        if (self.in_destroy):
735            return
736        data = self.treedata[item]
737        if (data == None):
738            return
739        parent = self.parent_item(item)
740        if (parent != None):
741           self.decr_item_warning(parent);
742           pass
743        data.num_warning = data.num_warning - 1
744        if (not data.active):
745            return
746        if (data.num_critical > 0):
747            return
748        if (data.num_severe > 0):
749            return
750        if (data.num_warning > 0):
751            return
752        self.tree.hlist.item_configure(item, 0, style=self.active_style)
753        return
754
755    def incr_item_severe(self, item):
756        if (self.in_destroy):
757            return
758        data = self.treedata[item]
759        if (data == None):
760            return
761        parent = self.parent_item(item)
762        if (parent != None):
763           self.incr_item_severe(parent);
764           pass
765        data.num_severe = data.num_severe + 1
766        if (not data.active):
767            return
768        if (data.num_critical > 0):
769            return
770        if (data.num_severe == 1):
771            self.tree.hlist.item_configure(item, 0, style=self.severe_style)
772            pass
773        return
774
775    def decr_item_severe(self, item):
776        if (self.in_destroy):
777            return
778        data = self.treedata[item]
779        if (data == None):
780            return
781        parent = self.parent_item(item)
782        if (parent != None):
783           self.decr_item_severe(parent);
784           pass
785        data.num_severe = data.num_severe - 1
786        if (not data.active):
787            return
788        if (data.num_critical > 0):
789            return
790        if (data.num_severe > 0):
791            return
792        if (data.num_warning > 0):
793            self.tree.hlist.item_configure(item, 0, style=self.warn_style)
794            return
795        self.tree.hlist.item_configure(item, 0, style=self.active_style)
796        return
797
798    def incr_item_critical(self, item):
799        if (self.in_destroy):
800            return
801        data = self.treedata[item]
802        if (data == None):
803            return
804        parent = self.parent_item(item)
805        if (parent != None):
806           self.incr_item_critical(parent);
807           pass
808        data.num_critical = data.num_critical + 1
809        if (not data.active):
810            return
811        if (data.num_critical == 1):
812            self.tree.hlist.item_configure(item, 0, style=self.critical_style)
813            pass
814        return
815
816    def decr_item_critical(self, item):
817        if (self.in_destroy):
818            return
819        data = self.treedata[item]
820        if (data == None):
821            return
822        parent = self.parent_item(item)
823        if (parent != None):
824           self.decr_item_critical(parent);
825           pass
826        data.num_critical = data.num_critical - 1
827        if (not data.active):
828            return
829        if (data.num_critical > 0):
830            return
831        if (data.num_severe > 0):
832            self.tree.hlist.item_configure(item, 0, style=self.severe_style)
833            return
834        if (data.num_warning > 0):
835            self.tree.hlist.item_configure(item, 0, style=self.warn_style)
836            return
837        self.tree.hlist.item_configure(item, 0, style=self.active_style)
838        return
839
840    def TreeMenu(self, event):
841        w = event.widget
842        item = w.nearest(event.y)
843        data = self.treedata[item]
844        if (data != None) and (hasattr(data, "HandleMenu")):
845            data.HandleMenu(event)
846            pass
847        return
848
849    def TreeExpanded(self, event):
850        item = event.GetItem()
851        data = self.tree.GetPyData(item)
852        if (data != None) and (hasattr(data, "HandleExpand")):
853            data.HandleExpand(event)
854            pass
855        return
856
857    def remove_domain(self, d):
858        if (self.in_destroy):
859            return
860        if (hasattr(d, "treeroot")):
861            self.cleanup_item(d.treeroot)
862            self.tree.hlist.delete_entry(d.treeroot)
863            pass
864        return
865
866    def add_connection(self, d, c):
867        if (self.in_destroy):
868            return
869        parent = d.treeroot + ".C"
870        item = parent + '.' + str(self.itemval)
871        self.itemval += 1
872        c.treeroot = item
873        c.name_str = str(c)
874        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=c.name_str)
875        self.tree.setmode(item, "none")
876        self.tree.close(item)
877        self.item_sethide(parent, item)
878        self.treedata[item] = c
879        self.setup_item(item, active=True)
880        return
881
882    def add_port(self, c, p):
883        if (self.in_destroy):
884            return
885        item = c.treeroot + '.' + str(self.itemval)
886        self.itemval += 1
887        p.treeroot = item
888        p.name_str = str(p)
889        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=p.name_str)
890        self.tree.setmode(item, "none")
891        self.tree.close(item)
892        self.item_sethide(c.treeroot, item)
893        self.treedata[item] = p
894        self.setup_item(item, active=True)
895        return
896
897    def remove_port(self, p):
898        if (self.in_destroy):
899            return
900        if (hasattr(p, "treeroot")):
901            self.cleanup_item(p.treeroot)
902            self.tree.hlist.delete_entry(p.treeroot)
903            del self.treedata[p.treeroot]
904            pass
905        return
906
907    def add_entity(self, d, e, parent=None):
908        if (self.in_destroy):
909            return
910        if (parent == None):
911            parent = d.treeroot + ".E"
912            pass
913        else:
914            parent = parent.treeroot
915            pass
916        e.name_str = str(e)
917        item = parent + '.' + str(self.itemval)
918        self.itemval += 1
919        e.treeroot = item
920        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=e.name_str)
921        self.tree.setmode(item, "open")
922        self.tree.close(item)
923        self.item_sethide(parent, item)
924        self.treedata[item] = e
925        self.setup_item(item, type="entity")
926
927        lstr = item + ".S"
928        self.tree.hlist.add(lstr, itemtype=Tix.TEXT, text="Sensors")
929        self.tree.setmode(lstr, "none")
930        self.tree.close(lstr)
931        self.tree.hlist.hide_entry(lstr)
932        self.treedata[lstr] = IPMITreeDummyItem(lstr)
933        self.setup_item(lstr, active=True)
934
935        lstr = item + ".C"
936        self.tree.hlist.add(lstr, itemtype=Tix.TEXT, text="Controls")
937        self.tree.setmode(lstr, "none")
938        self.tree.close(lstr)
939        self.tree.hlist.hide_entry(lstr)
940        self.treedata[lstr] = IPMITreeDummyItem(lstr)
941        self.setup_item(lstr, active=True)
942        return
943
944    def reparent_entity(self, d, e, parent):
945        if (self.in_destroy):
946            return
947        self.add_entity(d, e, parent)
948        return
949
950    def remove_entity(self, e):
951        if (self.in_destroy):
952            return
953        if (hasattr(e, "treeroot")):
954            self.cleanup_item(e.treeroot)
955            self.tree.hlist.delete_entry(e.treeroot)
956            del self.treedata[e.treeroot]
957            pass
958        return
959
960    def add_mc(self, d, m):
961        if (self.in_destroy):
962            return
963        parent = d.treeroot + ".M"
964        m.name_str = str(m)
965        item = parent + "." + str(self.itemval)
966        self.itemval += 1
967        m.treeroot = item
968        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=m.name_str)
969        self.tree.setmode(item, "none")
970        self.tree.close(item)
971        self.item_sethide(parent, item)
972        self.treedata[item] = m
973        self.setup_item(item)
974        return
975
976    def remove_mc(self, m):
977        if (self.in_destroy):
978            return
979        if (hasattr(m, "treeroot")):
980            self.cleanup_item(m.treeroot)
981            self.tree.hlist.delete_entry(m.treeroot)
982            del self.treedata[m.treeroot]
983            pass
984        return
985
986    def add_sensor(self, e, s):
987        if (self.in_destroy):
988            return
989        parent = e.treeroot + ".S"
990        s.name_str = str(s)
991        item = parent + "." + str(self.itemval)
992        self.itemval += 1
993        s.treeroot = item
994        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=s.name_str)
995        self.tree.setmode(item, "none")
996        self.tree.close(item)
997        self.item_sethide(parent, item)
998        self.treedata[item] = s
999        self.setup_item(item, active=True, type="sensor")
1000        return
1001
1002    def remove_sensor(self, s):
1003        if (self.in_destroy):
1004            return
1005        if (hasattr(s, "treeroot")):
1006            self.cleanup_item(s.treeroot)
1007            self.tree.hlist.delete_entry(s.treeroot)
1008            del self.treedata[s.treeroot]
1009            pass
1010        return
1011
1012    def add_control(self, e, c):
1013        if (self.in_destroy):
1014            return
1015        parent = e.treeroot + ".C"
1016        c.name_str = str(c)
1017        item =  parent + "." + str(self.itemval)
1018        self.itemval += 1
1019        c.treeroot = item
1020        self.tree.hlist.add(item, itemtype=Tix.TEXT, text=c.name_str)
1021        self.tree.setmode(item, "none")
1022        self.tree.close(item)
1023        self.item_sethide(parent, item)
1024        self.treedata[item] = c
1025        self.setup_item(item, active=True, type="control")
1026        return
1027
1028    def remove_control(self, c):
1029        if (self.in_destroy):
1030            return
1031        if (hasattr(c, "treeroot")):
1032            self.cleanup_item(c.treeroot)
1033            self.tree.hlist.delete_entry(c.treeroot)
1034            del self.treedata[c.treeroot]
1035            pass
1036        return
1037
1038    # XML preferences handling
1039    def getTag(self):
1040        return "guiparms"
1041
1042    def SaveInfo(self, doc, elem):
1043        elem.setAttribute("windowwidth", str(self.vpane.winfo_width()))
1044        elem.setAttribute("windowheight", str(self.vpane.winfo_height()))
1045        spos = int(self.vpane.panecget("objectsevents", "-size"))
1046        ipos = int(self.vpane.panecget("importantobjects", "-size"))
1047        elem.setAttribute("sashposition", str(spos))
1048        elem.setAttribute("isashposition", str(spos + ipos))
1049        elem.setAttribute("bsashposition",
1050                          str(self.hpane.panecget("objects", "-size")))
1051        #elem.setAttribute("treenamewidth", str(self.tree.GetColumnWidth(0)))
1052        elem.setAttribute("logevents", str(self.logevents))
1053        elem.setAttribute("fullevents", str(self.fulleventsv != 0))
1054        for i in list(self.impt_objs.values()):
1055            for j in list(i.values()):
1056                o = doc.createElement("watch")
1057                o.setAttribute("type", j.type)
1058                o.setAttribute("name", j.name)
1059                elem.appendChild(o)
1060                pass
1061            pass
1062        return
1063    pass
1064
1065def GetAttrInt(attr, default):
1066    try:
1067        return int(attr.nodeValue)
1068    except Exception as e:
1069        _oi_logging.error("Error getting init parm " + attr.nodeName +
1070                          ": " + str(e))
1071        return default
1072
1073def GetAttrBool(attr, default):
1074    if (attr.nodeValue.lower() == "true") or (attr.nodeValue == "1"):
1075        return True
1076    elif (attr.nodeValue.lower() == "false") or (attr.nodeValue == "0"):
1077        return False
1078    else:
1079        _oi_logging.error ("Error getting init parm " + attr.nodeName)
1080        pass
1081    return default
1082
1083class _GUIRestore(_saveprefs.RestoreHandler):
1084    def __init__(self, mainhandler):
1085        _saveprefs.RestoreHandler.__init__(self, mainhandler, "guiparms")
1086        return
1087
1088    def restore(self, mainhandler, node):
1089        global init_windowheight
1090        global init_windowwidth
1091        global init_sashposition
1092        global init_bsashposition
1093        global init_isashposition
1094        global init_treenamewidth
1095        global init_fullevents
1096        global init_logevents
1097        global init_impt_objs
1098
1099        for i in range(0, node.attributes.length):
1100            attr = node.attributes.item(i)
1101            if (attr.nodeName == "windowwidth"):
1102                init_windowwidth = GetAttrInt(attr, init_windowwidth)
1103            elif (attr.nodeName == "windowheight"):
1104                init_windowheight = GetAttrInt(attr, init_windowheight)
1105            elif (attr.nodeName == "sashposition"):
1106                init_sashposition = GetAttrInt(attr, init_sashposition)
1107            elif (attr.nodeName == "bsashposition"):
1108                init_bsashposition = GetAttrInt(attr, init_bsashposition)
1109            elif (attr.nodeName == "isashposition"):
1110                init_isashposition = GetAttrInt(attr, init_isashposition)
1111            elif (attr.nodeName == "treenamewidth"):
1112                init_treenamewidth = GetAttrInt(attr, init_treenamewidth)
1113            elif (attr.nodeName == "logevents"):
1114                init_logevents = GetAttrBool(attr, init_logevents)
1115            elif (attr.nodeName == "fullevents"):
1116                init_fullevents = GetAttrBool(attr, init_fullevents)
1117                pass
1118            pass
1119        for i in node.childNodes:
1120            if (i.nodeName == "watch"):
1121                name = None
1122                type = None
1123                for j in range(0, i.attributes.length):
1124                    attr = i.attributes.item(j)
1125                    if (attr.nodeName == "name"):
1126                        name = attr.nodeValue
1127                    elif (attr.nodeName == "type"):
1128                        type = attr.nodeValue
1129                    pass
1130                if (name != None) and (type != None):
1131                    init_impt_objs.append( (type, name) )
1132                    pass
1133                pass
1134            pass
1135        return
1136
1137    pass
1138
1139
1140