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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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