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

Contents of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1704 - (show annotations) (download) (as text)
Sun Jan 6 04:54:18 2008 UTC (12 years, 3 months ago) by jpye
File MIME type: text/x-python
File size: 16075 byte(s)
Added context menu for 'select units'.

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

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