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

Contents of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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