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

Contents of /trunk/pygtk/modelview.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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