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

Contents of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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