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

Annotation of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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