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

Contents of /trunk/pygtk/gtkbrowser.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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