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

Contents of /trunk/pygtk/gtkbrowser.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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