Package SimPy :: Module GUIDebug |
[hide private]
[frames] | no frames]

# Source Code for Module SimPy.GUIDebug

      1  from Tkinter import *
      2  from SimPy.SimulationStep import now,Globals
      3
      4  # Creates and controls the GUI of the program
      5 -class GUIController(object):
      6
      7 -    def __init__(self):
      8          self.root = Tk()
      9          self.root.withdraw()
     10
     11          self.saveNextEvent()
     12
     13          self.eventWin = EventWindow(self)
     14          self.wlist = []
     15          self.plist = []
     16          self.rlist = []
     17
     18      # Adds a new Window to the GUI
     19 -    def addNewWindow(self,obj,name,hook):
     20          self.wlist += [GenericWindow(obj,hook,self,name)]
     21
     22      # Adds a new Process to the GUI
     23 -    def addNewProcess(self,obj,name,hook):
     24          self.plist += [ProcessWindow(obj,hook,self,name)]
     25
     26      # Adds a new Resource to the GUI
     27 -    def addNewResource(self,obj,name,hook):
     28          self.rlist += [ResourceWindow(obj,hook,self,name)]
     29
     30      # Updates all the windows currently up
     31 -    def updateAllWindows(self):
     32
     33          for w in self.wlist: w.update()
     34          for p in self.plist: p.update()
     35          for r in self.rlist: r.update()
     36          if self.eventWin.window: self.eventWin.update()
     37
     38          self.organizeWindows()
     39
     40          self.saveNextEvent()
     41
     42      # removes all instances of window in lists
     43 -    def removeWindow(self, w):
     44          f = lambda win: win is not w
     45          self.wlist = filter(f,self.wlist)
     46          self.plist = filter(f,self.plist)
     47          self.rlist = filter(f,self.rlist)
     48
     49      # save next event to be run
     50 -    def saveNextEvent(self):
     51          #from SimPy.SimulationTrace import _e
     52
     53          tempList=[]
     54          tempList[:]=Globals.sim._e.timestamps
     55          tempList.sort()
     56
     57          for ev in tempList:
     58
     59              # return only event notices which are not cancelled
     60              if ev[3]: continue
     61
     62              # save next event
     63              self.nextEvent = ev
     64              return
     65
     66          self.nextEvent = (None,None,None,None)
     67
     68 -    def organizeWindows(self):
     69
     70          # event window
     71          eventWindowHeight = 0
     72
     73          # only organize event window only if it exists
     74          if self.eventWin.window:
     75              eventWindowHeight = 40 + 20 * self.eventWin.table.size()
     76              self.eventWin.setWindowSize(500, eventWindowHeight ,20,40)
     77
     78          # generic windows
     79          count = -1
     80
     81          for win in self.wlist:
     82              count += 1
     83
     84              (w,h,x,y) = win.getWindowSize()
     85              win.setWindowSize(w, h, 20, 40 + eventWindowHeight + 40 )
     86
     87              eventWindowHeight += h + 40
     88
     89          # process windows
     90          xCount = -1
     91          yCount = 0
     92
     93          for p in self.plist:
     94              xCount += 1
     95
     96              yCoord = 40 + 150 * xCount
     97              xCoord = 550 + 210 * yCount
     98
     99              p.setWindowSize(200,120, xCoord, yCoord )
    100
    101              if yCoord >= 600:
    102                  xCount = -1
    103                  yCount += 1
    104
    105          # resource windows
    106          count = -1
    107          for r in self.rlist:
    108              count += 1
    109
    110              windowHeight = 0
    111              windowHeight += 20 # capacity title
    112              windowHeight += 105 # empty table sizes
    113
    114              windowHeight += (r.activeT.size() + r.waitT.size()) * 17 # add size for each row
    115
    116              r.setWindowSize(200, windowHeight , 20 + 220 * count , 40 + eventWindowHeight + 40)
    117
    118
    119
    120  # Creates a basic window that shows a user made hook.
    121 -class GenericWindow(object):
    122
    123 -    def __init__(self, obj, hook, guiCtrl, title=None):
    124          self.window = Toplevel()
    125          self.window.protocol("WM_DELETE_WINDOW", self._destroyWindow)
    126          self.obj = obj
    127          self.hook = hook
    128          self.guiCtrl = guiCtrl
    129          if not title:
    130              self.title = "%s%s" % (type(obj),id(obj))
    131          else:
    132              self.title = title
    133          self.initGUI()
    134
    135
    136 -    def setWindowSize(self,w,h,x,y):
    137          newG = "%dx%d+%d+%d" % (w,h,x,y)
    138          self.window.geometry(newG)
    139
    140 -    def setWindowOrigin(self,x,y):
    141          (w,h,xx,yy) = self.getWindowSize()
    142          newG = "%dx%d+%d+%d" % (w,h,x,y)
    143          self.window.geometry(newG)
    144
    145 -    def getWindowSize(self):
    146          g = self.window.geometry()
    147          return [int(i) for i in g.replace('+','x').split('x')]
    148
    149 -    def _destroyWindow(self):
    150          self.window.destroy()
    151          self.window = None
    152          self.guiCtrl.removeWindow(self)
    153
    154      # Creates the window
    155 -    def initGUI(self):
    156          self.window.title(self.title)
    157          txt = self.hook()
    158          if txt != "": txt += '\n'
    159          self.hookTxt = Label(self.window,text=txt,justify=LEFT)
    160          self.hookTxt.pack()
    161
    162      # Updates the window
    163 -    def update(self):
    164          txt = self.hook()
    165          if txt != "": txt += '\n'
    166          self.hookTxt["text"] = txt
    167
    168  # Class that creates the event window for the simulation that
    169  # displays the time and event.
    170 -class EventWindow(GenericWindow):
    171
    172 -    def __init__(self, guiCtrl):
    173          self.window = Toplevel()
    174          self.window.protocol("WM_DELETE_WINDOW", self._destroyWindow)
    175          self.guiCtrl = guiCtrl
    176          self.initGUI()
    177
    178      # Creates the initial window using a two column window with a
    179      # status bar on the bottom
    180 -    def initGUI(self):
    181          self.window.title("Event List")
    182          # Creates the table
    183          self.table = MultiListbox(self.window,(('', 1), ('Time',15),
    184                                     ('Process',20),('Next Line',5)))
    185          # Adds the status bar to display the current simulation time
    186          self.status = StatusBar(self.window)
    187          self.status.pack(side=TOP, fill=X)
    188
    189          self.update()
    190
    191      # Updates the window
    192 -    def update(self):
    193          self.updateETable()
    194          self.updateStatus()
    195
    196      # Updates the status bar
    197 -    def updateStatus(self):
    198          self.status.set("  Current Time: %s",now())
    199
    200      # Updates the table
    201 -    def updateETable(self):
    202          #from SimPy.SimulationStep import _e
    203          self.table.delete(0,self.table.size())
    204
    205          tempList=[]
    206          tempList[:]=Globals.sim._e.timestamps
    207          tempList.sort()
    208
    209          ev = self.guiCtrl.nextEvent
    210
    211          nextLine = 0
    212          if( ev[2] ):
    213              if( ev[2]._nextpoint ):
    214                  nextLine = ev[2]._nextpoint.gi_frame.f_lineno
    215
    216          if ev[0]:
    217              self.table.insert(END,('  >>',
    218                     str(ev[0]), ev[2].name, nextLine ))
    219
    220          count = -1
    221          for ev in tempList:
    222
    223              # return only event notices which are not cancelled
    224              if ev[3]: continue
    225
    226              count += 1
    227
    228              currentEvent = ''
    229              #if count == 0 and now() == ev[0]:
    230              #   currentEvent = '  >>'
    231
    232              nextLine = 0
    233              if( ev[2] ):
    234                  if( ev[2]._nextpoint ):
    235                      nextLine = ev[2]._nextpoint.gi_frame.f_lineno
    236
    237              self.table.insert(END,(currentEvent,
    238                         str(ev[0]), ev[2].name, nextLine ))
    239
    240          self.table.pack(expand=YES,fill=BOTH)
    241
    242  # Creates a Process Window that shows the status, Next Event time,
    243  # if the Process is currently interupted, and an optional user hook.
    244 -class ProcessWindow(GenericWindow):
    245
    246 -    def __init__(self, obj, hook, guiCtrl, name):
    247          self.proc = obj
    248          if name:
    249              obj.name = name
    250          GenericWindow.__init__(self, obj, hook, guiCtrl, "Process")
    251
    252      # Initializes the window
    253 -    def initGUI(self):
    254          Label(self.window,text="%s" % (self.proc.name)).pack()
    255          # Creates the table
    256          self.table = MultiListbox(self.window,((None,10),(None,15)))
    257          self.status = StatusBar(self.window)
    258          self.status.pack(side=BOTTOM, fill=X)
    259
    260          GenericWindow.initGUI(self)
    261          self.setWindowSize(0,0,-1000,-1000)
    262
    263          self.update()
    264
    265      # Updates the window
    266 -    def update(self):
    267
    268          # If the process has been terminated close the window
    269          if self.proc.terminated():
    270              self._destroyWindow()
    271              return
    272
    273          if self.isRunning():
    274              self.status.label["text"] = "Running!"
    275              self.status.label["fg"] = "red"#"green"
    276          else:
    277              self.status.label["text"] = ""
    278              self.status.label["fg"] = "white"
    279
    280          self.table.delete(0,self.table.size())
    281
    282          if self.proc.active() == False:
    283              status = "Passive"
    284          else:
    285              status = "Active"
    286
    287          if self.proc._nextTime:
    288              nextEvent = self.proc._nextTime
    289          else:
    290              nextEvent = ""
    291
    292          if self.proc.interrupted() == True:
    293              interrupted = "True"
    294          else:
    295              interrupted = "False"
    296
    297          self.table.insert(END,("  Status:", status))
    298          self.table.insert(END,("  Next Event:", nextEvent))
    299          self.table.insert(END,("  Interrupted:", interrupted ))
    300
    301          self.table.pack(expand=YES,fill=BOTH)
    302
    303          GenericWindow.update(self)
    304
    305 -    def isRunning(self):
    306          return self.guiCtrl.nextEvent[2] is self.proc
    307
    308  # Creates a Resource Window that displays the capacity, waitQ,
    309  # activeQ and an optional user hook
    310 -class ResourceWindow(GenericWindow):
    311
    312 -    def __init__(self,obj,hook,guiCtrl,name):
    313          self.resource = obj
    314          if name:
    315              obj.name = name
    316          GenericWindow.__init__(self,obj,hook, guiCtrl,"Resource")
    317
    318      # Initializes the window with the two tables for the waitQ and activeQ
    319 -    def initGUI(self):
    320          Label(self.window,text="%s\tCapacity: %d" % (self.resource.name,self.resource.capacity)).pack()
    321
    322          self.activeT = MultiListbox(self.window,(('#',5),('ActiveQ',20)))
    323          self.waitT = MultiListbox(self.window,(('#',5),('WaitQ',20)))
    324          self.updateQTables()
    325
    326          GenericWindow.initGUI(self)
    327          self.setWindowSize(0,0,-1000,-1000)
    328
    329      # Updates the window
    330 -    def update(self):
    331          GenericWindow.update(self)
    332          self.updateQTables()
    333
    334      # Updates the waitQ and activeQ tables
    335 -    def updateQTables(self):
    336          self.activeT.delete(0,END)
    337          self.waitT.delete(0,END)
    338          # Update the activeQ
    339          for i in range(len(self.resource.activeQ)):
    340              col1 = '%d' % (i+1)
    341              col2 = self.resource.activeQ[i].name
    342              self.activeT.insert(END,("   " + col1,col2))
    343          # Update the waitQ
    344          for i in range(len(self.resource.waitQ)):
    345              col1 = '%d' % (i+1)
    346              col2 = self.resource.waitQ[i].name
    347              self.waitT.insert(END,("   " + col1,col2))
    348
    349          self.activeT.pack(expand=YES,fill=BOTH)
    350          self.waitT.pack(expand=YES,fill=BOTH)
    351          self.window.update()
    352
    353  # A class that creates a multilistbox with a scrollbar
    354 -class MultiListbox(Frame):
    355 -    def __init__(self, master, lists):
    356          Frame.__init__(self, master)
    357          self.lists = []
    358          for l,w in lists:
    359              frame = Frame(self); frame.pack(side=LEFT, expand=YES, fill=BOTH)
    360
    361              if l is None:
    362                  None
    363              elif l is '':
    364                  Label(frame, text='', borderwidth=1, relief=FLAT).pack(fill=X)
    365              else:
    366                  Label(frame, text=l, borderwidth=1, relief=SOLID).pack(fill=X)
    367
    368              lb = Listbox(frame, width=w, height=0, borderwidth=0, selectborderwidth=0,
    369                   relief=FLAT, exportselection=FALSE)
    370              lb.pack(expand=YES, fill=BOTH)
    371              self.lists.append(lb)
    372          frame = Frame(self); frame.pack(side=LEFT, fill=Y)
    373          Label(frame, borderwidth=1, relief=RAISED).pack(fill=X)
    374          sb = Scrollbar(frame, orient=VERTICAL, command=self._scroll)
    375          sb.pack(expand=YES, fill=Y)
    376          self.lists[0]['yscrollcommand']=sb.set
    377
    378 -    def _select(self, y):
    379          row = self.lists[0].nearest(y)
    380          self.selection_clear(0, END)
    381          self.selection_set(row)
    382          return 'break'
    383
    384 -    def _button2(self, x, y):
    385          for l in self.lists: l.scan_mark(x, y)
    386          return 'break'
    387
    388 -    def _b2motion(self, x, y):
    389          for l in self.lists: l.scan_dragto(x, y)
    390          return 'break'
    391
    392 -    def _scroll(self, *args):
    393          for l in self.lists:
    394              apply(l.yview, args)
    395
    396 -    def curselection(self):
    397          return self.lists[0].curselection()
    398
    399 -    def delete(self, first, last=None):
    400          for l in self.lists:
    401              l.delete(first, last)
    402
    403 -    def get(self, first, last=None):
    404          result = []
    405          for l in self.lists:
    406              result.append(l.get(first,last))
    407          if last: return apply(map, [None] + result)
    408          return result
    409
    410 -    def index(self, index):
    411          self.lists[0].index(index)
    412
    413 -    def insert(self, index, *elements):
    414          for e in elements:
    415              i = 0
    416              for l in self.lists:
    417                  l.insert(index, e[i])
    418                  i = i + 1
    419
    420 -    def size(self):
    421          return self.lists[0].size()
    422
    423 -    def see(self, index):
    424          for l in self.lists:
    425              l.see(index)
    426
    427 -    def selection_anchor(self, index):
    428          for l in self.lists:
    429              l.selection_anchor(index)
    430
    431 -    def selection_clear(self, first, last=None):
    432          for l in self.lists:
    433              l.selection_clear(first, last)
    434
    435 -    def selection_includes(self, index):
    436          return self.lists[0].selection_includes(index)
    437
    438 -    def selection_set(self, first, last=None):
    439          for l in self.lists:
    440              l.selection_set(first, last)
    441
    442  # Creates a statusbar
    443 -class StatusBar(Frame):
    444
    445 -    def __init__(self, master):
    446          Frame.__init__(self, master)
    447          self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
    448          self.label.pack(fill=X)
    449
    450 -    def set(self, format, *args):
    451          self.label.config(text=format % args)
    452          self.label.update_idletasks()
    453
    454 -    def clear(self):
    455          self.label.config(text="")
    456          self.label.update_idletasks()
    457