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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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