/[ascend]/trunk/pygtk/modelview.py
ViewVC logotype

Annotation of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2684 - (hide annotations) (download) (as text)
Tue Feb 26 01:56:46 2013 UTC (7 years, 1 month ago) by sreenatha
File MIME type: text/x-python
File size: 17196 byte(s)
Merging GSOC2012 contributions from Sreenatha, after some modifications made to fix minor bugs -- jpye.
1 johnpye 533 import gtk
2     import pango
3     import ascpy
4    
5     from varentry import *
6     from properties import *
7 jpye 1704 from unitsdialog import *
8 aakash 2494 from study import *
9 johnpye 533
10     BROWSER_FIXED_COLOR = "#008800"
11     BROWSER_FREE_COLOR = "#000088"
12 johnpye 844 BROWSER_SETTING_COLOR = "#4444AA"
13 johnpye 533
14 jpye 1360 BROWSER_INCLUDED_COLOR = "black"
15     BROWSER_UNINCLUDED_COLOR = "#888888"
16 johnpye 808
17 johnpye 533 class ModelView:
18 aakash 2494 def __init__(self,browser,builder):
19 jpye 1727 self.browser = browser # the parent object: the entire ASCEND browser
20 johnpye 533
21 aakash 2494 self.builder = builder
22 jpye 1727 self.notes = browser.library.getAnnotationDatabase()
23    
24 aakash 2494 self.modelview = builder.get_object("browserview")
25 johnpye 533
26     # name, type, value, foreground, weight, editable, status-icon
27     columns = [str,str,str,str,int,bool,gtk.gdk.Pixbuf]
28    
29     self.otank = {}
30    
31     # name, type, value, foreground, weight, editable, status-icon
32     columns = [str,str,str,str,int,bool,gtk.gdk.Pixbuf]
33     self.modelstore = gtk.TreeStore(*columns)
34     titles = ["Name","Type","Value"];
35     self.modelview.set_model(self.modelstore)
36     self.tvcolumns = [ gtk.TreeViewColumn() for _type in columns[:len(titles)] ]
37    
38     self.modelview.connect("row-expanded", self.row_expanded )
39     self.modelview.connect("button-press-event", self.on_treeview_event )
40 aakash 2494 self.modelview.connect("key-release-event",self.on_treeview_event )
41 johnpye 533
42     # data columns are: name type value colour weight editable
43    
44     i = 0
45     for tvcolumn in self.tvcolumns[:len(titles)]:
46     tvcolumn.set_title(titles[i])
47     self.modelview.append_column(tvcolumn)
48    
49     if(i==2):
50     # add status icon
51     renderer1 = gtk.CellRendererPixbuf()
52     tvcolumn.pack_start(renderer1, False)
53     tvcolumn.add_attribute(renderer1, 'pixbuf', 6)
54    
55     renderer = gtk.CellRendererText()
56     tvcolumn.pack_start(renderer, True)
57     tvcolumn.add_attribute(renderer, 'text', i)
58     tvcolumn.add_attribute(renderer, 'foreground', 3)
59     tvcolumn.add_attribute(renderer, 'weight', 4)
60     if(i==2):
61     tvcolumn.add_attribute(renderer, 'editable', 5)
62     renderer.connect('edited',self.cell_edited_callback)
63     i = i + 1
64    
65     #--------------------
66 aakash 2494 # get all menu icons and set up the context menu for fixing/freeing vars
67     _imagelist = []
68     for i in range(6):
69     _imagelist.append("image%s" % (i+1))
70     self.browser.builder.add_objects_from_file(self.browser.glade_file, _imagelist)
71     self.browser.builder.add_objects_from_file(self.browser.glade_file, ["treecontext"])
72    
73     self.treecontext = self.browser.builder.get_object("treecontext")
74     self.fixmenuitem = self.browser.builder.get_object("fix1")
75     self.freemenuitem = self.browser.builder.get_object("free1")
76     self.propsmenuitem = self.browser.builder.get_object("properties1")
77     self.observemenuitem = self.browser.builder.get_object("observe1")
78     self.studymenuitem = self.browser.builder.get_object("study1")
79     self.unitsmenuitem = self.browser.builder.get_object("units1")
80    
81 johnpye 533 self.fixmenuitem.connect("activate",self.fix_activate)
82     self.freemenuitem.connect("activate",self.free_activate)
83     self.propsmenuitem.connect("activate",self.props_activate)
84     self.observemenuitem.connect("activate",self.observe_activate)
85 aakash 2494 self.studymenuitem.connect("activate", self.study_activate)
86 jpye 1704 self.unitsmenuitem.connect("activate",self.units_activate)
87 johnpye 533
88     if not self.treecontext:
89     raise RuntimeError("Couldn't create browsercontext")
90    
91     def setSimulation(self,sim):
92     # instance hierarchy
93     self.sim = sim
94     self.modelstore.clear()
95     self.otank = {} # map path -> (name,value)
96 aakash 2494 self.browser.disable_menu()
97 johnpye 1300 try:
98     self.make( self.sim.getName(),self.sim.getModel() )
99 aakash 2494 self.browser.enable_on_model_tree_build()
100 johnpye 1300 except Exception,e:
101     self.browser.reporter.reportError("Error building tree: %s" % e);
102 johnpye 533 self.browser.maintabs.set_current_page(1);
103    
104     def clear(self):
105     self.modelstore.clear()
106     self.otank = {}
107    
108     # --------------------------------------------
109     # INSTANCE TREE
110    
111     def get_tree_row_data(self,instance): # for instance browser
112     _value = str(instance.getValue())
113     _type = str(instance.getType())
114     _name = str(instance.getName())
115 jpye 1360 _fgcolor = BROWSER_INCLUDED_COLOR
116 johnpye 533 _fontweight = pango.WEIGHT_NORMAL
117     _editable = False
118     _statusicon = None
119     if instance.getType().isRefinedSolverVar():
120     _editable = True
121     _fontweight = pango.WEIGHT_BOLD
122     if instance.isFixed():
123     _fgcolor = BROWSER_FIXED_COLOR
124     else:
125     _fgcolor = BROWSER_FREE_COLOR
126     _fontweight = pango.WEIGHT_BOLD
127 jpye 1362 _status = instance.getStatus();
128 johnpye 533 _statusicon = self.browser.statusicons[_status]
129 johnpye 806 elif instance.isRelation():
130 jpye 1362 _status = instance.getStatus();
131     _statusicon = self.browser.statusicons[_status]
132 jpye 1360 if not instance.isIncluded():
133     _fgcolor = BROWSER_UNINCLUDED_COLOR
134 johnpye 533 elif instance.isBool() or instance.isReal() or instance.isInt():
135     # TODO can't edit constants that have already been refined
136     _editable = True
137 johnpye 844 _fgcolor = BROWSER_SETTING_COLOR
138     _fontweight = pango.WEIGHT_BOLD
139     elif instance.isSymbol() and not instance.isConst():
140     _editable = True
141     _fgcolor = BROWSER_SETTING_COLOR
142     _fontweight = pango.WEIGHT_BOLD
143    
144 johnpye 533 #if(len(_value) > 80):
145     # _value = _value[:80] + "..."
146    
147     return [_name, _type, _value, _fgcolor, _fontweight, _editable, _statusicon]
148    
149     def make_row( self, piter, name, value ): # for instance browser
150 johnpye 1300 assert(value)
151 johnpye 533 _piter = self.modelstore.append( piter, self.get_tree_row_data(value) )
152     return _piter
153    
154     def refreshtree(self):
155     # @TODO FIXME use a better system than colour literals!
156     for _path in self.otank: # { path : (name,value) }
157     _iter = self.modelstore.get_iter(_path)
158     _name, _instance = self.otank[_path]
159     self.modelstore.set_value(_iter, 2, _instance.getValue())
160     if _instance.getType().isRefinedSolverVar():
161     if _instance.isFixed() and self.modelstore.get_value(_iter,3)==BROWSER_FREE_COLOR:
162     self.modelstore.set_value(_iter,3,BROWSER_FIXED_COLOR)
163     elif not _instance.isFixed() and self.modelstore.get_value(_iter,3)==BROWSER_FIXED_COLOR:
164     self.modelstore.set_value(_iter,3,BROWSER_FREE_COLOR)
165 jpye 1362 self.modelstore.set_value(_iter, 6, self.browser.statusicons[_instance.getStatus()])
166 johnpye 808 elif _instance.isRelation():
167 jpye 1362 self.modelstore.set_value(_iter, 6, self.browser.statusicons[_instance.getStatus()])
168 jpye 1360 if _instance.isIncluded():
169     self.modelstore.set_value(_iter,3,BROWSER_INCLUDED_COLOR)
170 johnpye 808 else:
171 jpye 1360 self.modelstore.set_value(_iter,3,BROWSER_UNINCLUDED_COLOR)
172 johnpye 533
173 jpye 1711 def get_selected_type(self):
174 jpye 1927 return self.get_selected_instance().getType()
175    
176     def get_selected_instance(self):
177 jpye 1711 model,iter = self.modelview.get_selection().get_selected()
178     if iter is None:
179     return None
180     path = model.get_path(iter)
181     name,instance = self.otank[path]
182 jpye 1927 return instance
183 jpye 1711
184 johnpye 533 def cell_edited_callback(self, renderer, path, newtext, **kwargs):
185     # get back the Instance object we just edited (having to use this seems like a bug)
186     path = tuple( map(int,path.split(":")) )
187    
188     if not self.otank.has_key(path):
189     raise RuntimeError("cell_edited_callback: invalid path '%s'" % path)
190     return
191    
192     _name, _instance = self.otank[path]
193    
194     if _instance.isReal():
195 aakash 2494 if _instance.getValue() == newtext:
196     return
197 johnpye 533 # only real-valued things can have units
198    
199     _e = RealAtomEntry(_instance,newtext);
200     try:
201     _e.checkEntry()
202     _e.setValue()
203     _e.exportPreferredUnits(self.browser.prefs)
204     except InputError, e:
205 johnpye 792 self.browser.reporter.reportError(str(e))
206 johnpye 533 return;
207    
208     else:
209     if _instance.isBool():
210     _lower = newtext.lower();
211     if _lower.startswith("t") or _lower.startswith("y") or _lower.strip()=="1":
212     newtext = 1
213     elif _lower.startswith("f") or _lower.startswith("n") or _lower.strip()=="0":
214     newtext = 0
215     else:
216 johnpye 792 self.browser.reporter.reportError("Invalid entry for a boolean variable: '%s'" % newtext)
217 johnpye 533 return
218     _val = bool(newtext);
219     if _val == _instance.getValue():
220 johnpye 792 self.browser.reporter.reportNote("Boolean atom '%s' was not altered" % _instance.getName())
221 johnpye 533 return
222     _instance.setBoolValue(_val)
223    
224     elif _instance.isInt():
225     _val = int(newtext)
226     if _val == _instance.getValue():
227 johnpye 792 self.browser.reporter.reportNote("Integer atom '%s' was not altered" % _instance.getName())
228 johnpye 533 return
229     _instance.setIntValue(_val)
230 johnpye 844 elif _instance.isSymbol():
231     _val = str(newtext)
232     if _val == _instance.getValue():
233     self.browser.reporter.reportNote("Symbol atom '%s' was not altered" % _instance.getName())
234     return
235     _instance.setSymbolValue(ascpy.SymChar(_val))
236    
237 johnpye 533 else:
238 johnpye 792 self.browser.reporter.reportError("Attempt to set a non-real, non-boolean, non-integer value!")
239 johnpye 533 return
240    
241     # now that the variable is set, update the GUI and re-solve if desired
242     _iter = self.modelstore.get_iter(path)
243     self.modelstore.set_value(_iter,2,_instance.getValue())
244    
245     if _instance.getType().isRefinedSolverVar():
246     self.modelstore.set_value(_iter,3,BROWSER_FIXED_COLOR) # set the row green as fixed
247    
248     self.browser.do_solve_if_auto()
249    
250     def make_children(self, value, piter ):
251 johnpye 1300 assert(value)
252 johnpye 533 if value.isCompound():
253     children=value.getChildren();
254     for child in children:
255 johnpye 1300 try:
256     _name = child.getName();
257     _piter = self.make_row(piter,_name,child)
258     _path = self.modelstore.get_path(_piter)
259     self.otank[_path]=(_name,child)
260     #self.browser.reporter.reportError("2 Added %s at path %s" % (_name,repr(_path)))
261     except Exception,e:
262     self.browser.reporter.reportError("%s: %s" % (_name,e))
263    
264 johnpye 533 def make(self, name=None, value=None, path=None, depth=1):
265     if path is None:
266     # make root node
267     piter = self.make_row( None, name, value )
268     path = self.modelstore.get_path( piter )
269     self.otank[ path ] = (name, value)
270 johnpye 792 #self.browser.reporter.reportError("4 Added %s at path %s" % (name, path))
271 johnpye 533 else:
272 johnpye 1300 name, value = self.otank[ path ]
273 johnpye 533
274 johnpye 1300 assert(value)
275    
276 johnpye 533 piter = self.modelstore.get_iter( path )
277     if not self.modelstore.iter_has_child( piter ):
278 johnpye 1300 #self.browser.reporter.reportNote( "name=%s has CHILDREN..." % name )
279     self.make_children(value,piter)
280 johnpye 533
281     if depth:
282     for i in range( self.modelstore.iter_n_children( piter ) ):
283     self.make( path = path+(i,), depth = depth - 1 )
284     else:
285     self.modelview.expand_row("0",False)
286    
287     def row_expanded( self, modelview, piter, path ):
288     self.make( path = path )
289    
290    
291     # ------------------------------
292     # CONTEXT MENU
293    
294     def on_treeview_event(self,widget,event):
295 jpye 1727 _path = None
296     _contextmenu = False
297 aakash 2494 if event.type==gtk.gdk.KEY_RELEASE:
298 johnpye 1149 _keyval = gtk.gdk.keyval_name(event.keyval)
299 johnpye 533 _path, _col = self.modelview.get_cursor()
300 johnpye 1149 if _keyval=='Menu':
301     _contextmenu = True
302 jpye 1727 _button = 3
303 johnpye 1149 elif _keyval == 'F2':
304     print "F2 pressed"
305     self.modelview.set_cursor(_path,self.tvcolumns[2],1)
306    
307     return
308 johnpye 533 elif event.type==gtk.gdk.BUTTON_PRESS:
309 jpye 1727 _x = int(event.x)
310     _y = int(event.y)
311     _button = event.button
312     _pthinfo = self.modelview.get_path_at_pos(_x, _y)
313     if _pthinfo is not None:
314 johnpye 533 _path, _col, _cellx, _celly = _pthinfo
315 jpye 1727 if event.button == 3:
316     _contextmenu = True
317 johnpye 1149
318 jpye 1727 if _path:
319     _name,_instance = self.otank[_path]
320     # set the statusbar
321     nn = self.notes.getNotes(self.sim.getModel().getType(),ascpy.SymChar("inline"),_name)
322     for n in nn:
323     print "%s: (%s) %s" % (n.getId(),str(n.getLanguage()),n.getText())
324 aakash 2494
325     self.builder.get_object("free_variable").set_sensitive(False)
326     self.builder.get_object("fix_variable").set_sensitive(False)
327     self.builder.get_object("propsmenuitem").set_sensitive(False)
328     if _instance.isReal():
329     self.builder.get_object("units").set_sensitive(True)
330     if _instance.getType().isRefinedSolverVar():
331     self.builder.get_object("propsmenuitem").set_sensitive(True)
332     if _instance.isFixed():
333     self.builder.get_object("free_variable").set_sensitive(True)
334     else:
335     self.builder.get_object("fix_variable").set_sensitive(True)
336 aakash 2502 elif _instance.isRelation():
337     self.builder.get_object("propsmenuitem").set_sensitive(True)
338 jpye 1727
339 johnpye 533 if not _contextmenu:
340 johnpye 1149 #print "NOT DOING ANYTHING ABOUT %s" % gtk.gdk.keyval_name(event.keyval)
341 johnpye 533 return
342    
343     _canpop = False;
344 johnpye 792 # self.browser.reporter.reportError("Right click on %s" % self.otank[_path][0])
345 jpye 1704
346 jpye 1706 self.unitsmenuitem.set_sensitive(False)
347     self.fixmenuitem.set_sensitive(False)
348     self.freemenuitem.set_sensitive(False)
349     self.observemenuitem.set_sensitive(False)
350 aakash 2494 self.studymenuitem.set_sensitive(False)
351 jpye 1706 self.propsmenuitem.set_sensitive(False)
352    
353     if _instance.isReal():
354     print "CAN POP: real atom"
355     _canpop = True
356 jpye 1704 self.unitsmenuitem.set_sensitive(True)
357    
358 johnpye 533 if _instance.getType().isRefinedSolverVar():
359 johnpye 774 _canpop = True
360 jpye 1706 self.propsmenuitem.set_sensitive(True)
361 johnpye 533 self.observemenuitem.set_sensitive(True)
362     if _instance.isFixed():
363     self.freemenuitem.set_sensitive(True)
364 aakash 2494 if len(self.browser.observers) > 0:
365     self.studymenuitem.set_sensitive(True)
366 johnpye 533 else:
367     self.fixmenuitem.set_sensitive(True)
368     elif _instance.isRelation():
369 johnpye 774 _canpop = True
370 johnpye 533 self.propsmenuitem.set_sensitive(True)
371 johnpye 774 elif _instance.isModel():
372     # MODEL instances have a special context menu:
373     _menu = self.get_model_context_menu(_instance)
374     self.modelview.grab_focus()
375     self.modelview.set_cursor(_path,_col,0)
376     print "RUNNING POPUP MENU"
377     _menu.popup(None,None,None,_button,event.time)
378     return
379 johnpye 533
380     if not _canpop:
381     return
382    
383     self.modelview.grab_focus()
384     self.modelview.set_cursor( _path, _col, 0)
385     self.treecontext.popup( None, None, None, _button, event.time)
386     return 1
387    
388 johnpye 774 def get_model_context_menu(self,instance):
389     menu = gtk.Menu()
390 johnpye 834
391     if instance.isPlottable():
392     print "PLOTTABLE"
393     mi = gtk.ImageMenuItem("P_lot",True);
394     img = gtk.Image()
395 johnpye 1030 img.set_from_file(self.browser.options.assets_dir+'/plot.png')
396 johnpye 834 mi.set_image(img)
397     mi.show()
398     mi.connect("activate",self.plot_activate)
399     menu.append(mi);
400     sep = gtk.SeparatorMenuItem(); sep.show()
401     menu.append(sep)
402    
403 johnpye 774 mi = gtk.ImageMenuItem("Run method...",False)
404     mi.set_sensitive(False)
405     img = gtk.Image()
406     img.set_from_stock(gtk.STOCK_EXECUTE,gtk.ICON_SIZE_MENU)
407     mi.set_image(img)
408     mi.show()
409     menu.append(mi)
410    
411     sep = gtk.SeparatorMenuItem(); sep.show()
412     menu.append(sep)
413    
414     t = instance.getType()
415     ml = t.getMethods()
416     if len(ml):
417     for m in ml:
418     mi = gtk.MenuItem(m.getName(),False)
419     mi.show()
420     mi.connect("activate",self.run_activate,instance,m)
421     menu.append(mi)
422    
423     return menu
424    
425     def run_activate(self,widget,instance,method):
426     print "RUNNING %s" % method.getName()
427 jpye 1371 try:
428     self.browser.sim.run(method,instance)
429     except Exception,e:
430     self.browser.reporter.reportError(str(e))
431 johnpye 774 self.refreshtree()
432    
433 johnpye 533 def fix_activate(self,widget):
434     _path,_col = self.modelview.get_cursor()
435     _name, _instance = self.otank[_path]
436     self.set_fixed(_instance,True);
437     _instance.setFixed(True)
438     return 1
439    
440     def free_activate(self,widget):
441     _path,_col = self.modelview.get_cursor()
442     _instance = self.otank[_path][1]
443     self.set_fixed(_instance,False)
444     return 1
445    
446     def plot_activate(self,widget):
447 johnpye 559
448     self.browser.reporter.reportNote("plot_activate...");
449 johnpye 533 _path,_col = self.modelview.get_cursor()
450     _instance = self.otank[_path][1]
451     if not _instance.isPlottable():
452 johnpye 559 self.browser.reporter.reportError("Can't plot instance %s" % _instance.getName().toString())
453 johnpye 533 return
454     else:
455 johnpye 559 self.browser.reporter.reportNote("Instance %s about to be plotted..." % _instance.getName().toString())
456 johnpye 533
457     print("Plotting instance '%s'..." % _instance.getName().toString())
458    
459     _plot = _instance.getPlot()
460    
461     print "Title: ", _plot.getTitle()
462     _plot.show(True)
463    
464     return 1
465    
466     def props_activate(self,widget,*args):
467 jpye 2031 if not hasattr(self,'sim'):
468     self.browser.reporter.reportError("Can't show properties until a simulation has been created.");
469     return
470 johnpye 533 _path,_col = self.modelview.get_cursor()
471     _instance = self.otank[_path][1]
472     if _instance.isRelation():
473     print "Relation '"+_instance.getName().toString()+"':", \
474     _instance.getRelationAsString(self.sim.getModel())
475     _dia = RelPropsWin(self.browser,_instance);
476     _dia.run();
477     elif _instance.getType().isRefinedSolverVar():
478     _dia = VarPropsWin(self.browser,_instance);
479     _dia.run();
480     else:
481 jpye 2401 self.browser.reporter.reportWarning("Select a variable or relation first...")
482 johnpye 533
483     def observe_activate(self,widget,*args):
484     _path,_col = self.modelview.get_cursor()
485     _instance = self.otank[_path][1]
486     if _instance.getType().isRefinedSolverVar():
487 jpye 2401 print "OBSERVING",_instance.getName().toString()
488 johnpye 533 self.browser.observe(_instance)
489    
490     def on_fix_variable_activate(self,*args):
491     _path,_col = self.modelview.get_cursor()
492     _instance = self.otank[_path][1]
493     self.set_fixed(_instance,True)
494    
495     def on_free_variable_activate(self,*args):
496     _path,_col = self.modelview.get_cursor()
497     _instance = self.otank[_path][1]
498     self.set_fixed(_instance,False)
499    
500     def set_fixed(self,instance,val):
501     if instance.getType().isRefinedSolverVar():
502     f = instance.isFixed();
503     if (f and not val) or (not f and val):
504     instance.setFixed(val)
505     self.browser.do_solve_if_auto()
506 jpye 1704
507 aakash 2494
508     def study_activate(self, *args):
509     _path,_col = self.modelview.get_cursor()
510     _instance = self.otank[_path][1]
511     self.browser.observe(_instance)
512     _dia = StudyWin(self.browser,_instance);
513     _dia.run()
514    
515 jpye 1704 def units_activate(self,*args):
516 jpye 1711 T = self.get_selected_type()
517 jpye 2401 try:
518     _un = UnitsDialog(self.browser,T)
519     _un.run()
520     except:
521     self.browser.reporter.reportError("Unable to display units dialog.")
522 jpye 1704

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