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

Contents of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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