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

Annotation of /trunk/pygtk/gtkbrowser.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 227 - (hide annotations) (download) (as text)
Sat Jan 28 04:44:15 2006 UTC (14 years, 8 months ago) by johnpye
Original Path: trunk/pygtk/interface/gtkbrowser.py
File MIME type: text/x-python
File size: 33711 byte(s)
Added grouping of solver parameters into pages
1 johnpye 132 #!/usr/bin/env python
2    
3     import pygtk
4     pygtk.require('2.0')
5     import gtk
6     import gtk.glade
7     import pango
8     import re
9     import preferences
10     import urlparse
11     import optparse
12    
13     import sys, dl
14     # This sets the flags for dlopen used by python so that the symbols in the
15     # ascend library are made available to libraries dlopened within ASCEND:
16     sys.setdlopenflags(dl.RTLD_GLOBAL|dl.RTLD_NOW)
17     import ascend
18    
19     # This is my first ever GUI code so please be nice :)
20    
21     # The fancy tree-view gizmo is the GtkTreeView object. See the article
22     # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/300304
23     # for the original source code on which my implementation was based.
24    
25     GLADE_FILE = "/home/john/src/ascend/trunk/pygtk/interface/ascend.glade"
26    
27 johnpye 226 CHANGED_COLOR = "#FFFF88"
28 johnpye 227 SOLVERPARAM_BOOL_TRUE = "Yes"
29     SOLVERPARAM_BOOL_FALSE = "No"
30 johnpye 226
31 johnpye 227 ESCAPE_KEY = 65307
32    
33 johnpye 223 #======================================
34     # Browser is the main ASCEND library/model browser window
35    
36 johnpye 132 class Browser:
37    
38     # ---------------------------------
39     # SETUP
40    
41     def __init__(self):
42     #--------
43     # load the file referenced in the command line, if any
44    
45     parser = optparse.OptionParser(usage="%prog [[-m typename] file]", version="gtkbrowser $rev$" )
46     # add options here if we want
47    
48 johnpye 160 parser.add_option("-m", "--model"
49     ,action="store", type="string", dest="model"
50     ,help="specify the model to instantiate upon loading modules")
51 johnpye 132 (options, args) = parser.parse_args()
52    
53     #print "OPTIONS_______________:",options
54    
55     #--------
56     # load up the preferences ini file
57    
58     self.prefs = preferences.Preferences()
59    
60     #--------
61     # initialise ASCEND
62    
63     self.library = ascend.Library()
64    
65     self.sim = None
66    
67     #-------------------
68     # Set up the window and main widget actions
69    
70     glade = gtk.glade.XML(GLADE_FILE,"browserwin")
71    
72     self.window = glade.get_widget("browserwin")
73 johnpye 208
74 johnpye 132 if not self.window:
75     raise RuntimeError("Couldn't load window from glade file")
76 johnpye 172
77 johnpye 173 _display = self.window.get_screen().get_display().get_name();
78     _geom=self.prefs.getGeometrySizePosition(_display,"browserwin")
79 johnpye 172 if _geom:
80     self.window.resize(_geom[0],_geom[1]);
81     self.window.move(_geom[2],_geom[3]);
82 johnpye 173
83 johnpye 132 self.window.connect("delete_event", self.delete_event)
84    
85 johnpye 173 self.browserpaned=glade.get_widget("browserpaned");
86     _geom2=self.prefs.getGeometryValue(_display,"browserpaned");
87     if _geom2:
88     self.browserpaned.set_position(_geom2);
89    
90 johnpye 132 self.openbutton=glade.get_widget("openbutton")
91     self.openbutton.connect("clicked",self.open_click)
92    
93     self.reloadbutton=glade.get_widget("reloadbutton")
94     self.reloadbutton.connect("clicked",self.reload_click)
95    
96     self.solvebutton=glade.get_widget("solvebutton")
97     self.solvebutton.connect("clicked",self.solve_click)
98    
99     self.checkbutton=glade.get_widget("checkbutton")
100     self.checkbutton.connect("clicked",self.check_click)
101    
102     self.autotoggle=glade.get_widget("autotoggle")
103     self.autotoggle.connect("toggled",self.auto_toggle)
104    
105     self.methodrunbutton=glade.get_widget("methodrunbutton")
106     self.methodrunbutton.connect("clicked",self.methodrun_click)
107    
108     self.methodsel=glade.get_widget("methodsel")
109    
110     self.maintabs = glade.get_widget("maintabs")
111    
112 johnpye 164 self.statusbar = glade.get_widget("statusbar")
113    
114 johnpye 208 self.menu = glade.get_widget("browsermenu")
115     glade.signal_autoconnect(self)
116    
117 johnpye 132 #-------------------
118 johnpye 164 # waitwin
119    
120     self.waitwin = gtk.gdk.Window(self.window.window,
121     gtk.gdk.screen_width(),
122     gtk.gdk.screen_height(),
123     gtk.gdk.WINDOW_CHILD,
124     0,
125     gtk.gdk.INPUT_ONLY)
126    
127     _cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
128     self.waitwin.set_cursor(_cursor)
129    
130     #-------------------
131 johnpye 132 # pixbufs to be used in the error listing
132    
133     self.iconok = self.window.render_icon(gtk.STOCK_YES,gtk.ICON_SIZE_MENU)
134     self.iconinfo = self.window.render_icon(gtk.STOCK_DIALOG_INFO,gtk.ICON_SIZE_MENU)
135     self.iconwarning = self.window.render_icon(gtk.STOCK_DIALOG_WARNING,gtk.ICON_SIZE_MENU)
136     self.iconerror = self.window.render_icon(gtk.STOCK_DIALOG_ERROR,gtk.ICON_SIZE_MENU)
137    
138     #--------------------
139     # set up the context menu for fixing/freeing vars
140    
141 johnpye 226 # TODO import this menu from Glade (this code is a PITA)
142    
143 johnpye 132 self.treecontext = gtk.Menu();
144 johnpye 181 self.fixmenuitem = gtk.ImageMenuItem("_Fix",True);
145     _img = gtk.Image()
146     _img.set_from_file('icons/locked.png')
147     self.fixmenuitem.set_image(_img)
148    
149     self.freemenuitem = gtk.ImageMenuItem("F_ree",True);
150     _img = gtk.Image()
151     _img.set_from_file('icons/unlocked.png')
152     self.freemenuitem.set_image(_img)
153    
154     self.plotmenuitem = gtk.ImageMenuItem("P_lot",True);
155     _img = gtk.Image()
156     _img.set_from_file('icons/plot.png')
157     self.plotmenuitem.set_image(_img)
158    
159     self.propsmenuitem = gtk.ImageMenuItem("_Properties",True);
160     _img = gtk.Image()
161     _img.set_from_file('icons/properties.png')
162     self.propsmenuitem.set_image(_img)
163    
164 johnpye 207 self.fixmenuitem.show(); self.fixmenuitem.set_sensitive(False)
165     self.freemenuitem.show(); self.freemenuitem.set_sensitive(False)
166     self.plotmenuitem.show(); self.plotmenuitem.set_sensitive(False)
167 johnpye 181 self.propsmenuitem.show()
168 johnpye 132 self.treecontext.append(self.fixmenuitem);
169     self.treecontext.append(self.freemenuitem);
170 johnpye 181 _sep = gtk.SeparatorMenuItem(); _sep.show()
171     self.treecontext.append(_sep);
172 johnpye 172 self.treecontext.append(self.plotmenuitem);
173 johnpye 181 _sep = gtk.SeparatorMenuItem(); _sep.show()
174     self.treecontext.append(_sep);
175     self.treecontext.append(self.propsmenuitem);
176 johnpye 132 self.fixmenuitem.connect("activate",self.fix_activate)
177     self.freemenuitem.connect("activate",self.free_activate)
178 johnpye 175 self.plotmenuitem.connect("activate",self.plot_activate)
179 johnpye 181 self.propsmenuitem.connect("activate",self.props_activate)
180 johnpye 132 if not self.treecontext:
181     raise RuntimeError("Couldn't create browsercontext")
182     #--------------------
183     # set up the error view
184    
185 johnpye 168 self.errorview = glade.get_widget("errorview")
186 johnpye 132 errstorecolstypes = [gtk.gdk.Pixbuf,str,str,str,int]
187     self.errorstore = gtk.TreeStore(*errstorecolstypes)
188     errtitles = ["","Location","Message"];
189     self.errorview.set_model(self.errorstore)
190     self.errcols = [ gtk.TreeViewColumn() for _type in errstorecolstypes]
191    
192     i = 0
193     for tvcolumn in self.errcols[:len(errtitles)]:
194     tvcolumn.set_title(errtitles[i])
195     self.errorview.append_column(tvcolumn)
196    
197     if i>0:
198     _renderer = gtk.CellRendererText()
199     tvcolumn.pack_start(_renderer, True)
200     tvcolumn.add_attribute(_renderer, 'text', i)
201     if(i==2):
202     tvcolumn.add_attribute(_renderer, 'foreground', 3)
203     tvcolumn.add_attribute(_renderer, 'weight', 4)
204     else:
205     _renderer1 = gtk.CellRendererPixbuf()
206     tvcolumn.pack_start(_renderer1, False)
207     tvcolumn.add_attribute(_renderer1, 'pixbuf', int(0))
208    
209     i = i + 1
210    
211    
212     #--------------------
213     # set up the error reporter callback
214     self.reporter = ascend.getReporter()
215     self.reporter.setPythonErrorCallback(self.error_callback)
216    
217     #-------------------
218     # set up the module view
219    
220     self.modtank = {}
221     self.moduleview = glade.get_widget("moduleview")
222     modulestorecoltypes = [str, str]
223     self.modulestore = gtk.TreeStore(*modulestorecoltypes)
224     moduleviewtitles = ["Module name", "Filename"]
225     self.moduleview.set_model(self.modulestore)
226     self.modcols = [ gtk.TreeViewColumn() for _type in modulestorecoltypes]
227     i = 0
228     for modcol in self.modcols[:len(moduleviewtitles)]:
229     modcol.set_title(moduleviewtitles[i])
230     self.moduleview.append_column(modcol)
231     _renderer = gtk.CellRendererText()
232     modcol.pack_start(_renderer, True)
233     modcol.add_attribute(_renderer, 'text', i)
234     i = i + 1
235     self.moduleview.connect("row-activated", self.module_activated )
236    
237     #-------------------
238     # RE for units matching
239     self.units_re = re.compile("([-+]?(\d+(\.\d*)?|\d*\.d+)([eE][-+]?\d+)?)\s*(.*)");
240    
241     #--------------------
242     # set up the methods combobox
243    
244     self.methodstore = gtk.ListStore(str)
245     self.methodsel.set_model(self.methodstore)
246     _methodrenderer = gtk.CellRendererText()
247     self.methodsel.pack_start(_methodrenderer, True)
248     self.methodsel.add_attribute(_methodrenderer, 'text',0)
249    
250     #--------
251     # set up the instance browser view
252    
253     self.otank = {}
254     self.treeview = glade.get_widget("browserview")
255     columns = [str,str,str,str,int,bool]
256     self.treestore = gtk.TreeStore(*columns)
257     titles = ["Name","Type","Value"];
258     self.treeview.set_model(self.treestore)
259     self.tvcolumns = [ gtk.TreeViewColumn() for _type in columns[:len(titles)] ]
260    
261     self.treeview.connect("row-expanded", self.row_expanded )
262     self.treeview.connect("button-press-event", self.tree_click )
263    
264     # data columns are: name type value colour weight editable
265    
266     i = 0
267     for tvcolumn in self.tvcolumns[:len(titles)]:
268     tvcolumn.set_title(titles[i])
269     self.treeview.append_column(tvcolumn)
270    
271     renderer = gtk.CellRendererText()
272     tvcolumn.pack_start(renderer, True)
273     tvcolumn.add_attribute(renderer, 'text', i)
274     tvcolumn.add_attribute(renderer, 'foreground', 3)
275     tvcolumn.add_attribute(renderer, 'weight', 4)
276     if(i==2):
277     tvcolumn.add_attribute(renderer, 'editable', 5)
278     renderer.connect('edited',self.cell_edited_callback)
279     i = i + 1
280    
281    
282     if(len(args)==1):
283     self.do_open(args[0])
284    
285     print "Options: ",options
286    
287     if options.model:
288     try:
289     _t =self.library.findType(options.model);
290     self.do_sim(_t);
291     except RuntimeError, e:
292     self.reporter.reportError("Failed to create instance of '%s': %s" %(options.model, str(e)));
293    
294 johnpye 223
295 johnpye 132 def run(self):
296     self.window.show()
297     gtk.main()
298    
299     # --------------------------------------------
300     # MAJOR GUI COMMANDS
301    
302    
303     def do_open(self,filename):
304     # TODO does the user want to lose their work?
305     # TODO do we need to chdir?
306    
307 johnpye 164 _context = self.statusbar.get_context_id("do_open")
308    
309 johnpye 132 self.errorstore.clear()
310    
311     self.treestore.clear()
312     self.otank = {}
313    
314 johnpye 175 # self.library.clear()
315 johnpye 164
316     self.statusbar.push(_context,"Loading '"+filename+"'")
317 johnpye 132 self.library.load(filename)
318 johnpye 164 self.statusbar.pop(_context)
319 johnpye 132
320     self.filename = filename
321    
322     # Load the current list of modules into self.modules
323     self.modtank = {}
324     self.modulestore.clear()
325     modules = self.library.getModules()
326     for m in reversed(modules):
327     _n = str( m.getName() )
328     _f = str( m.getFilename() )
329     #print "ADDING ROW name %s, file = %s" % (_n, _f)
330     _r = self.modulestore.append(None, [ _n, _f ])
331     for t in self.library.getModuleTypes(m):
332     _n = t.getName()
333     #print "ADDING TYPE %s" % _n
334     _piter = self.modulestore.append(_r , [ _n, "" ])
335     _path = self.modulestore.get_path(_piter)
336     self.modtank[_path]=t
337    
338     #print "DONE ADDING MODULES"
339    
340     self.sim = None;
341     self.maintabs.set_current_page(0);
342 johnpye 164
343 johnpye 168 # See http://www.daa.com.au/pipermail/pygtk/2005-October/011303.html
344     # for details on how the 'wait cursor' is done.
345 johnpye 164 def start_waiting(self, message):
346     self.waitcontext = self.statusbar.get_context_id("waiting")
347     self.statusbar.push(self.waitcontext,message)
348    
349     if self.waitwin:
350     self.waitwin.show()
351    
352     while gtk.events_pending():
353     gtk.main_iteration()
354 johnpye 132
355 johnpye 164 def stop_waiting(self):
356     if self.waitwin:
357     self.statusbar.pop(self.waitcontext)
358     self.waitwin.hide()
359    
360 johnpye 132 def do_sim(self, type_object):
361     self.sim = None;
362     # TODO: clear out old simulation first!
363    
364     print "DO_SIM(%s)" % str(type_object.getName())
365 johnpye 164 self.start_waiting("Compiling...")
366    
367 johnpye 132 self.sim = type_object.getSimulation(str(type_object.getName())+"_sim")
368     print "...DONE 'getSimulation'"
369 johnpye 164 self.stop_waiting()
370 johnpye 132
371 johnpye 164 self.start_waiting("Building simulation...")
372 johnpye 132 print "BUILDING SIMULATION"
373 johnpye 164 self.sim.build()
374 johnpye 132 print "DONE BUILDING"
375 johnpye 164 self.stop_waiting()
376 johnpye 132
377 johnpye 223 self.sim.setSolver(ascend.Solver("QRSlv"))
378    
379 johnpye 132 # empty things out first
380     self.methodstore.clear()
381     self.treestore.clear()
382    
383     # methods
384     _methods = self.sim.getType().getMethods()
385 johnpye 160 _activemethod = None;
386 johnpye 132 for _m in _methods:
387 johnpye 160 _i = self.methodstore.append([_m.getName()])
388     if _m.getName()=="default_self":
389     self.methodsel.set_active_iter(_i)
390 johnpye 132
391     # instance hierarchy
392     self.otank = {} # map path -> (name,value)
393     self.make( self.sim.getName(),self.sim.getModel() )
394     self.maintabs.set_current_page(1);
395    
396     def do_solve(self):
397     if not self.sim:
398     self.reporter.reportError("No model selected yet")
399 johnpye 171 return;
400 johnpye 132
401 johnpye 168 self.start_waiting("Solving...")
402 johnpye 164
403 johnpye 154 self.sim.solve(ascend.Solver("QRSlv"))
404 johnpye 164
405 johnpye 168 self.stop_waiting()
406 johnpye 132 self.refreshtree()
407    
408     def do_check(self):
409     if not self.sim:
410     self.reporter.reportError("No model selected yet")
411    
412 johnpye 171 self.start_waiting("Checking system...")
413    
414 johnpye 132 if self.sim.check():
415     self.reporter.reportNote("System check OK")
416 johnpye 171
417 johnpye 132 self.sim.checkDoF()
418    
419 johnpye 171 self.stop_waiting()
420    
421 johnpye 132 self.refreshtree()
422    
423     def do_method(self,method):
424     if not self.sim:
425     self.reporter.reportError("No model selected yet")
426    
427     self.sim.run(method)
428     self.refreshtree()
429    
430     # --------------------------------------------
431     # MODULE LIST
432    
433     def module_activated(self, treeview, path, column, *args):
434     modules = self.library.getModules()
435     print "PATH",path
436     if len(path)==1:
437     self.reporter.reportNote("Launching of external editor not yet implemented")
438     elif len(path)==2:
439     if(self.modtank.has_key(path)):
440     _type = self.modtank[path];
441     self.reporter.reportNote("Creating simulation for type %s" % str(_type.getName()) )
442     self.do_sim(_type)
443     else:
444     self.reporter.reportError("Didn't find type corresponding to row")
445    
446     # --------------------------------------------
447     # INSTANCE TREE
448    
449     def get_tree_row_data(self,instance):
450     _value = str(instance.getValue())
451     _type = str(instance.getType())
452     _name = str(instance.getName())
453     _fgcolor = "black"
454     _fontweight = pango.WEIGHT_NORMAL
455     _editable = False
456     if instance.getType().isRefinedSolverVar():
457     _editable = True
458     if instance.isFixed():
459     _fgcolor = "#008800"
460     _fontweight = pango.WEIGHT_BOLD
461     else:
462     _fgcolor = "#000088"
463     _fontweight = pango.WEIGHT_BOLD
464     elif instance.isBool() or instance.isReal() or instance.isInt():
465     # TODO can't edit constants that have already been refined
466     _editable = True
467    
468     #if(len(_value) > 80):
469     # _value = _value[:80] + "..."
470    
471     return [_name, _type, _value, _fgcolor, _fontweight, _editable]
472    
473     def get_error_row_data(self,sev,filename,line,msg):
474     _sevicon = {
475     0: self.iconok
476     ,1: self.iconinfo
477     ,2: self.iconwarning
478     ,3: self.iconerror
479     ,4: self.iconinfo
480     ,5: self.iconwarning
481     ,6: self.iconerror
482     }[sev]
483    
484     _fontweight = pango.WEIGHT_NORMAL
485     if sev==6:
486     _fontweight = pango.WEIGHT_BOLD
487    
488     _fgcolor = "black"
489     if sev==4:
490     _fgcolor = "#888800"
491     elif sev==5:
492     _fgcolor = "#884400"
493     elif sev==6:
494     _fgcolor = "#880000"
495     elif sev==0:
496     _fgcolor = "#008800"
497    
498     if not filename and not line:
499     _fileline = ""
500     else:
501     if(len(filename) > 25):
502     filename = "..."+filename[-22:]
503     _fileline = filename + ":" + str(line)
504    
505     _res = [_sevicon,_fileline,msg.rstrip(),_fgcolor,_fontweight]
506     #print _res
507     return _res
508    
509     def make_row( self, piter, name, value ):
510    
511     _piter = self.treestore.append( piter, self.get_tree_row_data(value) )
512     return _piter
513    
514     def refreshtree(self):
515     # @TODO FIXME use a better system than colour literals!
516     for _path in self.otank: # { path : (name,value) }
517     _iter = self.treestore.get_iter(_path)
518     _name, _instance = self.otank[_path]
519     self.treestore.set_value(_iter, 2, _instance.getValue())
520     if _instance.getType().isRefinedSolverVar():
521     if _instance.isFixed() and self.treestore.get_value(_iter,3)=="#000088":
522     self.treestore.set_value(_iter,3,"#008800")
523     elif not _instance.isFixed() and self.treestore.get_value(_iter,3)=="#008800":
524     self.treestore.set_value(_iter,3,"#000088")
525    
526     def cell_edited_callback(self, renderer, path, newtext, **kwargs):
527     # get back the Instance object we just edited (having to use this seems like a bug)
528     path = tuple( map(int,path.split(":")) )
529    
530     if not self.otank.has_key(path):
531     raise RuntimeError("cell_edited_callback: invalid path '%s'" % path)
532     return
533    
534     _name, _instance = self.otank[path]
535    
536     if _instance.isReal():
537     # only real-valued things can have units
538    
539     try:
540     # match a float with option text afterwards, optionally separated by whitespace
541     _match = re.match(self.units_re,newtext)
542     if not _match:
543     self.reporter.reportError("Not a valid value-and-optional-units")
544     return
545    
546     _val = _match.group(1)
547     _units = _match.group(5)
548     #_val, _units = re.split("[ \t]+",newtext,2);
549     except RuntimeError:
550     self.reporter.reportError("Unable to split value and units")
551     return
552     print "val = ",_val
553     print "units = ",_units
554    
555     # parse the units, throw an error if no good
556     try:
557     _val = float(_val)
558     except RuntimeError:
559     self.reporter.reportError("Unable to convert number part '%s' to float" % _val)
560    
561     if _units.strip() == "":
562     _u = _instance.getType().getPreferredUnits()
563     if _u == None:
564     _u = _instance.getDimensions().getDefaultUnits()
565     self.reporter.reportNote("Assuming units '%s'" % _u.getName().toString() )
566     else:
567     try:
568     _u = ascend.Units(_units)
569     self.reporter.reportNote("Parsed units %s" % _units)
570     except RuntimeError:
571     self.reporter.reportError("Unrecognisable units '%s'" % _units)
572     return
573    
574     if _instance.getDimensions() != _u.getDimensions():
575    
576     if _u.getDimensions().isDimensionless():
577     _units = "[dimensionless]"
578    
579     _my_dims = _instance.getDimensions().getDefaultUnits()
580     if _instance.getDimensions().isDimensionless():
581     _my_dims = "[dimensionless]"
582    
583     self.reporter.reportError("Incompatible units '%s' (must fit with '%s')"
584     % (_units, _my_dims) )
585     return
586    
587     if _units.strip() != "" and not _instance.getDimensions().isDimensionless():
588     self.prefs.setPreferredUnits(str(_instance.getType().getName()), _units);
589    
590     _conv = float(_u.getConversion())
591     # self.reporter.reportNote("Converting: multiplying '%s %s' by factor %s to get SI units" % (_val, _units, _conv) )
592     _val = _val * _conv;
593    
594     self.reporter.reportNote("Setting '%s' to '%f'" % (_name, _val))
595    
596     if _instance.getType().isRefinedSolverVar():
597     # set the 'fixed' flag as well
598     _instance.setFixedValue(float(_val))
599     else:
600     _instance.setRealValue(float(_val))
601     else:
602     if _instance.isBool():
603     _lower = newtext.lower();
604     if _lower.startswith("t") or _lower.startswith("y") or _lower.strip()=="1":
605     newtext = 1
606     elif _lower.startswith("f") or _lower.startswith("n") or _lower.strip()=="0":
607     newtext = 0
608     else:
609     self.reporter.reportError("Invalid entry for a boolean variable: '%s'" % newtext)
610     return
611     _val = bool(newtext);
612     if _val == _instance.getValue():
613     self.reporter.reportNote("Boolean atom '%s' was not altered" % _instance.getName())
614     return
615     _instance.setBoolValue(_val)
616    
617     elif _instance.isInt():
618     _val = int(newtext)
619     if _val == _instance.getValue():
620     self.reporter.reportNote("Integer atom '%s' was not altered" % _instance.getName())
621     return
622     _instance.setIntValue(_val)
623     else:
624     self.reporter.reportError("Attempt to set a non-real, non-boolean, non-integer value!")
625     return
626    
627     # now that the variable is set, update the GUI and re-solve if desired
628     _iter = self.treestore.get_iter(path)
629     self.treestore.set_value(_iter,2,_instance.getValue())
630    
631     if _instance.getType().isRefinedSolverVar():
632     self.treestore.set_value(_iter,3,"#008800") # set the row green as fixed
633    
634     if self.autotoggle.get_active():
635     self.sim.check()
636     self.do_solve()
637     #self.reporter.reportError("SOLVER completed")
638    
639    
640     def make_children(self, value, piter ):
641     if value.isCompound():
642     children=value.getChildren();
643     for child in children:
644     _name = child.getName();
645     _piter = self.make_row(piter,_name,child)
646     _path = self.treestore.get_path(_piter)
647     self.otank[_path]=(_name,child)
648     #self.reporter.reportError("2 Added %s at path %s" % (_name,repr(_path)))
649    
650     def make(self, name=None, value=None, path=None, depth=1):
651     if path is None:
652     # make root node
653     piter = self.make_row( None, name, value )
654     path = self.treestore.get_path( piter )
655     self.otank[ path ] = (name, value)
656     #self.reporter.reportError("4 Added %s at path %s" % (name, path))
657     else:
658     name, value = self.otank[ path ]
659    
660     piter = self.treestore.get_iter( path )
661     if not self.treestore.iter_has_child( piter ):
662     self.make_children(value,piter)
663    
664     if depth:
665     for i in range( self.treestore.iter_n_children( piter ) ):
666     self.make( path = path+(i,), depth = depth - 1 )
667 johnpye 160 else:
668     self.treeview.expand_row("0",False)
669 johnpye 132
670     def row_expanded( self, treeview, piter, path ):
671     self.make( path = path )
672    
673     # ----------------------------------
674     # ERROR PANEL
675    
676     def error_callback(self,sev,filename,line,msg):
677     pos = self.errorstore.append(None, self.get_error_row_data(sev, filename,line,msg))
678     path = self.errorstore.get_path(pos)
679     col = self.errorview.get_column(3)
680     self.errorview.scroll_to_cell(path,col)
681    
682     return 0;
683    
684     # --------------------------------
685     # BUTTON METHODS
686    
687     def open_click(self,*args):
688     dialog = gtk.FileChooserDialog("Open file...",
689 johnpye 160 None,
690     gtk.FILE_CHOOSER_ACTION_OPEN,
691     (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
692     gtk.STOCK_OPEN, gtk.RESPONSE_OK))
693 johnpye 132 dialog.set_default_response(gtk.RESPONSE_OK)
694    
695     filter = gtk.FileFilter()
696     filter.set_name("*.a4c, *.a4l")
697     filter.add_pattern("*.[Aa]4[Cc]")
698     filter.add_pattern("*.[Aa]4[Ll]")
699     dialog.add_filter(filter)
700    
701     filter = gtk.FileFilter()
702     filter.set_name("All files")
703     filter.add_pattern("*")
704     dialog.add_filter(filter)
705    
706     response = dialog.run()
707     _filename = dialog.get_filename()
708     dialog.destroy()
709    
710     if response == gtk.RESPONSE_OK:
711     self.reporter.reportNote("File %s selected." % dialog.get_filename() )
712 johnpye 185 self.library.clear()
713 johnpye 132 self.do_open( _filename)
714    
715    
716     def reload_click(self,*args):
717     _type = None
718     if(self.sim):
719     _type = self.sim.getType().getName().toString();
720    
721 johnpye 185 self.library.clear()
722 johnpye 132 self.do_open(self.filename)
723    
724     if _type:
725     _t = self.library.findType(_type)
726     self.do_sim(_t)
727    
728     def solve_click(self,*args):
729     #self.reporter.reportError("Solving simulation '" + self.sim.getName().toString() +"'...")
730     self.do_solve()
731    
732     def check_click(self,*args):
733     self.do_check()
734     #self.reporter.reportError("CHECK clicked")
735    
736 johnpye 208 def preferences_click(self,*args):
737     if not self.sim:
738     self.reporter.reportError("No simulation created yet!");
739    
740 johnpye 223 _paramswin = SolverParametersWindow(self.sim, self.reporter)
741     _paramswin.show()
742 johnpye 221
743 johnpye 132 def methodrun_click(self,*args):
744     _sel = self.methodsel.get_active_text()
745     if _sel:
746     _method = None
747     _methods = self.sim.getType().getMethods()
748     for _m in _methods:
749     if _m.getName()==_sel:
750     _method = _m
751     if not _method:
752     self.reporter.reportError("Method is not valid")
753     return
754     self.do_method(_method)
755     else:
756     self.reporter.reportError("No method selected")
757    
758     def auto_toggle(self,button,*args):
759     if button.get_active():
760 johnpye 168 self.reporter.reportSuccess("Auto mode is now ON")
761 johnpye 132 else:
762 johnpye 168 self.reporter.reportSuccess("Auto mode is now OFF")
763 johnpye 132
764     # ------------------------------
765     # CONTEXT MENU
766    
767     def tree_click(self,widget,event):
768     # which button was clicked?
769     if event.button == 3:
770     _x = int(event.x)
771     _y = int(event.y)
772     _time = event.time
773     _pthinfo = self.treeview.get_path_at_pos(_x, _y)
774     if _pthinfo != None:
775 johnpye 172 _canpop = False;
776 johnpye 132 _path, _col, _cellx, _celly = _pthinfo
777     # self.reporter.reportError("Right click on %s" % self.otank[_path][0])
778     _instance = self.otank[_path][1]
779     if _instance.getType().isRefinedSolverVar():
780 johnpye 172 _canpop = True;
781 johnpye 132 if _instance.isFixed():
782 johnpye 181 self.fixmenuitem.set_sensitive(False)
783     self.freemenuitem.set_sensitive(True)
784 johnpye 132 else:
785 johnpye 181 self.fixmenuitem.set_sensitive(True)
786     self.freemenuitem.set_sensitive(False)
787 johnpye 207 elif _instance.isRelation():
788     _canpop = True;
789     self.propsmenuitem.set_sensitive(True)
790 johnpye 175 else:
791 johnpye 181 self.fixmenuitem.set_sensitive(False)
792     self.freemenuitem.set_sensitive(False)
793 johnpye 172
794     if _instance.isPlottable():
795 johnpye 181 self.plotmenuitem.set_sensitive(True)
796 johnpye 172 _canpop = True;
797     else:
798 johnpye 181 self.plotmenuitem.set_sensitive(False)
799 johnpye 172
800     if _canpop:
801     self.treeview.grab_focus()
802     self.treeview.set_cursor( _path, _col, 0)
803 johnpye 132 self.treecontext.popup( None, None, None, event.button, _time)
804     return 1
805    
806     def fix_activate(self,widget):
807     _path,_col = self.treeview.get_cursor()
808     _name, _instance = self.otank[_path]
809     _instance.setFixed(True)
810     self.reporter.reportNote("Fixed variable %s" % _instance.getName().toString())
811     if self.autotoggle.get_active():
812     self.sim.check()
813     self.do_solve()
814     else:
815     self.refreshtree()
816     return 1
817    
818     def free_activate(self,widget):
819     _path,_col = self.treeview.get_cursor()
820     _instance = self.otank[_path][1]
821     _instance.setFixed(False)
822     self.reporter.reportNote("Freed variable %s" % _instance.getName().toString())
823     if self.autotoggle.get_active():
824     self.sim.check()
825     self.do_solve()
826     else:
827     self.refreshtree()
828     return 1
829    
830 johnpye 172 def plot_activate(self,widget):
831 johnpye 175 self.reporter.reportNote("plot_activate...");
832 johnpye 172 _path,_col = self.treeview.get_cursor()
833     _instance = self.otank[_path][1]
834     if not _instance.isPlottable():
835 johnpye 175 self.reporter.reportError("Can't plot instance %s" % _instance.getName().toString())
836 johnpye 172 return
837 johnpye 175 else:
838     self.reporter.reportNote("Instance %s about to be plotted..." % _instance.getName().toString())
839 johnpye 172
840 johnpye 175 print("Plotting instance '%s'..." % _instance.getName().toString())
841    
842 johnpye 176 _plot = _instance.getPlot()
843 johnpye 175
844 johnpye 176 print "Title: ", _plot.getTitle()
845 johnpye 180 _plot.show(True)
846 johnpye 176
847 johnpye 172 return 1
848    
849 johnpye 181 def props_activate(self,widget):
850 johnpye 207 _path,_col = self.treeview.get_cursor()
851     _instance = self.otank[_path][1]
852     if _instance.isRelation():
853 johnpye 215 print "Relation '"+_instance.getName().toString()+"':", \
854     _instance.getRelationAsString(self.sim.getModel())
855 johnpye 207 else:
856     self.reporter.reportWarning("props_activate not implemented")
857 johnpye 172
858    
859 johnpye 132 # ---------------------------------
860     # WINDOW-LEVEL ACTIONS
861    
862     def delete_event(self, widget, event, data=None):
863     self.reporter.clearPythonErrorCallback()
864 johnpye 172 _w,_h = self.window.get_size()
865     _t,_l = self.window.get_position()
866 johnpye 173 _display = self.window.get_screen().get_display().get_name()
867     self.prefs.setGeometrySizePosition(_display,"browserwin",_w,_h,_t,_l );
868 johnpye 132
869 johnpye 173 _p = self.browserpaned.get_position()
870     self.prefs.setGeometryValue(_display,"browserpaned",_p);
871    
872 johnpye 132 # causes prefs to be saved unless they are still being used elsewher
873     del(self.prefs)
874    
875     gtk.main_quit()
876     print "GTK QUIT"
877     return False
878    
879 johnpye 223 #======================================================
880     # SOLVER PARAMETERS WINDOW
881    
882     class SolverParametersWindow:
883     def __init__(self,sim,reporter):
884     self.sim = sim
885     self.params = self.sim.getSolverParameters();
886    
887     self.reporter = reporter
888    
889     _xml = gtk.glade.XML(GLADE_FILE,"paramswin")
890     self.window = _xml.get_widget("paramswin")
891 johnpye 227 self.paramdescription = _xml.get_widget("paramdescription")
892     self.solvername = _xml.get_widget("solvername")
893 johnpye 223 _xml.signal_autoconnect(self)
894 johnpye 227
895     self.solvername.set_text(self.sim.getSolver().getName())
896 johnpye 223
897     self.paramsview = _xml.get_widget("paramsview")
898     self.otank = {}
899 johnpye 227 self.paramstore = gtk.TreeStore(str,str,str,bool,str,int)
900 johnpye 223 self.paramsview.set_model(self.paramstore)
901    
902     # name column
903     _renderer0 = gtk.CellRendererText()
904 johnpye 227 _col0 = gtk.TreeViewColumn("Name", _renderer0, text=0, background=4, weight=5)
905 johnpye 223 self.paramsview.append_column(_col0)
906    
907     # value column: 'editable' set by column 3 of the model data.
908 johnpye 225 _renderer1 = gtk.CellRendererText()
909     _renderer1.connect('edited',self.on_paramsview_edited)
910     _col1 = gtk.TreeViewColumn("Value", _renderer1, text=1, editable=3, background=4)
911 johnpye 223 self.paramsview.append_column(_col1)
912    
913     # range column
914     _renderer2 = gtk.CellRendererText()
915 johnpye 225 _col2 = gtk.TreeViewColumn("Range", _renderer2, text=2, background=4)
916 johnpye 223 self.paramsview.append_column(_col2)
917    
918     self.populate()
919    
920 johnpye 227 self.paramsview.expand_all()
921 johnpye 226
922 johnpye 227 #def on_paramswin_key_press_event(self,widget,event):
923     # if event.keyval == ESCAPE_KEY:
924     # if not gtk.gdk.events_pending():
925     # self.do_destroy()
926    
927 johnpye 226 def on_paramsview_row_activated(self,treeview,path,view_column,*args,**kwargs):
928     # get back the object we just clicked
929    
930     if not self.otank.has_key(path):
931     return
932    
933     _iter,_param = self.otank[path]
934    
935     if _param.isBool():
936     newvalue = not _param.getBoolValue()
937     _param.setBoolValue(newvalue)
938 johnpye 227 if newvalue:
939     self.paramstore.set_value(_iter,1,SOLVERPARAM_BOOL_TRUE)
940     else:
941     self.paramstore.set_value(_iter,1,SOLVERPARAM_BOOL_FALSE)
942 johnpye 226 self.paramstore.set_value(_iter,4, CHANGED_COLOR)
943    
944     def on_paramsview_button_press_event(self,widget,event):
945     if event.button == 1:
946     _x = int(event.x)
947     _y = int(event.y)
948     _time = event.time
949     _pathinfo = self.paramsview.get_path_at_pos(_x, _y)
950     if _pathinfo != None:
951     _path, _col, _cellx, _celly = _pathinfo
952 johnpye 227 if not self.otank.has_key(_path):
953     return
954 johnpye 226 _iter, _param = self.otank[_path]
955 johnpye 227
956     # update the description field
957     self.paramdescription.set_text(_param.getDescription())
958    
959 johnpye 226 if _param.isStr():
960     _menu = gtk.Menu();
961     _head = gtk.ImageMenuItem("Options",True)
962     _head.show()
963     _head.set_sensitive(False)
964     _img = gtk.Image()
965     _img.set_from_file('icons/folder-open.png')
966     _head.set_image(_img)
967     _menu.append(_head)
968     _sep = gtk.SeparatorMenuItem(); _sep.show()
969     _menu.append(_sep);
970    
971     _item = None;
972     for i in _param.getStrOptions():
973     _item = gtk.RadioMenuItem(group=_item, label=i);
974     if i == _param.getStrValue():
975     _item.set_active(True)
976     else:
977     _item.set_active(False)
978     _item.show()
979     _item.connect('activate', self.on_menu_activate, _param, _iter, i);
980     _menu.append(_item)
981    
982     _menu.show()
983     _menu.popup(None, None, None, event.button, _time)
984    
985     def on_menu_activate(self, menuitem, param, iter, newvalue):
986     if param.getStrValue() != newvalue:
987     param.setStrValue(newvalue)
988     self.paramstore.set_value(iter, 1, newvalue)
989     self.paramstore.set_value(iter, 4, CHANGED_COLOR)
990     else:
991     print "NOT CHANGED"
992 johnpye 227
993     def on_paramsview_cursor_changed(self, *args, **kwargs):
994     _path, _col = self.paramsview.get_cursor()
995     if not self.otank.has_key(_path):
996     self.paramdescription.set_text("")
997     return
998     _iter, _param = self.otank[_path]
999     self.paramdescription.set_text(_param.getDescription())
1000     #self.paramsview.set_cursor(_path,self.paramsview.get_column(1));
1001 johnpye 226
1002 johnpye 225 def on_paramsview_edited(self, renderer, path, newtext, **kwargs):
1003     # get back the Instance object we just edited (having to use this seems like a bug)
1004     path = tuple( map(int,path.split(":")) )
1005    
1006     if not self.otank.has_key(path):
1007     raise RuntimeError("cell_edited_callback: invalid path '%s'" % path)
1008     return
1009    
1010     _iter,_param = self.otank[path]
1011     # you can only edit real, int, str:
1012    
1013     _changed = False
1014     if _param.isInt():
1015     newvalue = int(newtext)
1016     if _param.isBounded():
1017     if newvalue > _param.getIntUpperBound():
1018     self.doErrorDialog("The entered value '%d' is above the upper bound." % newvalue)
1019     return False
1020     if newvalue < _param.getIntLowerBound():
1021     self.doErrorDialog("The entered value '%d' is below the lower bound." % newvalue)
1022     return False
1023     if _param.getIntValue() != newvalue:
1024     _param.setIntValue(newvalue)
1025     _changed = True
1026     elif _param.isReal():
1027     newvalue = float(newtext)
1028     if _param.isBounded():
1029     if newvalue > _param.getRealUpperBound():
1030     self.doErrorDialog("The entered value '%f' is above the upper bound." % newvalue)
1031     return False
1032     if newvalue < _param.getRealLowerBound():
1033     self.doErrorDialog("The entered value '%f' is below the lower bound." % newvalue)
1034     return False
1035     if _param.getRealValue() != newvalue:
1036     _param.setRealValue(newvalue)
1037     _changed = True
1038     elif _param.isStr():
1039     newvalue = str(newtext)
1040     if _param.getStrValue() != newvalue:
1041     _param.setStrValue(newvalue)
1042     _changed = True
1043    
1044     if _changed:
1045     self.paramstore.set_value(_iter, 1, newvalue)
1046 johnpye 226 self.paramstore.set_value(_iter, 4, CHANGED_COLOR)
1047 johnpye 225 else:
1048     print "NO CHANGE"
1049 johnpye 227
1050 johnpye 225
1051 johnpye 223 def create_row_data(self,p):
1052     _row = [p.getLabel()];
1053     if p.isStr():
1054 johnpye 226 _row.extend([p.getStrValue(), str(len(p.getStrOptions()))+" options", False]);
1055 johnpye 223 elif p.isBool():
1056     if p.getBoolValue():
1057 johnpye 227 _val = SOLVERPARAM_BOOL_TRUE
1058 johnpye 223 else:
1059 johnpye 227 _val = SOLVERPARAM_BOOL_FALSE
1060 johnpye 223 _row.extend([_val,"",False])
1061     elif p.isReal():
1062 johnpye 227 if not p.isBounded():
1063 johnpye 223 _row.extend([str(p.getRealValue()), "",True])
1064     else:
1065     _row.extend([str(p.getRealValue()), "[ "+str(p.getRealLowerBound())+", "+str(p.getRealUpperBound())+" ]",True])
1066     elif p.isInt():
1067 johnpye 227 if not p.isBounded():
1068 johnpye 223 _row.extend([str(p.getIntValue()), "", True])
1069     else:
1070     _row.extend([str(p.getIntValue()), "[ "+str(p.getIntLowerBound())+", "+str(p.getIntLowerBound())+" ]", True])
1071    
1072     else:
1073     raise RuntimeError("invalid type")
1074 johnpye 225
1075 johnpye 227 _row.extend(["white",pango.WEIGHT_NORMAL])
1076 johnpye 223 return _row;
1077    
1078     def populate(self):
1079     # Fill the paramstore with data
1080    
1081 johnpye 227 data = {}
1082 johnpye 223 for i in self.params:
1083 johnpye 227 if not data.has_key(i.getPage()):
1084     data[i.getPage()] = {}
1085     data[i.getPage()][i.getNumber()] = i;
1086 johnpye 223
1087 johnpye 227 _pagenum = 1;
1088     for _page in sorted(data.keys()):
1089     if len(data[_page].keys()):
1090     _pageiter = self.paramstore.append( None, ["Page "+str(_pagenum), "", "", False, "white", pango.WEIGHT_BOLD])
1091     for _number in sorted(data[_page].keys()):
1092     _param = data[_page][_number]
1093     _piter = self.paramstore.append( _pageiter, self.create_row_data(_param) )
1094     _path = self.paramstore.get_path(_piter)
1095     self.otank[ _path ] = (_piter, _param)
1096     _pagenum = _pagenum + 1
1097 johnpye 223
1098     def show(self):
1099     self.window.show()
1100    
1101 johnpye 227 def on_paramscancel_clicked(self,*args,**kwargs):
1102 johnpye 223 self.do_destroy()
1103    
1104 johnpye 227 def on_paramsapply_clicked(self,*args,**kwargs):
1105 johnpye 225 self.sim.setSolverParameters(self.params);
1106     self.do_destroy()
1107 johnpye 223
1108     def on_paramswin_destroy(self,*args,**kwargs):
1109     self.do_destroy()
1110    
1111     def do_destroy(self):
1112     self.window.hide()
1113     del(self.window)
1114     del(self.params)
1115    
1116 johnpye 132 def test():
1117     import ascend
1118     b = Browser();
1119     b.run()
1120    
1121     if __name__ == "__main__":
1122     test()

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