/[ascend]/branches/ksenija2/pygtk/observer.py
ViewVC logotype

Annotation of /branches/ksenija2/pygtk/observer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2867 - (hide annotations) (download) (as text)
Mon Mar 23 02:31:01 2015 UTC (7 years, 4 months ago) by jpye
File MIME type: text/x-python
File size: 31628 byte(s)
minor changes to debug output.
comments relating to disused var flags.

1 johnpye 245 import pygtk
2     pygtk.require('2.0')
3     import gtk
4     import pango
5 jpye 1356 import os.path
6 johnpye 245
7 aakash 2494 from study import *
8     from unitsdialog import *
9    
10 johnpye 852 OBSERVER_EDIT_COLOR = "#008800"
11     OBSERVER_NOEDIT_COLOR = "#000088"
12     OBSERVER_NORMAL_COLOR = "black"
13 aakash 2494 OBSERVER_TAINTED_COLOR = "#FFBBBB"
14     OBSERVER_DEAD_COLOR = "#ababab"
15 johnpye 1053 # This code uses the techniques described in
16 johnpye 280 # http://www.daa.com.au/pipermail/pygtk/2006-February/011777.html
17 johnpye 1053 # http://piman.livejournal.com/361173.html
18 johnpye 280
19 johnpye 849 OBSERVER_NUM=0
20    
21 johnpye 1053 class ClickableTreeColumn(gtk.TreeViewColumn):
22     def __init__(self, title="", *args, **kwargs):
23     super(ClickableTreeColumn, self).__init__(None, *args, **kwargs)
24     self.label = gtk.Label("%s" % title)
25     self.label.show()
26     self.set_widget(self.label)
27 aakash 2494 self.title = title
28     #self.set_sort_column_id(0)
29     #self.set_clickable(True)
30 johnpye 1053
31     def do_connect(self):
32     """ Connect the defined 'on_click' method. Note: must be called after
33     this object (ClickableTreeColumn) has been added to the TreeView,
34     eg mytreeview.append_column(col). """
35     button = self.label.get_ancestor(gtk.Button)
36     h = button.connect("clicked",self.on_click)
37     #button.clicked()
38    
39     def on_click(self,widget,*args):
40     print "RECEIVED EVENT"
41    
42 johnpye 849 class ObserverColumn:
43     """
44     A class to identify the instance that relates to a specify column
45     and the units of measurement and column title, etc.
46     """
47 jpye 2836 def __init__(self,instance,index,name=None,units=None,browser=None,eventdata=None):
48 johnpye 849 self.instance = instance
49     self.name = name
50     self.index = index
51    
52     if name==None:
53     if browser == None:
54     name = "UNNAMED"
55     else:
56     name = browser.sim.getInstanceName(instance)
57    
58 jpye 1735 if units is None:
59 johnpye 849 units = instance.getType().getPreferredUnits()
60 jpye 1735 if units is None:
61 johnpye 849 units = instance.getType().getDimensions().getDefaultUnits()
62    
63     uname = str(units.getName())
64 jpye 1387 if len(uname) or uname.find("/")!=-1:
65 johnpye 849 uname = "["+uname+"]"
66    
67     if uname == "":
68     _title = "%s" % (name)
69     else:
70     _title = "%s / %s" % (name, uname)
71    
72     self.title = _title
73     self.units = units
74     self.uname = uname
75     self.name = name
76 jpye 2836 self.eventdata = eventdata
77 johnpye 849
78     def __repr__(self):
79     return "ObserverColumn(name="+self.name+")"
80    
81 sreenatha 2684 def cellvalue(self, column, cell, model, row_iter, user_data=None):
82     _rowobject = model.get_value(row_iter,0)
83 johnpye 849
84 johnpye 852 cell.set_property('editable',False)
85     cell.set_property('weight',400)
86 johnpye 849 try:
87 aakash 2494 if _rowobject.active or _rowobject.dead:
88 johnpye 849 _rawval = self.instance.getRealValue()
89 johnpye 852 if self.instance.getType().isRefinedSolverVar():
90     if self.instance.isFixed():
91     cell.set_property('editable',True)
92     cell.set_property('weight',700)
93     cell.set_property('foreground',OBSERVER_EDIT_COLOR)
94     else:
95     cell.set_property('foreground',OBSERVER_NOEDIT_COLOR)
96 aakash 2494 _dataval = _rawval / self.units.getConversion()
97 johnpye 849 else:
98 johnpye 852 cell.set_property('foreground',OBSERVER_NORMAL_COLOR)
99 aakash 2494 try :
100     _rawval = _rowobject.values[self.index]
101     _dataval = _rawval / self.units.getConversion()
102     except:
103     _dataval = ""
104     if _rowobject.tainted is True:
105     cell.set_property('background', OBSERVER_TAINTED_COLOR)
106 sreenatha 2684 elif _rowobject.dead or user_data == True:
107 aakash 2494 cell.set_property('background', OBSERVER_DEAD_COLOR)
108     cell.set_property('editable', False)
109     else:
110     cell.set_property('background', None)
111 johnpye 856 except IndexError:
112 johnpye 853 _dataval = ""
113 johnpye 849
114     cell.set_property('text', _dataval)
115    
116     class ObserverRow:
117     """
118     Just a container for a vector of values, but with columns that
119     should correspond to those in the Observer object's vector of
120     ObserverColumn objects.
121     """
122 aakash 2494 def __init__(self,values=None,active=True,tainted=False):
123 johnpye 849 if values==None:
124 aakash 2494 values={}
125     self.tainted = tainted
126 johnpye 849 self.values = values
127     self.active = active
128 aakash 2494 self.dead = False
129     self.error_msg = None
130 johnpye 849
131     def make_static(self,table):
132     self.active = False
133 jpye 2598 #print "TABLE COLS:",table.cols
134     #print "ROW VALUES:",self.values
135 aakash 2494 _v = {}
136 johnpye 856 for col in table.cols.values():
137 aakash 2494 _v[col.index] = col.instance.getRealValue()
138 johnpye 856 self.values = _v
139 jpye 2598 #print "Made static, values:",self.values
140 johnpye 849
141 johnpye 852 def get_values(self,table):
142 aakash 2494 vv = {}
143 johnpye 852 if not self.active:
144 jpye 1366 for k,v in table.cols.iteritems():
145 aakash 2494 try:
146     vv[k]=(self.values[v.index]/v.units.getConversion())
147     except:
148     vv[k]=""
149 jpye 1366 return vv
150 johnpye 852 else:
151 aakash 2494 for index, col in table.cols.iteritems():
152     vv[index] = float(col.instance.getRealValue())/col.units.getConversion()
153     return vv
154 johnpye 852
155 johnpye 245 class ObserverTab:
156 johnpye 849
157 aakash 2494 def __init__(self,browser,tab,name=None,alive=True):
158 johnpye 849 global OBSERVER_NUM
159     self.colindex = 0
160     if name==None:
161     OBSERVER_NUM=OBSERVER_NUM+1
162     name = "Observer %d" % OBSERVER_NUM
163     self.name = name
164     self.browser=browser
165 aakash 2494 self.browser.builder.connect_signals(self)
166     self.view = self.browser.builder.get_object('observerview')
167     self.view.set_has_tooltip(True)
168     self.addbutton = self.browser.builder.get_object('add')
169 johnpye 849 self.tab = tab
170     self.alive=alive
171 sreenatha 2684 self.reloaded = False
172 aakash 2494 self.old_path = None
173     self.current_instance = None
174 johnpye 849 if self.alive:
175     self.browser.reporter.reportNote("New observer is 'alive'")
176    
177     self.keptimg = gtk.Image()
178     self.activeimg = gtk.Image()
179 aakash 2494 self.errorimg = gtk.Image()
180 jpye 1356 self.activeimg.set_from_file(os.path.join(browser.options.assets_dir,"active.png"))
181 aakash 2494 self.errorimg.set_from_file(os.path.join(browser.options.assets_dir,"solveerror.png"))
182 johnpye 849 # create PixBuf objects from these?
183     self.rows = []
184 johnpye 852 _store = gtk.TreeStore(object)
185 johnpye 849 self.cols = {}
186 sreenatha 2684 self.tvcols = {}
187     self.renderers = {}
188 johnpye 849
189     # create the 'active' pixbuf column
190     _renderer = gtk.CellRendererPixbuf()
191 johnpye 1053 _col = ClickableTreeColumn("")
192 johnpye 849 _col.pack_start(_renderer,False)
193     _col.set_cell_data_func(_renderer, self.activepixbufvalue)
194 johnpye 1053 self.view.append_column(_col)
195     _col.do_connect()
196 johnpye 849
197 aakash 2494 # get the context menu
198     self.treecontext=self.browser.builder.get_object("observercontext")
199     self.studycolumnmenuitem=self.browser.builder.get_object("study_column")
200     self.unitsmenuitem=self.browser.builder.get_object("units2")
201     self.deleterowmenuitem=self.browser.builder.get_object("delete_row")
202     self.deletecolumnmenuitem=self.browser.builder.get_object("delete_column")
203     self.plotmenuitem=self.browser.builder.get_object("plotmenuitem")
204 jpye 2836 self.columnplotevents=self.browser.builder.get_object("column_plot_events")
205 johnpye 849 # initially there will not be any other columns
206    
207     if self.alive:
208     # for a 'live' Observer, create the 'active' bottom row
209     self.browser.reporter.reportNote("Adding empty row to store")
210 johnpye 852 _row = ObserverRow()
211     self.activeiter = _store.append(None, [_row] )
212     self.rows.append(_row)
213 sreenatha 2684 else:
214     self.activeiter = None
215 johnpye 849
216     self.view.set_model(_store)
217     self.browser.reporter.reportNote("Created observer '%s'" % self.name)
218 aakash 2494
219     _sel = self.view.get_selection()
220     _sel.set_mode(gtk.SELECTION_MULTIPLE)
221 johnpye 849
222     def activepixbufvalue(self,column,cell,model,iter):
223     _rowobject = model.get_value(iter,0)
224     if _rowobject.active:
225     cell.set_property('pixbuf',self.activeimg.get_pixbuf())
226 aakash 2494 elif _rowobject.tainted:
227     cell.set_property('pixbuf',self.errorimg.get_pixbuf())
228 johnpye 849 else:
229     cell.set_property('pixbuf',self.keptimg.get_pixbuf())
230    
231     def on_add_clicked(self,*args):
232     self.do_add_row()
233    
234     def on_clear_clicked(self,*args):
235 aakash 2494 if self.alive is False:
236     self.on_close_observer_clicked()
237     return
238 johnpye 852 _store = self.view.get_model()
239     _store.clear();
240 jpye 1367 self.rows = []
241 aakash 2494 _row = ObserverRow()
242     self.activeiter = _store.append(None, [_row] )
243     self.rows.append(_row)
244 johnpye 849
245 sreenatha 2684 def plot(self,x=None,y=None):
246 jpye 2865 """Create a plot from specified columns in the ObserverTable
247    
248     There will be points for each timestep in the 'samplelist', and also
249     points for each event/boundary-crossing if any occurred.
250     """
251 jpye 1387 import platform
252     import matplotlib
253     matplotlib.use('GTKAgg')
254     import pylab
255     pylab.ioff()
256 sreenatha 2684
257     # nothing provided: use the first and second columns
258 jpye 1387 if x is None or y is None:
259     if len(self.cols)<2:
260     raise Exception("Not enough columns to plot (need 2+)")
261     if x is None:
262     x=self.cols[0]
263     if y is None:
264 sreenatha 2684 y=[self.cols[1]]
265 jpye 1387
266 sreenatha 2684 # if column indices are provided instead of columns, convert them
267 jpye 1387 if x.__class__ is int and x>=0 and x<len(self.cols):
268     x=self.cols[x]
269     if y.__class__ is int and y>=0 and y<len(self.cols):
270 sreenatha 2684 y=[self.cols[y]]
271 jpye 1387
272 aakash 2494 start = None
273     _p = self.browser.prefs
274     _ignore = _p.getBoolPref("PlotDialog", "ignore_error_points", True)
275     r = {}
276 sreenatha 2684 # FIXME this is not nicely written; we need to collapse the follow if/else
277     # cases into a single bit of code.
278 aakash 2494 if _ignore == False:
279 sreenatha 2684 # get all rows, including ones that didn't solve properly
280     for i in range(len(self.rows)):
281 aakash 2494 try:
282     r = self.rows[i].get_values(self)
283 sreenatha 2684 # flag if any row are empty -- no data? FIXME why would that happen?
284     flag = True
285     for j in y:
286     if r[j.index]=="":
287     flag = False
288     break
289     if r[x.index]!="" and flag==True:
290 aakash 2494 if start == None:
291     start = i
292     break
293     except:
294     continue
295     if start == None:
296     self.browser.reporter.reportError("Can't plot, could not get enough points.")
297     return
298 sreenatha 2684 A = pylab.zeros((len(self.rows)-1-start,len(y)+1),'f')
299 aakash 2494 i = 0
300 sreenatha 2684 j = start
301     while j <len(self.rows)-1:
302     r = self.rows[j].get_values(self)
303 aakash 2494 A[i,0]=r[x.index]
304 sreenatha 2684 for k in range(len(y)):
305     A[i,k+1]=r[y[k].index]
306     j+=1
307 aakash 2494 i+=1
308     else:
309 sreenatha 2684 # ignore error points: get just the non-error rows
310 aakash 2494 j = 0
311     k = 0
312 sreenatha 2684 l = 0
313     # count the error-free rows (FIXME: why aren't we just checking the 'tainted' property??)
314 aakash 2494 for i in range(len(self.rows)-1):
315     if self.rows[i].tainted is False:
316     try:
317     r = self.rows[i].get_values(self)
318 sreenatha 2684 flag = True
319     for l in y:
320     if r[l.index]=="":
321     flag = False
322     break
323     if r[x.index]!="" and flag == True:
324 aakash 2494 if start == None:
325     start = i
326     j=0
327     j+=1
328     except:
329     continue
330     if start == None:
331     self.browser.reporter.reportError("Can't plot, could not get enough points.")
332 aakash 2495 return
333 sreenatha 2684 A = pylab.zeros((j,len(y)+1),'f')
334 aakash 2494 while start<len(self.rows)-1:
335     if self.rows[start].tainted is True:
336 aakash 2495 start+=1
337 aakash 2494 continue
338     r = self.rows[start].get_values(self)
339     A[k,0]=r[x.index]
340 sreenatha 2684 for j in range(len(y)):
341     A[k,j+1]=r[y[j].index]
342 aakash 2494 k+=1
343     start+=1
344 jpye 1387
345 sreenatha 2684 fig = pylab.figure()
346    
347     if len(y) == 2:
348     # two y vectors: use two different y axes on one plot
349     ax1 = pylab.subplot(111)
350     # TODO: second y axis label gets cut off?
351     #pylab.axis('auto')
352     ax1.set_xlabel(x.title)
353     ax1.set_ylabel(y[0].title,labelpad=20)
354     l1 = ax1.plot(A[:,0],A[:,1],'-bo',label=y[0].title)
355     ax2 = ax1.twinx()
356     l2 = ax2.plot(A[:,0],A[:,2],'-ro',label=y[1].title)
357     ax2.set_ylabel(y[1].title,labelpad=20)
358 jpye 1387 ax2.yaxis.tick_right()
359 sreenatha 2684 l = l1+l2
360     labels = [i.get_label() for i in l]
361     leg = ax1.legend(l,labels,loc='upper left')
362     leg.get_frame().set_alpha(0.3)
363 jpye 2865 leg.draggable() #doesn't work?
364     #FIXME the events haven't been plotted in this case
365 sreenatha 2684 else :
366 jpye 2865 _colcyc = ['r','g','b','y','m','c']
367     _ncc = len(_colcyc)
368 sreenatha 2684 sharex = None
369     j = 0.83/len(y)
370     for i in range(len(y)):
371     if i == 0:
372     ax = pylab.subplot(len(y),1,i+1)
373     sharex = ax
374     else:
375     ax = pylab.subplot(len(y),1,i+1,sharex=sharex)
376     #ax[i] = fig.add_axes([0.27, 0.08+(i*(j+0.02)), 0.65, j-0.01], **axprops)
377 jpye 2836 if y[i].eventdata:
378 jpye 2865 # FIXME the 'get_values' function used above does unit conversion
379     # but this 'eventdata' (hack!) doesn't do that, which breaks the plots
380     # when there are non-base-SI units used in the Observer.
381 jpye 2836 arrx = []
382     arry = []
383     for _vals in y[i].eventdata:
384 jpye 2865 arry.append(_vals[1])
385 jpye 2836 for _vals in x.eventdata:
386     arrx.append(_vals[1])
387 sreenatha 2684
388 jpye 2866 pylab.plot(A[:,0],A[:,i+1],'-',color=_colcyc[i%_ncc],marker='',lw=2,label=y[i].title)
389 jpye 2865 pylab.plot(arrx,arry,'s',color='black')
390 jpye 2836 else:
391 jpye 2867 pylab.plot(A[:,0],A[:,i+1],'-',color=_colcyc[i%_ncc],marker='o',label=y[i].title)
392 jpye 2836
393 sreenatha 2684 # put the x-axis label only on the last plot
394     if i+1 != len(y):
395     pylab.setp(ax.get_xticklabels(),visible=False)
396     else:
397     ax.set_xlabel(x.title)
398    
399     # only use a y-axis label if it's a single plot, else put legend on each plot
400     if len(y)==1:
401     pylab.ylabel(y[i].title)
402     else:
403     leg = pylab.legend(loc='upper left')
404     leg.get_frame().set_alpha(0.3)
405    
406     # FIXME why can't I drag the legend?
407    
408 jpye 1387 pylab.ion()
409 jpye 2522 pylab.show()
410 jpye 1387
411     def on_plot_clicked(self,*args):
412 jpye 2865 """This is the 'plot' button at the top of the observer tab"""
413 jpye 1387 try:
414 aakash 2494 if len(self.cols)<2:
415     raise Exception("Not enough columns to plot (need 2+)")
416     _plotwin = PlotDialog(self.browser, self)
417     _plot = _plotwin.run()
418     if _plot:
419     self.plot(x=_plotwin.xcol, y=_plotwin.ycol)
420 jpye 1387 except Exception,e:
421     self.browser.reporter.reportError(str(e))
422    
423 johnpye 854 def do_add_row(self,values=None):
424     _store = self.view.get_model()
425 johnpye 849 if self.alive:
426 johnpye 852 _row = ObserverRow()
427     self.rows.append(_row)
428 aakash 2494 if self.activeiter is not None:
429     _oldrow = _store.get_value(self.activeiter,0)
430     _oldrow.make_static(self)
431 johnpye 852 self.activeiter = _store.append(None,[_row])
432     _path = _store.get_path(self.activeiter)
433     _oldpath,_oldcol = self.view.get_cursor()
434     self.view.set_cursor(_path, _oldcol)
435 johnpye 849 else:
436 jpye 2601 _row = ObserverRow(values=values,active=False,tainted=False)
437 johnpye 854 self.rows.append(_row)
438     _store.append(None,[_row])
439 johnpye 894 #self.browser.reporter.reportNote("Added data row")
440 aakash 2494
441 johnpye 852 def on_view_cell_edited(self, renderer, path, newtext, col):
442     # we can assume it's always the self.activeiter that is edited...
443     if col.instance.isFixed():
444     val = float(newtext) * col.units.getConversion()
445     col.instance.setRealValue( val )
446     self.browser.reporter.reportNote("Updated value to %f" % float(newtext))
447     else:
448     self.browser.reporter.reportError("Can't set a FREE variable from the Observer")
449     return
450     self.browser.do_solve_if_auto()
451 johnpye 849
452     def sync(self):
453 johnpye 852 self.view.queue_draw()
454 johnpye 894 #self.browser.reporter.reportNote("SYNC performed")
455 johnpye 849
456 jpye 2836 def add_instance(self,instance,edata=None):
457     _col = ObserverColumn(instance,self.colindex,browser=self.browser,eventdata=edata)
458 aakash 2494
459     # the loop is to ensure that we dont add multiple columns for the same variable
460     for _cols in self.cols:
461     if self.cols[_cols].title == _col.title:
462     del(_col)
463     return
464 johnpye 849 self.cols[self.colindex] = _col
465     self.colindex = self.colindex + 1
466    
467     # create a new column
468     _renderer = gtk.CellRendererText()
469 johnpye 852 _renderer.connect('edited',self.on_view_cell_edited, _col)
470 johnpye 1053 _tvcol = ClickableTreeColumn(_col.title)
471 johnpye 849 _tvcol.pack_start(_renderer,False)
472 sreenatha 2684 self.tvcols[self.colindex-1] = _tvcol
473     self.renderers[self.colindex-1] = _renderer
474 johnpye 849 _tvcol.set_cell_data_func(_renderer, _col.cellvalue)
475     self.view.append_column(_tvcol);
476 johnpye 1053 _tvcol.do_connect()
477 johnpye 888 #self.browser.reporter.reportError("cols = "+str(self.cols))
478 johnpye 849
479 johnpye 852 def copy_to_clipboard(self,clip):
480     _s = []
481     _s.append('\t'.join([_v.title for _k,_v in self.cols.iteritems()]))
482 jpye 1387 #_cf = [_v.units.getConversion() for _k,_v in self.cols.iteritems()]
483 johnpye 852 print "COPYING %d ROWS" % len(self.rows)
484 jpye 1387 #print "CONVERSIONS:",_cf
485 johnpye 852 for _r in self.rows:
486 aakash 2494 _s.append("\t".join(["%s" % _v for _k, _v in _r.get_values(self).iteritems()]))
487 johnpye 852
488     clip.set_text('\n'.join(_s),-1)
489    
490     self.browser.reporter.reportNote("Observer '%s' data copied to clipboard" % self.name)
491 aakash 2494
492     def on_observerview_query_tooltip(self, widget, _x, _y, keyboard_mode, _tooltip):
493     _store = self.view.get_model()
494     _pthinfo = self.view.get_path_at_pos(_x, _y)
495    
496     if _pthinfo is None:
497     return False
498     _path, _col, _cellx, _celly = _pthinfo
499     _temp, = _path
500     if(_temp==0):
501     return False
502     _path = _temp-1,
503    
504     # the folowing is to ensure that the tooltip
505     # gets refreshed for each row
506     if self.old_path == _path:
507     _iter = _store.get_iter(_path)
508     _rowobject = _store.get_value(_iter,0)
509     if _rowobject.error_msg is None:
510     return False
511     _tooltip.set_text(_rowobject.error_msg)
512     return True
513     else:
514     self.old_path = _path
515     return False
516    
517     def set_all_menu_items_sensitive(self):
518     self.unitsmenuitem.set_sensitive(True)
519     self.studycolumnmenuitem.set_sensitive(True)
520     self.plotmenuitem.set_sensitive(True)
521     self.deletecolumnmenuitem.set_sensitive(True)
522 jpye 2836 self.columnplotevents.set_sensitive(True)
523 aakash 2494
524     def on_treeview_event(self,widget,event):
525    
526     _path = None
527     _delete_row = False
528     _contextmenu = False
529    
530     _sel = self.view.get_selection()
531     _model, _rowlist = _sel.get_selected_rows()
532     if event.type==gtk.gdk.KEY_PRESS:
533     _keyval = gtk.gdk.keyval_name(event.keyval)
534     _path, _col = self.view.get_cursor()
535     if _path is not None:
536     if _keyval=='Menu':
537     self.set_all_menu_items_sensitive()
538     _contextmenu = True
539     _button = 3
540     elif _keyval=='Delete' or _keyval=='BackSpace':
541     _delete_row = True
542    
543     elif event.type==gtk.gdk.BUTTON_PRESS:
544     _x = int(event.x)
545     _y = int(event.y)
546     _button = event.button
547     _pthinfo = self.view.get_path_at_pos(_x, _y)
548     if _pthinfo is not None:
549     _path, _col, _cellx, _celly = _pthinfo
550     if event.button == 3:
551     self.set_all_menu_items_sensitive()
552     _contextmenu = True
553    
554     if not (_contextmenu or _delete_row):
555     #print "NOT DOING ANYTHING ABOUT %s" % gtk.gdk.keyval_name(event.keyval)
556     return
557    
558     if len(_rowlist)>1:
559     self.unitsmenuitem.set_sensitive(False)
560     self.studycolumnmenuitem.set_sensitive(False)
561     self.plotmenuitem.set_sensitive(False)
562     self.deletecolumnmenuitem.set_sensitive(False)
563     if _delete_row:
564     self.on_delete_row()
565 jpye 2584 return True
566 aakash 2494 self.treecontext.popup( None, None, None, _button, event.time)
567     return
568    
569     self.view.grab_focus()
570     self.view.set_cursor( _path, _col, 0)
571    
572     self.current_path = _path
573     self.current_col = _col
574     self.current_instance = None
575     if _delete_row:
576     self.on_delete_row()
577     elif self.alive is False:
578     self.unitsmenuitem.set_sensitive(False)
579     self.studycolumnmenuitem.set_sensitive(False)
580     self.treecontext.popup( None, None, None, _button, event.time)
581     else:
582     # Since we have the instance data in self.cols and treeview points us to the
583     # ClickableTreeColumn, we need to match the two.
584     for _cols in self.cols:
585     if self.cols[_cols].title == self.current_col.title:
586     self.current_instance = self.cols[_cols].instance
587     self.current_col_key = _cols
588     break
589     if self.current_instance is None:
590     return 0
591     if self.current_instance.isFixed() == False:
592     self.studycolumnmenuitem.set_sensitive(False)
593     self.treecontext.popup( None, None, None, _button, event.time)
594     return 1
595    
596     def on_study_column_activate(self, *args):
597     if self.current_instance is not None:
598     _dia = StudyWin(self.browser,self.current_instance)
599     _dia.run()
600    
601     def on_delete_row(self, *args):
602     # We need to remove the row from two places,
603     # the treestore, and our own list of ObserverRows
604    
605     _sel = self.view.get_selection()
606     _store, _rowlist = _sel.get_selected_rows()
607     i = 0
608     (x,) = _rowlist[0]
609     for _path in _rowlist:
610     if len(self.rows) == x+1:
611     self.browser.reporter.reportWarning("Can't delete the active row")
612     return
613     self.rows.pop(x)
614     _store.remove(_store.get_iter((x,)))
615    
616     # now that we have deleted the row, it is
617     # time to move the cursor to the next available element
618    
619     self.view.grab_focus()
620     self.view.set_cursor((x,), self.current_col, 0)
621    
622     def taint_row(self, msg, _rowobject = None):
623     # to set the solver error message as the row's tooltip
624     _store = self.view.get_model()
625     if _rowobject is None:
626     _rowobject = _store.get_value(self.activeiter,0)
627     _rowobject.error_msg = msg
628     _rowobject.tainted = True
629    
630     def on_delete_column(self, *args):
631     # To delete columns
632 jpye 2836 for _col in self.cols:
633     if self.cols[_col].title == self.current_col.title:
634     current_col_key = _col
635     self.cols.pop(current_col_key)
636 aakash 2494 self.view.remove_column(self.current_col)
637 jpye 2836
638     def on_column_plot_events(self, *args):
639     for _col in self.cols:
640     if self.cols[_col].title == self.current_col.title:
641     current_col_key = _col
642     _plotwin = ColPlotEventsDialog(self.browser, self)
643     _plot = _plotwin.run()
644     if _plot:
645     self.plot_event(x=self.cols[current_col_key], t=_plotwin.col, title = self.cols[0].title)
646    
647     def plot_event(self, x, t, title):
648 jpye 2865 """Plot internal details of event handling for an individual variable"""
649 jpye 2836 import platform
650     import matplotlib
651     matplotlib.use('GTKAgg')
652     import pylab
653     pylab.ioff()
654    
655     vals = []
656     for x1, x2 in x.eventdata:
657     if x1 == t:
658     vals.append(x2)
659     pylab.xlim(-1,len(vals))
660     vmin = min(vals)
661     vmax = max(vals)
662     pylab.ylim(vmin-1,vmax+1)
663     pylab.plot(vals,'rD')
664     pylab.suptitle("0 - before crossing the boundary,\n1 - after the first call of the logical solver,\n2 - after solving the boundary equations,\n3+ - added if solving the system changes the values of some boolean vars.",bbox={'facecolor':'green', 'alpha':0.5, 'pad':10})
665     pylab.xlabel(title + ' = ' + str(t))
666     pylab.ylabel(x.title)
667     pylab.tight_layout(pad = 7)
668     pylab.ion()
669     pylab.show()
670    
671 aakash 2494 def on_plotmenuitem_activate(self, *args):
672     # To preselect the column as y axis
673     try:
674     if len(self.cols)<2:
675     raise Exception("Not enough columns to plot (need 2+)")
676     _plotwin = PlotDialog(self.browser, self)
677     _plotwin.select_ycol(self.cols[self.current_col_key], self)
678     _plot = _plotwin.run()
679     if _plot:
680     self.plot(x=_plotwin.xcol, y=_plotwin.ycol)
681     except Exception,e:
682     self.browser.reporter.reportError(str(e))
683    
684     def on_close_observer_clicked(self, *args):
685     # First, the dialog box is brought up, and if the user clicks on yes,
686     # the observer tab is closed. Need to make sure that this instance is
687     # removed from the list of observers maintained in the browser
688    
689     _alertwin = CloseDialog(self.browser)
690     destroy = _alertwin.run()
691     if destroy:
692     self.view.destroy()
693     if self.browser.currentobservertab == self.browser.currentpage:
694     self.browser.currentobservertab = None
695     self.browser.maintabs.remove_page(self.browser.currentpage)
696     self.rows = []
697     self.browser.observers.remove(self)
698    
699     def on_units_activate(self, *args):
700     if self.current_instance is not None:
701     T = self.current_instance.getType()
702     _un = UnitsDialog(self.browser,T)
703     _un.run()
704    
705     def units_refresh(self, instance_type):
706     for _col in self.cols.values():
707     _units = None
708     _units = instance_type.getPreferredUnits()
709     if _units is None:
710     _units = instance_type.getDimensions().getDefaultUnits()
711     _uname = str(_units.getName())
712    
713     _col_type = _col.instance.getType()
714     _col_units = _col_type.getPreferredUnits()
715     if _col_units is None:
716     _col_units = _col_type.getDimensions().getDefaultUnits()
717     _col_uname = str(_col_units.getName())
718    
719     if _col_uname == _uname:
720     if self.browser == None:
721     name = "UNNAMED"
722     else:
723     name = self.browser.sim.getInstanceName(_col.instance)
724    
725     _uname = str(_units.getName())
726     if len(_uname) or _uname.find("/")!=-1:
727     _uname = "["+_uname+"]"
728    
729     if _uname == "":
730     _title = "%s" % (name)
731     else:
732     _title = "%s / %s" % (name, _uname)
733     for _tvcol in self.view.get_columns():
734     if _tvcol.title == _col.title:
735     _tvcol.label.set_text(str(_title))
736     _tvcol.title = _title
737     _tvcol.set_title(_title)
738     _col.title = _title
739     _col.units = _units
740     _col.uname = _uname
741     _col.name = name
742     def set_dead(self):
743 sreenatha 2684 if self.alive == False and self.reloaded == True:
744     for i in range(self.colindex):
745     col = self.cols[i]
746     renderer = self.renderers[i]
747     tvcol = self.tvcols[i]
748     tvcol.set_cell_data_func(renderer, None)
749     tvcol.set_cell_data_func(renderer, col.cellvalue, True)
750 aakash 2494 self.alive = False
751     self.addbutton.set_sensitive(False)
752     _selection = self.view.get_selection()
753     _selection.unselect_all()
754     _store = self.view.get_model()
755     if self.activeiter is not None:
756     _rowobject = _store.get_value(self.activeiter,0)
757     _rowobject.active = False
758     _rowobject.dead = True
759     self.activeiter = None
760    
761     class CloseDialog:
762    
763     # Just a dialog to confirm that the user REALLY wants to close
764     # the observer
765    
766     def __init__(self, browser):
767     browser.builder.add_objects_from_file(browser.glade_file, ["closeobserverdialog"])
768     self.alertwin = browser.builder.get_object("closeobserverdialog")
769     browser.builder.connect_signals(self)
770    
771     def on_closeobserverdialog_close(self,*args):
772     self.alertwin.response(gtk.RESPONSE_CLOSE)
773    
774     def run(self):
775     _continue = True
776     while _continue:
777     _res = self.alertwin.run()
778     if _res == gtk.RESPONSE_YES:
779     self.alertwin.destroy()
780     return True
781     else:
782     self.alertwin.destroy()
783     return False
784    
785     class PlotDialog:
786    
787     # a dialog where the user can select which columns to plot
788    
789     def __init__(self, browser, tab):
790     self.browser = browser
791     self.browser.builder.add_objects_from_file(browser.glade_file, ["plotdialog"])
792     self.plotwin = self.browser.builder.get_object("plotdialog")
793     self.plotbutton = self.browser.builder.get_object("plotbutton")
794     self.xview = self.browser.builder.get_object("treeview1")
795     self.yview = self.browser.builder.get_object("treeview2")
796 sreenatha 2684 self.yview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
797 aakash 2494 self.ignorepoints = self.browser.builder.get_object("ignorepoints")
798    
799     _p = self.browser.prefs
800     _ignore = _p.getBoolPref("PlotDialog", "ignore_error_points", True)
801     self.ignorepoints.set_active(_ignore)
802    
803     _xstore = gtk.TreeStore(object)
804     self.xview.set_model(_xstore)
805     _xrenderer = gtk.CellRendererText()
806     _xtvcol = gtk.TreeViewColumn("X axis")
807     _xtvcol.pack_start(_xrenderer,False)
808     _xtvcol.set_cell_data_func(_xrenderer, self.varlist)
809     self.xview.append_column(_xtvcol)
810    
811     _ystore = gtk.TreeStore(object)
812     self.yview.set_model(_ystore)
813     _yrenderer = gtk.CellRendererText()
814     _ytvcol = gtk.TreeViewColumn("Y axis")
815     _ytvcol.pack_start(_yrenderer,False)
816     _ytvcol.set_cell_data_func(_yrenderer, self.varlist)
817     self.yview.append_column(_ytvcol)
818    
819     self.xcol = None
820     self.ycol = None
821     for _cols in tab.cols:
822     _xtemp = _xstore.append(None, [tab.cols[_cols]])
823     _ytemp = _ystore.append(None, [tab.cols[_cols]])
824     if self.xcol is None:
825     self.xcol = tab.cols[_cols]
826     _xiter = _xtemp
827     continue
828     if self.ycol is None:
829     self.ycol = tab.cols[_cols]
830     _yiter = _ytemp
831     self.plotbutton.set_sensitive(True)
832    
833     _selx = self.xview.get_selection()
834     _selx.select_iter(_xiter)
835    
836     _sely = self.yview.get_selection()
837     _sely.select_iter(_yiter)
838    
839     self.browser.builder.connect_signals(self)
840    
841     def on_plotdialog_close(self,*args):
842     self.plotwin.response(gtk.RESPONSE_CANCEL)
843    
844     def varlist(self,column,cell,model,iter):
845     _value = model.get_value(iter,0)
846     cell.set_property('text', _value.title)
847    
848     def on_treeview_event(self,widget,event):
849    
850     _path = None
851     _col = None
852     self.plotbutton.set_sensitive(False)
853     if event.type==gtk.gdk.KEY_RELEASE:
854     _keyval = gtk.gdk.keyval_name(event.keyval)
855     if _keyval == "Escape":
856     self.plotwin.response(gtk.RESPONSE_CANCEL)
857     return
858     _path, _tvcol = widget.get_cursor()
859     if _path is None:
860     return
861    
862     elif event.type==gtk.gdk.BUTTON_RELEASE:
863     _x = int(event.x)
864     _y = int(event.y)
865     _button = event.button
866     _pthinfo = widget.get_path_at_pos(_x, _y)
867     if _pthinfo is None:
868     return
869     _path, _tvcol, _cellx, _celly = _pthinfo
870     if _path is None:
871     return
872    
873     _sel = widget.get_selection()
874 sreenatha 2684 _view, path_list = _sel.get_selected_rows()
875     if path_list is None:
876 aakash 2494 return
877 sreenatha 2684 #_path = _view.get_path(_iter)
878     #_path = _iter[0]
879     #if _path is None:
880     # return
881 aakash 2494 widget.grab_focus()
882     _store = widget.get_model()
883 sreenatha 2684 #_selx = self.xview.get_selection()
884     #_sely = self.yview.get_selection()
885    
886     #widget.set_cursor( _path, None, 0)
887     flag=True
888     for _path in path_list:
889     if _path is None:
890     return
891     _iter = _store.get_iter(_path)
892     _col = _store.get_value(_iter,0)
893     if widget is self.xview:
894     self.xcol = _col
895     #_selx.select_iter(_iter)
896     break
897     else:
898     if flag==True:
899     self.ycol = []
900     flag=False
901     self.ycol.append(_col)
902     #_sely.select_iter(_iter)
903    
904     if self.ycol is not None and type(self.ycol)!=type([]) :
905     self.ycol = [self.ycol]
906    
907     flag=True
908 aakash 2494 if self.xcol is not None and self.ycol is not None:
909 sreenatha 2684 for yitem in self.ycol:
910     if self.xcol.title == yitem.title:
911     flag=False
912     if widget is self.xview:
913     self.yview.get_selection().unselect_all()
914     self.ycol = None
915     else:
916     self.xview.get_selection().unselect_all()
917     self.xcol = None
918     break
919     if flag==True:
920 aakash 2494 self.plotbutton.set_sensitive(True)
921    
922     def select_ycol(self, _col, _tab):
923     _ystore = self.yview.get_model()
924     _iter = _ystore.get_iter_first()
925     for i in _tab.cols:
926     _item = _ystore.get_value(_iter, 0)
927     if _item.title == _col.title:
928     self.ycol = _col
929     _sel = self.yview.get_selection()
930     _sel.unselect_all()
931     _sel.select_iter(_iter)
932     self.xcol = None
933     self.xview.get_selection().unselect_all()
934     self.plotbutton.set_sensitive(False)
935     _iter = _ystore.iter_next(_iter)
936    
937     def run(self):
938     _continue = True
939     while _continue:
940     _res = self.plotwin.run()
941     if _res == gtk.RESPONSE_YES:
942     _p = self.browser.prefs
943     _p.setBoolPref("PlotDialog", "ignore_error_points", self.ignorepoints.get_active())
944     self.plotwin.destroy()
945 sreenatha 2684 if self.ycol is not None and type(self.ycol)!=type([]) :
946     self.ycol = [self.ycol]
947 aakash 2494 return True
948     else:
949     self.plotwin.destroy()
950 jpye 2522 return False
951 jpye 2836
952     class ColPlotEventsDialog:
953    
954     # a dialog where the user can select which events to plot
955     # FIXME: this window should be scrolled
956    
957     def __init__(self, browser, tab):
958     self.browser = browser
959     self.browser.builder.add_objects_from_file(browser.glade_file, ["colploteventsdialog"])
960     self.plotwin = self.browser.builder.get_object("colploteventsdialog")
961     self.plotbutton = self.browser.builder.get_object("plotbutton")
962     self.view = self.browser.builder.get_object("treeview1")
963    
964     _store = gtk.TreeStore(object)
965     self.view.set_model(_store)
966     _renderer = gtk.CellRendererText()
967     _tvcol = gtk.TreeViewColumn("t")
968     _tvcol.pack_start(_renderer,False)
969     _tvcol.set_cell_data_func(_renderer, self.vallist)
970     self.view.append_column(_tvcol)
971    
972     self.col = None
973     tprev = tab.cols[0].eventdata[0]
974     for _vals in tab.cols[0].eventdata:
975     if _vals[0] != tprev:
976     _temp = _store.append(None,[_vals[0]])
977     tprev = _vals[0]
978     if self.col is None:
979     self.col = _vals[0]
980     _iter = _temp
981    
982     self.browser.builder.connect_signals(self)
983    
984     def on_colploteventsdialog_close(self,*args):
985     self.plotwin.response(gtk.RESPONSE_CANCEL)
986    
987     def vallist(self,column,cell,model,iter):
988     _value = model.get_value(iter,0)
989     cell.set_property('text', _value)
990    
991     def on_treeview_event(self,widget,event):
992     _path = None
993     _col = None
994     self.plotbutton.set_sensitive(False)
995     if event.type==gtk.gdk.KEY_RELEASE:
996     _keyval = gtk.gdk.keyval_name(event.keyval)
997     if _keyval == "Escape":
998     self.plotwin.response(gtk.RESPONSE_CANCEL)
999     return
1000     _path, _tvcol = widget.get_cursor()
1001     if _path is None:
1002     return
1003     elif event.type==gtk.gdk.BUTTON_RELEASE:
1004     _x = int(event.x)
1005     _y = int(event.y)
1006     _button = event.button
1007     _pthinfo = widget.get_path_at_pos(_x, _y)
1008     if _pthinfo is None:
1009     return
1010     _path, _tvcol, _cellx, _celly = _pthinfo
1011     if _path is None:
1012     return
1013    
1014     _sel = widget.get_selection()
1015     _view, path_list = _sel.get_selected_rows()
1016     if path_list is None:
1017     return
1018     widget.grab_focus()
1019     _store = widget.get_model()
1020     flag=True
1021     for _path in path_list:
1022     if _path is None:
1023     return
1024     _iter = _store.get_iter(_path)
1025     _col = _store.get_value(_iter,0)
1026     if widget is self.view:
1027     self.col = _col
1028     break
1029    
1030     flag=True
1031     if self.col is not None:
1032     self.plotbutton.set_sensitive(True)
1033    
1034     def run(self):
1035     _continue = True
1036     while _continue:
1037     _res = self.plotwin.run()
1038     if _res == gtk.RESPONSE_YES:
1039     self.plotwin.destroy()
1040     return True
1041     else:
1042     self.plotwin.destroy()
1043     return False
1044 jpye 2865
1045    

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22