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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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