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

Contents of /trunk/pygtk/gtkbrowser.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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