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

Contents of /trunk/pygtk/interface/gtkbrowser.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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