/[ascend]/branches/python3/pygtk/gtkbrowser.py
ViewVC logotype

Contents of /branches/python3/pygtk/gtkbrowser.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3483 - (show annotations) (download) (as text)
Sun Aug 15 06:40:34 2021 UTC (5 months, 1 week ago) by jpye
File MIME type: text/x-python
File size: 52306 byte(s)
created new 'a4' convenient script which is intended to be used whenever running ascend in a development environment.
cleaning up path-checking stuff from test.py and ascdev.in, consolidated in a4 script now.
explicitly request gtksourceview 3 in moduleview (we need a sourceview 4 syntax definition...)
preferences uses 'ConfigParser' now, 'SafeConfigParser' has been renamed.
gtkbrowser uses time.perf_counter now.

1 import sys
2
3 try:
4 import loading
5 #loading.print_status("Loading PSYCO")
6 #try:
7 # import psyco
8 # psyco.full()
9 # print "Running with PSYCO optimisation..."
10 #except ImportError:
11 # pass
12
13 loading.print_status("Loading python standard libraries")
14
15 import gi
16 gi.require_version('Gtk', '3.0')
17 from gi.repository import Gtk, GdkPixbuf, Gdk, GLib
18
19 import re
20 import urllib.parse
21 import optparse
22 import platform
23 import sys
24 import time
25 import threading
26
27 if platform.system() != "Windows":
28 try:
29 import dl
30 _dlflags = dl.RTLD_GLOBAL|dl.RTLD_NOW
31 except:
32 # On platforms that unilaterally refuse to provide the 'dl' module
33 # we'll just set the value and see if it works.
34 loading.print_status("Setting dlopen flags","Python 'dl' module not available on this system")
35 _dlflags = 258
36 # This sets the flags for dlopen used by python so that the symbols in the
37 # ascend library are made available to libraries dlopened within ASCEND:
38 sys.setdlopenflags(_dlflags)
39
40
41
42 loading.print_status("Loading LIBASCEND/ascpy")
43 import ascpy
44 import os.path
45
46 loading.print_status("Loading PyGI, pango")
47
48 from gi.repository import Pango
49
50 loading.load_matplotlib()
51
52 loading.print_status("Loading ASCEND python modules")
53 from preferences import * # loading/saving of .ini options
54 from solverparameters import * # 'solver parameters' window
55 from help import * # viewing help files
56 from incidencematrix import * # incidence/sparsity matrix matplotlib window
57 from imagewindow import * # image viewer window
58 from observer import * # observer tab support
59 from properties import * # solver_var properties dialog
60 from varentry import * # for inputting of variables with units
61 from diagnose import * # for diagnosing block non-convergence
62 from solverreporter import * # solver status reporting
63 from moduleview import * # module browser
64 from modelview import * # model browser
65 from integrator import * # integrator dialog
66 from infodialog import * # general-purpose textual information dialog
67 from versioncheck import * # version check (contacts ascend.cruncher2.dyndns.org)
68 from unitsdialog import * # general-purpose textual information dialog
69 from solverhooks import * # solver hooks for use from Python layer
70 import config
71
72 #loading.complete();
73
74 except RuntimeError as e:
75 print("ASCEND had problems starting up. Please report the following")
76 print("error message on ASCEND bug tracker.")
77 print(("\n\nFull error message:",str(e)))
78 print("\n\nPress ENTER to close this window.")
79 sys.stdout.flush()
80 sys.stdin.readline();
81 sys.exit();
82
83 except ImportError as e:
84 print("\n\n------------------ ERROR ---------------------")
85 print("ASCEND had problems importing required Python modules.")
86 print("\nPlease ensure you have all the runtime prerequisites installed.")
87 print("Please then report a bug if you continue to have problems.")
88 print(("\nFull error message:",str(e)))
89 #if platform.system()=="Windows":
90 # print "\nYou will also need to report the contents of any popup error"
91 # print "messages from Windows if any were shown."
92 print("\n\nPress ENTER to close this window.")
93 sys.stdout.flush()
94 sys.stdin.readline();
95 sys.exit();
96
97 loading.print_status("Starting GUI")
98
99 # This is my first ever GUI code so please be nice :)
100 # But I *have* at least read
101 # http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html
102 # and leafed through
103 # http://developer.gnome.org/projects/gup/hig/
104
105 # The fancy tree-view gizmo is the GtkTreeView object. See the article
106 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/300304
107 # for the original source code on which my implementation was based.
108
109 ESCAPE_KEY = 65307
110
111 HELP_ROOT = None
112
113 #======================================
114 # Browser is the main ASCEND library/model browser window
115
116 class Browser:
117
118 # ---------------------------------
119 # SETUP
120
121 def __init__(self,librarypath=None,assetspath=None):
122
123 if assetspath==None:
124 assetspath=config.PYGTK_ASSETS
125
126 #--------
127 # load the file referenced in the command line, if any
128
129 loading.print_status("Parsing options","CONFIG = %s"%config.VERSION)
130
131 #print "Command-line options:",sys.argv
132
133 parser = optparse.OptionParser(usage="%prog [[-m typename] file]", version="gtkbrowser $rev$" )
134 # add options here if we want
135
136 #print "About to parse..."
137
138 if platform.system() == "Darwin":
139 parser.add_option("-p", "--silly-mac-thing"
140 ,action="store", type="string", dest="process_number"
141 ,help="Launch Services for Mac passes in a -psn-NNNNN argument that we need to swallow.")
142
143 parser.add_option("-m", "--model"
144 ,action="store", type="string", dest="model"
145 ,help="specify the model to instantiate upon loading modules")
146
147 parser.add_option("--pygtk-assets"
148 ,action="store", type="string", dest="assets_dir"
149 ,help="override the configuration value for the location of assets"\
150 +" required by PyGTK for the ASCEND GUI, optional"
151 ,default=assetspath
152 )
153
154 parser.add_option("--library"
155 ,action="store", type="string", dest="library_path"
156 ,help="override the configuration value for the library path"
157 ,default=librarypath
158 )
159
160 parser.add_option("--no-auto-sim"
161 ,action="store_false", dest="auto_sim"
162 ,help="disable auto-instantiation of MODEL named as the file stem"
163 ,default=True
164 )
165
166 parser.add_option("-t", "--test"
167 ,action="store", type="string", dest="test"
168 ,help="load a model and run contained tests without GUI")
169
170 (self.options, args) = parser.parse_args()
171
172 if len(args)>=1:
173 if os.path.isfile(args[0])==False:
174 error = '\033[91mERROR : %s is not a file\033[0m'%args[0]
175 print(error)
176 sys.exit()
177
178 #print "OPTIONS_______________:",self.options
179
180 self.assets_dir = self.options.assets_dir
181 #loading.create_window(self.assets_dir)
182
183 self.observers = []
184 self.currentobservertab = None
185 self.clip = None
186
187 #--------
188 # load up the preferences ini file
189
190 loading.print_status("Loading preferences")
191
192 self.prefs = Preferences()
193 _prefpath = self.prefs.getStringPref("Directories","librarypath",None)
194 _preffileopenpath = self.prefs.getStringPref("Directories","fileopenpath",None)
195 self.filename = None
196
197 #--------
198 # set up library path and the path to use for File->Open dialogs
199
200 if self.options.library_path != None:
201 _path = os.path.abspath(self.options.library_path)
202 _pathsrc = "command line options"
203 # when a special path is specified, use the last path component as the file-open location
204 if platform.system()=="Windows":
205 self.fileopenpath = _path.split(":").pop()
206 else:
207 self.fileopenpath = _path.split(":").pop()
208 else:
209 if _prefpath:
210 _path = _prefpath
211 _pathsrc = "user preferences"
212 else:
213 # default setting, but override with Windows registry if present
214 _path = config.LIBRARY_PATH
215 _pathsrc = "default (config.py)"
216
217 if platform.system()=="Windows":
218 # use the registry
219 try:
220 import winreg
221 x=winreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)
222 y= winreg.OpenKey(x,r"SOFTWARE\ASCEND")
223 _regpath,t = winreg.QueryValueEx(y,"ASCENDLIBRARY")
224 winreg.CloseKey(y)
225 winreg.CloseKey(x)
226 _path = _regpath
227 os.environ['ASCENDLIBRARY'] = _regpath
228 _pathsrc = "Windows registry"
229 except:
230 # otherwise keep using the default
231 pass
232
233 if _preffileopenpath:
234 self.fileopenpath = _preffileopenpath
235 else:
236 self.fileopenpath = _path
237
238 #--------
239 # Create the ASCXX 'Library' object
240
241 loading.print_status("Creating ASCEND 'Library' object","ASCENDLIBRARY = "+_path+" FROM "+_pathsrc)
242 self.library = ascpy.Library(str(_path))
243
244 self.sim = None
245
246 #-------------------
247 # Set up the window and main widget actions
248 self.glade_file = os.path.join(self.assets_dir,config.GLADE_FILE)
249
250 loading.print_status("Setting up windows") #,"GLADE_FILE = %s" % self.glade_file)
251
252 builder = Gtk.Builder()
253 #builder.add_from_file(self.glade_file)
254 builder.add_objects_from_file(self.glade_file,["integ_icon","browserwin","list_of_td"])
255 self.builder=builder
256 self.window=self.builder.get_object ("browserwin")
257
258 self.disable_menu()
259 self.disable_on_first_run()
260 if not self.window:
261 raise RuntimeError("Couldn't load window from glade file")
262
263 _display = self.window.get_screen().get_display().get_name()
264 _geom=self.prefs.getGeometrySizePosition(_display,"browserwin")
265 if _geom:
266 self.window.resize(_geom[0],_geom[1])
267 self.window.move(_geom[2],_geom[3])
268
269 self.window.connect("delete_event", self.delete_event)
270
271 self.browserpaned=self.builder.get_object ("browserpaned")
272 _geom2=self.prefs.getGeometryValue(_display,"browserpaned")
273 if _geom2:
274 self.browserpaned.set_position(_geom2)
275
276 buttons = ["open","reload","solve","integrate","check","methodrun"]
277 for n in buttons:
278 name = "%sbutton"%n
279 setattr(self,name,self.builder.get_object(name))
280 getattr(self,name).connect("clicked",getattr(self,"%s_click"%n))
281
282 widgets = ["autotoggle","automenu","methodsel","maintabs","lowertabs","consolescroll","statusbar","browsermenu","reloadwarn"]
283 for n in widgets:
284 setattr(self,n,self.builder.get_object(n))
285
286 self.autotoggle.connect("toggled",self.auto_toggle)
287
288 self.show_solving_popup=self.builder.get_object("show_solving_popup")
289 self.show_solving_popup.set_active(self.prefs.getBoolPref("SolverReporter","show_popup",True))
290 self.close_on_converged=self.builder.get_object("close_on_converged")
291 self.close_on_converged.set_active(self.prefs.getBoolPref("SolverReporter","close_on_converged",True))
292 self.close_on_nonconverged=self.builder.get_object("close_on_nonconverged")
293 self.close_on_nonconverged.set_active(self.prefs.getBoolPref("SolverReporter","close_on_nonconverged",True))
294 self.solver_engine=self.builder.get_object("solver_engine")
295 self.recent_files=self.builder.get_object("recentfiles")
296
297 self.use_relation_sharing=self.builder.get_object("use_relation_sharing")
298 self.use_relation_sharing.set_active(self.prefs.getBoolPref("Compiler","use_relation_sharing",True))
299
300 self.use_binary_compilation=self.builder.get_object("use_binary_compilation")
301 self.use_binary_compilation.set_active(self.prefs.getBoolPref("Compiler","use_binary_compilation",False))
302 self.use_binary_compilation.set_sensitive(self.use_relation_sharing.get_active())
303
304 self.check_weekly=self.builder.get_object("check_weekly")
305 self.check_weekly.set_active(not(self.prefs.getBoolPref("Browser","disable_auto_check_for_updates",False)))
306
307 self.builder.connect_signals(self)
308
309 #-------
310 # Status icons
311
312 self.fixedimg = Gtk.Image()
313 _fixedimgpath = os.path.join(self.options.assets_dir,'locked.png')
314
315 # this stuff catches some strange environment-variable related problems on Mac OSX.
316 try:
317 if not os.path.exists(_fixedimgpath):
318 raise RuntimeError("Image file '%s' could not be found" % _fixedimgpath)
319 _fixedpixbuf = GdkPixbuf.Pixbuf.new_from_file(_fixedimgpath)
320 self.fixedimg.set_from_pixbuf(_fixedpixbuf)
321 except Exception as e:
322 raise RuntimeError("Failed to load pixbuf '%s' (%s)" % (_fixedimgpath, str(e)))
323
324 self.inactiveimg = Gtk.Image()
325 self.inactiveimg.set_from_file(os.path.join(self.options.assets_dir,'unattached.png'))
326
327 self.iconstatusunknown = None
328 self.iconfixed = self.fixedimg.get_pixbuf()
329 self.iconsolved = self.window.render_icon(Gtk.STOCK_YES,Gtk.IconSize.MENU)
330 self.iconactive = self.window.render_icon(Gtk.STOCK_NO,Gtk.IconSize.MENU)
331 self.iconinactive = self.inactiveimg.get_pixbuf()
332 self.iconunsolved = None
333
334 self.statusicons={
335 ascpy.ASCXX_INST_STATUS_UNKNOWN: self.iconstatusunknown
336 ,ascpy.ASCXX_VAR_FIXED: self.iconfixed
337 ,ascpy.ASCXX_VAR_SOLVED: self.iconsolved
338 ,ascpy.ASCXX_VAR_ACTIVE: self.iconactive
339 ,ascpy.ASCXX_VAR_UNSOLVED: self.iconunsolved
340 ,ascpy.ASCXX_REL_INACTIVE: self.iconinactive
341 }
342
343
344 self.statusmessages={
345 ascpy.ASCXX_INST_STATUS_UNKNOWN: "Status unknown"
346 ,ascpy.ASCXX_VAR_FIXED: "Fixed"
347 ,ascpy.ASCXX_VAR_SOLVED: "Converged"
348 ,ascpy.ASCXX_VAR_ACTIVE: "Active (unconverged)"
349 ,ascpy.ASCXX_VAR_UNSOLVED: "Not yet visited"
350 ,ascpy.ASCXX_REL_INACTIVE: "Inactive"
351 }
352
353 #-------------------
354 # waitwin
355
356 _gdkw = self.window.get_screen().get_active_window()
357 self.waitwin = _gdkw
358
359 if self.waitwin:
360 _cursor = Gdk.Cursor.new(Gdk.CursorType.WATCH)
361 self.waitwin.set_cursor(_cursor)
362
363 #-------------------
364 # pixbufs to be used in the error listing
365
366 self.iconok = self.window.render_icon(Gtk.STOCK_YES,Gtk.IconSize.MENU)
367 self.iconinfo = self.window.render_icon(Gtk.STOCK_DIALOG_INFO,Gtk.IconSize.MENU)
368 self.iconwarning = self.window.render_icon(Gtk.STOCK_DIALOG_WARNING,Gtk.IconSize.MENU)
369 self.iconerror = self.window.render_icon(Gtk.STOCK_DIALOG_ERROR,Gtk.IconSize.MENU)
370
371 #--------------------
372 # pixbufs for solver_var status
373
374 #--------------------
375 # set up the error view
376
377 self.errorview = self.builder.get_object("errorview")
378 errstorecolstypes = [GdkPixbuf.Pixbuf,str,str,str,int]
379 self.errorstore = Gtk.TreeStore(*errstorecolstypes)
380 errtitles = ["","Location","Message"];
381 self.errorview.set_model(self.errorstore)
382 self.errcols = [ Gtk.TreeViewColumn() for _type in errstorecolstypes]
383
384 i = 0
385 for tvcolumn in self.errcols[:len(errtitles)]:
386 tvcolumn.set_title(errtitles[i])
387 self.errorview.append_column(tvcolumn)
388
389 if i>0:
390 _renderer = Gtk.CellRendererText()
391 tvcolumn.pack_start(_renderer, True)
392 tvcolumn.add_attribute(_renderer, 'text', i)
393 if(i==2):
394 tvcolumn.add_attribute(_renderer, 'foreground', 3)
395 tvcolumn.add_attribute(_renderer, 'weight', 4)
396 else:
397 _renderer1 = Gtk.CellRendererPixbuf()
398 tvcolumn.pack_start(_renderer1, False)
399 tvcolumn.add_attribute(_renderer1, 'pixbuf', int(0))
400
401 i = i + 1
402
403
404 #--------------------
405 # set up the error reporter callback
406 self.reporter = ascpy.getReporter()
407 self.reporter.setPythonErrorCallback(self.error_callback)
408
409
410 #--------
411 # report absence of solvers if nec.
412
413 if not len(ascpy.getSolvers()):
414 print("NO SOLVERS LOADED!")
415 self.reporter.reportError( "No solvers were loaded! ASCEND is probably not configured correctly." )
416
417 #--test option
418 if self.options.test:
419 print('================================================================================')
420 print('IN TEST')
421 self.test()
422 return
423
424
425 #-------
426 # Solver engine list
427
428 _slvlist = ascpy.getSolvers()
429 self.solver_engine_menu = Gtk.Menu()
430 self.solver_engine_menu.show()
431 self.solver_engine.set_submenu(self.solver_engine_menu)
432 self.solver_engine_menu_dict = {}
433 _fmi = None
434 for _s in _slvlist:
435 _mi = Gtk.RadioMenuItem(label=_s.getName(), group=_fmi)
436 if _fmi is None:
437 _fmi = _mi
438 _mi.show()
439 _mi.connect('toggled',self.on_select_solver_toggled,_s.getName())
440 self.solver_engine_menu.append(_mi)
441 self.solver_engine_menu_dict[_s.getName()]=_mi
442
443 #-------
444 # Recent file list
445
446 self.recent_file_list = Gtk.Menu()
447 self.recent_file_list.show()
448 self.recent_files.set_submenu(self.recent_file_list)
449
450 _max_num = int(self.prefs.getStringPref("recentfiles","max","-1"))
451 if _max_num == -1:
452 self.prefs.setStringPref("recentfiles","max","10")
453
454 _cur_num = int(self.prefs.getStringPref("recentfiles","cur","-1"))
455 if _cur_num >= 0:
456 for _i in range(_cur_num):
457 _fname = self.prefs.getStringPref("recentfiles","file%s"%(_cur_num -_i - 1),"no recent files")
458 _mi = Gtk.MenuItem(_fname)#Edit
459 _mi.show()
460 _mi.connect("activate",self.on_recent_file_select)
461 self.recent_file_list.append(_mi)
462 else:
463 self.recent_file_list.set_state(Gtk.StateType.INSENSITIVE)
464
465 _pref_solver = self.prefs.getStringPref("Solver","engine","QRSlv")
466 _mi = self.solver_engine_menu_dict.get(_pref_solver)
467 if _mi:
468 _mi.set_active(True)
469 self.set_solver(_pref_solver)
470
471 #--------
472 # Assign an icon to the main window
473
474 self.icon = None
475 if config.ICON_EXTENSION:
476 _iconpath = ""
477 try:
478 _icon = Gtk.Image()
479 _iconpath = os.path.join(self.assets_dir,'ascend'+config.ICON_EXTENSION)
480 _icon.set_from_file(_iconpath)
481 _iconpbuf = _icon.get_pixbuf()
482 self.window.set_icon(_iconpbuf)
483 self.icon = _iconpbuf
484 except Exception as e:
485 print(("FAILED TO SET APPLICATION ICON PATH '%s': %s" % (_iconpath,str(e))))
486 self.reporter.reportError("FAILED to set application icon '%s': %s"
487 % (_iconpath,str(e))
488 )
489
490 #-------------------
491 # set up the module view
492
493 self.modtank = {}
494 self.moduleview = ModuleView(self,self.builder,self.library)
495
496 #--------------------
497 # set up the methods combobox
498
499 self.methodstore = Gtk.ListStore(str)
500 self.methodsel.set_model(self.methodstore)
501 _methodrenderer = Gtk.CellRendererText()
502 self.methodsel.pack_start(_methodrenderer, True)
503 #self.methodsel.add_attribute(_methodrenderer, 'text',0)
504
505 #--------
506 # set up the instance browser view
507 self.modelview = ModelView(self,self.builder)
508
509 #--------
510 # set up the tabs
511 self.tabs = {}
512 self.activetab = None # most recent observer tab
513
514 #--------
515 # set the state of the 'auto' toggle
516
517 self.is_auto = self.prefs.getBoolPref("Browser","auto_solve",True)
518 self.autotoggle.set_active(self.is_auto)
519 self.automenu.set_active(self.is_auto)
520
521 #--------
522 # set the state of the 'warn on reload' toggle
523
524 self.reload_warn = self.prefs.getBoolPref("Browser","warn_on_reload",True)
525 self.reloadwarn.set_active(self.reload_warn)
526
527 #--------
528 # tell libascend about this 'browser' object
529
530 #print dir(ascpy.Registry())
531 ascpy.Registry().set("browser",self)
532
533 #--------
534 # Set up SolverHooks
535
536 print("PYTHON: SETTING UP SOLVER HOOKS")
537 self.solverhooks = SolverHooksPythonBrowser(self)
538 ascpy.SolverHooksManager_Instance().setHooks(self.solverhooks)
539
540 self.solve_interrupt = False
541 #--------
542 # options
543 if(len(args)==1):
544 try:
545 self.do_open(args[0])
546 except RuntimeError as e:
547 self.reporter.reportError(str(e))
548 return
549
550 #print "Options: ",self.options
551
552 _model = None
553 if self.options.model:
554 _model = self.options.model
555 print(("MODEL: '%s'" % _model))
556 elif self.options.auto_sim:
557 _head, _tail = os.path.split(args[0])
558 if(_tail):
559 _model, _ext = os.path.splitext(_tail)
560
561 if _model:
562 try:
563 _t=self.library.findType(_model)
564 if not _t.isModel():
565 if self.options.auto_sim:
566 self.reporter.reportError("Won't auto-instantiate with type '%s': not a MODEL." % _model)
567 elif _t.hasParameters():
568 if self.options.auto_sim:
569 self.reporter.reportError("Won't auto-instantiate MODEL %s: model requires parameters." % _model)
570 else:
571 try:
572 self.do_sim(_t)
573 if not self.options.model:
574 self.reporter.reportNote("Instantiated self-titled model '%s'" %_model)
575 except RuntimeError as e:
576 self.reporter.reportError("Failed to create instance of '%s': %s"
577 %(_model, str(e))
578 );
579 except RuntimeError as e:
580 if self.options.model:
581 self.reporter.reportError("Unknown model type '%s': %s"
582 %(_model, str(e))
583 );
584
585
586 #--------
587 # IPython console, if available
588
589 import console
590 console.create_widget(self)
591
592 import locale
593 if locale.localeconv()['decimal_point'] != '.':
594 self.reporter.reportError(
595 """Incompatible locale settings detected. Please set your system local to one which
596 uses '.' as the decimal point separator, such as en_US or en_AU. Note that failing
597 to make this change will cause input and output values to be truncated.
598 For details, see http://ascendbugs.cheme.cmu.edu/view.php?id=337"""
599 )
600
601 def run(self):
602 if not self.options.test:
603 #self.window.show()
604 loading.print_status("ASCEND is now running")
605 loading.complete()
606 if self.prefs.getStringPref('Browser','first_run') == None:
607 self.prefs.setStringPref('Browser','first_run',time.perf_counter())
608 else:
609 time_now = time.perf_counter()
610 first_run_time = float(self.prefs.getStringPref('Browser','first_run'))
611 if ((time_now-first_run_time)/(3600*24)) >= 7:
612 self.auto_update_check()
613
614 GObject.threads_init()
615 Gtk.main()
616
617 def test(self):
618 print((sys.argv[1]))
619 print((sys.argv[3]))
620 if len(sys.argv)==4:
621 ascpy.test_model(str(sys.argv[1]),str(sys.argv[3]))
622 #Call the function at the SWIG API level that runs all the tests and pass to it, the *args
623 #ascpy is accessible here
624
625
626 # ------------------
627 # SOLVER LIST
628
629 def set_solver(self,solvername):
630 """ this sets the active solver in the GUI, which is the default applied to newly instantiated models """
631 self.solver = ascpy.Solver(solvername)
632 self.prefs.setStringPref("Solver","engine",solvername)
633 self.reporter.reportNote("Set solver engine to '%s'" % solvername)
634
635 # --------------------------------------------
636 # MAJOR GUI COMMANDS
637
638 def on_fix_variable_activate(self,*args):
639 if not self.sim:
640 self.reporter.reportError("No model selected yet")
641 return
642 self.modelview.on_fix_variable_activate(*args)
643
644 def on_free_variable_activate(self,*args):
645 if not self.sim:
646 self.reporter.reportError("No model selected yet")
647 return
648 self.modelview.on_free_variable_activate(*args)
649
650 def on_select_solver_toggled(self,widget,solvername):
651 if widget.get_active():
652 self.set_solver(solvername)
653
654 def on_recent_file_select(self,widget):
655 if widget:
656 # _msg = Gtk.MessageDialog(buttons=Gtk.ButtonsType.OK,message_format=filename,flags=Gtk.DialogFlags.MODAL)
657 # _msg.run()
658 self.do_open(widget.get_label())
659
660 def update_recent_files(self,filename):
661 if filename:
662 _max_num = int(self.prefs.getStringPref("recentfiles","max","10"))
663 _cur_num = int(self.prefs.getStringPref("recentfiles","cur","0"))
664 _should_change = False
665 _temp = None
666 if _cur_num < _max_num:
667 for _i in range(_cur_num):
668 _temp = self.prefs.getStringPref("recentfiles","file%s"%(_i),None)
669 if _temp == filename: #already in the list before
670 _should_change = True
671 if _should_change and _i+1 < _cur_num:
672 _temp = self.prefs.getStringPref("recentfiles","file%s"%(_i+1),None)
673 self.prefs.setStringPref("recentfiles","file%s"%(_i),_temp)
674 if _should_change and _i == _cur_num - 1:
675 self.prefs.setStringPref("recentfiles","file%s"%(_i),filename)
676
677 if _should_change == False:
678 self.prefs.setStringPref("recentfiles","file%s"%(_cur_num),filename)
679 self.prefs.setStringPref("recentfiles","cur",_cur_num+1)
680 else:
681 for _i in range(_max_num):
682 _temp = self.prefs.getStringPref("recentfiles","file%s"%(_i),None)
683 if _temp == filename: #already in the list before
684 _should_change = True
685 if _should_change and _i+1 < _max_num:
686 _temp = self.prefs.getStringPref("recentfiles","file%s"%(_i+1),None)
687 self.prefs.setStringPref("recentfiles","file%s"%(_i),_temp)
688 if _should_change and _i == _max_num - 1:
689 self.prefs.setStringPref("recentfiles","file%s"%(_i),filename)
690
691 if _should_change == False: #this is a new file, then remove the oldest one
692 for _i in range(_max_num):
693 if _i+1 < _max_num:
694 _temp = self.prefs.getStringPref("recentfiles","file%s"%(_i+1),None)
695 self.prefs.setStringPref("recentfiles","file%s"%(_i),_temp)
696 else:
697 self.prefs.setStringPref("recentfiles","file%s"%(_i),filename)
698
699
700 def do_open(self,filename):
701 # TODO does the user want to lose their work?
702 # TODO do we need to chdir?
703
704 _context = self.statusbar.get_context_id("do_open")
705
706 self.errorstore.clear()
707 self.modelview.clear()
708 self.moduleview.clear()
709 self.currentobservertab = None
710 for _obs in self.observers:
711 if _obs.alive == False:
712 _obs.reloaded = True
713 _obs.set_dead()
714 # self.library.clear()
715 #print "Filename =",filename
716 self.statusbar.push(_context,"Loading '"+filename+"'")
717 try:
718 self.filename = filename
719 self.disable_menu()
720 self.enable_on_file_open()
721 # call the low-level 'load' command...
722 self.library.load(filename)
723 self.update_recent_files(filename)
724 except RuntimeError as e:
725 self.statusbar.pop(_context)
726 raise
727
728 try:
729 self.statusbar.pop(_context)
730 except TypeError as e:
731 print(("For some reason, a type error (context=%s,filename=%s): %s" % (_context,filename,e)))
732
733 # Load the current list of modules into self.modules
734 self.moduleview.refresh(self.library)
735
736 self.sim = None;
737 self.maintabs.set_current_page(0);
738
739 # See http://www.daa.com.au/pipermail/pygtk/2005-October/011303.html
740 # for details on how the 'wait cursor' is done.
741 def start_waiting(self, message):
742 self.waitcontext = self.statusbar.get_context_id("waiting")
743 self.statusbar.push(self.waitcontext,message)
744
745 if self.waitwin:
746 self.waitwin.show()
747
748 while Gtk.events_pending():
749 Gtk.main_iteration()
750
751 def stop_waiting(self):
752 if self.waitwin:
753 self.statusbar.pop(self.waitcontext)
754 self.waitwin.hide()
755
756 def do_sim(self, type_object):
757 self.sim = None;
758 # TODO: clear out old simulation first!
759
760 #print "DO_SIM(%s)" % str(type_object.getName())
761 self.start_waiting("Compiling...")
762
763 try:
764 _v = self.prefs.getBoolPref("Compiler","use_relation_sharing",True)
765 ascpy.getCompiler().setUseRelationSharing(_v)
766 print(("Relation sharing set to",_v))
767
768 _v = self.prefs.getBoolPref("Compiler","use_binary_compilation",False)
769 ascpy.getCompiler().setBinaryCompilation(_v)
770 print(("Binary compilation set to",_v))
771
772 self.sim = type_object.getSimulation(str(type_object.getName())+"_sim",False)
773
774 #self.reporter.reportNote("SIMULATION ASSIGNED")
775 except RuntimeError as e:
776 self.stop_waiting()
777 self.reporter.reportError(str(e))
778 return
779
780 self.stop_waiting()
781
782 # get method names and load them into the GUI
783 self.methodstore.clear()
784 _methods = self.sim.getType().getMethods()
785 _activemethod = None;
786 for _m in _methods:
787 _i = self.methodstore.append([_m.getName()])
788 if _m.getName()=="on_load":
789 self.methodsel.set_active_iter(_i)
790
791 self.modelview.setSimulation(self.sim)
792
793 # run the 'on_load' method
794 self.start_waiting("Running default method...")
795 try:
796 #self.reporter.reportNote("SIMULATION CREATED, RUNNING DEFAULT METHOD NOW...")
797 self.sim.runDefaultMethod()
798 except RuntimeError as e:
799 self.stop_waiting()
800 self.reporter.reportError(str(e))
801 return
802 self.stop_waiting()
803
804 self.modelview.refreshtree()
805
806 def do_solve_if_auto(self):
807 if self.is_auto:
808 self.sim.checkInstance()
809 self.do_solve()
810 else:
811 try:
812 self.sim.processVarStatus()
813 except RuntimeError as e:
814 self.reporter.reportError(str(e))
815 self.modelview.refreshtree()
816
817 self.sync_observers()
818
819
820 def no_built_system(self):
821 """ check that the system is 'built', ready for use by the solver. """
822
823 if not self.sim:
824 self.reporter.reportError("No model selected yet")
825 return 1
826
827 try:
828 self.sim.build()
829 self.enable_on_sim_build()
830 except RuntimeError as e:
831 self.reporter.reportError("Couldn't build system: %s" % str(e))
832 return 1
833
834 return 0
835
836 def do_solve_update(self, reporter, status):
837 self.solve_interrupt = reporter.report(status)
838 return False
839
840 def do_solve_finish(self, reporter, status):
841 reporter.finalise(status)
842 self.modelview.refreshtree()
843 return False
844
845 def do_solve_thread(self, reporter):
846 try:
847 self.sim.presolve(self.solver)
848 status = self.sim.getStatus()
849 while status.isReadyToSolve() and not self.solve_interrupt:
850 res = self.sim.iterate()
851 status.getSimulationStatus(self.sim)
852 GObject.idle_add(self.do_solve_update, reporter, status)
853 # 'make' some time for gui update
854 time.sleep(0.001)
855 if res != 0:
856 break
857 GObject.idle_add(self.do_solve_finish, reporter, status)
858 self.sim.postsolve(status)
859 except RuntimeError as err:
860 self.reporter.reportError(str(err))
861
862 def do_solve(self):
863 if self.no_built_system():
864 return
865
866 if not hasattr(self,'solver'):
867 self.reporter.reportError("No solver assigned!")
868 return
869
870 if self.prefs.getBoolPref("SolverReporter","show_popup",True):
871 reporter = PopupSolverReporter(self,self.sim)
872 else:
873 reporter = SimpleSolverReporter(self)
874
875 self.solve_interrupt = False
876 thread = threading.Thread(target=self.do_solve_thread, args=(reporter,))
877 thread.daemon = True
878 thread.start()
879
880 def do_integrate(self):
881 if self.no_built_system():
882 return
883
884 try:
885 self.sim.build()
886 except RuntimeError as e:
887 self.reporter.reportError("Couldn't build system: %s",str(e))
888 return
889 integrator = ascpy.Integrator(self.sim)
890 try:
891 integrator.findIndependentVar()
892 except RuntimeError as e:
893 self.reporter.reportNote(str(e))
894
895 integwin = IntegratorWindow(self,self.sim)
896 _integratorreporter = integwin.run()
897 if _integratorreporter!=None:
898 _integratorreporter.run()
899
900 def do_check(self):
901 if self.no_built_system():
902 return
903
904 self.start_waiting("Checking system...")
905
906 try:
907 self.sim.checkInstance()
908 self.reporter.reportWarning("System instance check run, check above for error (if any).")
909 # the above gives output but doesn't throw errors or return a status.
910 # ... this is a problem (at the C level)
911
912 status = self.sim.checkDoF()
913 if status==ascpy.ASCXX_DOF_UNDERSPECIFIED:
914 self.on_show_fixable_variables_activate(None)
915 elif status==ascpy.ASCXX_DOF_OVERSPECIFIED:
916 self.on_show_freeable_variables_activate(None)
917 elif status==ascpy.ASCXX_DOF_STRUCT_SINGULAR:
918 if not self.sim.checkStructuralSingularity():
919 sing = self.sim.getSingularityInfo()
920 title = "Structural singularity"
921 text = title
922 msgs = {
923 "The singularity can be reduced by freeing the following variables" : sing.freeablevars
924 ,"Relations involved in the structural singularity" : sing.rels
925 ,"Variables involved in the structural singularity" : sing.vars
926 }
927 for k,v in list(msgs.items()):
928 text+="\n\n%s:" % k
929 if len(v):
930 _l = [j.getName() for j in v]
931 _l.sort()
932 text+= "\n\t" + "\n\t".join(_l)
933 else:
934 text += "\nnone"
935
936 _dialog = InfoDialog(self,self.window,text,title)
937 _dialog.run()
938 else:
939 self.reporter.reportNote("System DoF check OK")
940
941 except RuntimeError as e:
942 self.stop_waiting()
943 self.reporter.reportError(str(e))
944 return
945
946 self.stop_waiting()
947 self.modelview.refreshtree()
948
949 def do_method(self,method):
950
951 try:
952 self.sim.run(method)
953 except RuntimeError as e:
954 self.reporter.reportError(str(e))
955
956 self.sim.processVarStatus()
957 self.modelview.refreshtree()
958
959 def do_quit(self):
960 loading.print_status("Saving window location")
961 self.reporter.clearPythonErrorCallback()
962
963 _w,_h = self.window.get_size()
964 _t,_l = self.window.get_position()
965 _display = self.window.get_screen().get_display().get_name()
966 self.prefs.setGeometrySizePosition(_display,"browserwin",_w,_h,_t,_l );
967
968 _p = self.browserpaned.get_position()
969 self.prefs.setGeometryValue(_display,"browserpaned",_p);
970
971 loading.print_status("Saving current directory")
972 self.prefs.setStringPref("Directories","fileopenpath",self.fileopenpath)
973
974 self.prefs.setBoolPref("Browser","auto_solve",self.is_auto)
975
976 loading.print_status("Saving preferences")
977 # causes prefs to be saved unless they are still being used elsewher
978 del(self.prefs)
979
980 loading.print_status("Clearing error callback")
981 self.reporter.clearPythonErrorCallback()
982
983 loading.print_status("Closing down GTK")
984 Gtk.main_quit()
985
986 loading.print_status("Clearing library")
987 self.library.clear()
988
989 loading.print_status("Quitting")
990
991 return False
992
993 def on_tools_sparsity_click(self,*args):
994
995 self.reporter.reportNote("Preparing incidence matrix...")
996 try:
997 _im = self.sim.getIncidenceMatrix()
998 self.reporter.reportNote("Plotting incidence matrix...")
999 _sp = IncidenceMatrixWindow(_im)
1000 _sp.run()
1001 except RuntimeError as e:
1002 self.reporter.reportError(str(e))
1003
1004 def on_units_click(self,*args):
1005 T = self.modelview.get_selected_type()
1006 _un = UnitsDialog(self,T)
1007 _un.run()
1008
1009 def on_tools_incidencegraph_click(self,*args):
1010 self.reporter.reportNote("Preparing incidence graph...")
1011 import tempfile
1012 f,fname = tempfile.mkstemp(suffix=".png")
1013 f = file(fname,'wb')
1014 self.reporter.reportNote("temp file name = %s" % fname)
1015 self.reporter.reportNote("file = %s" % f)
1016 self.start_waiting("Creating incidence graph...")
1017 try:
1018 self.sim.write(fname,'dot') # create a PNG file in f
1019 except Exception as e:
1020 self.stop_waiting()
1021 self.reporter.reportError("Failed to create incidence graph: %s" % str(e))
1022 return
1023 f.close()
1024 self.stop_waiting()
1025 _ig = ImageWindow(self, self.window, fname, title="Incidence Graph", delete=True)
1026 _ig.run()
1027
1028 def on_tools_repaint_tree_activate(self,*args):
1029 self.reporter.reportNote("Repainting model view...")
1030 self.modelview.refreshtree()
1031
1032 def on_diagnose_blocks_activate(self,*args):
1033 try:
1034 _bl = self.sim.getActiveBlock()
1035 _db = DiagnoseWindow(self,_bl)
1036 _db.run();
1037 except RuntimeError as e:
1038 self.reporter.reportError(str(e))
1039 return
1040
1041 def on_add_observer_click(self,*args):
1042 self.create_observer()
1043
1044 def on_keep_observed_click(self,*args):
1045 print("KEEPING...")
1046 if self.currentobservertab is None:
1047 self.reporter.reportError("No observers defined for this model!")
1048 return
1049 self.tabs[self.currentobservertab].do_add_row()
1050
1051 def on_copy_observer_matrix_click(self,*args):
1052 if self.clip == None:
1053 self.clip = Gtk.Clipboard()
1054
1055 if len(self.observers) <= 0:
1056 self.reporter.reportError("No observer defined!")
1057 return
1058 self.tabs[self.currentpage].copy_to_clipboard(self.clip)
1059
1060 def on_use_relation_sharing_toggle(self,checkmenuitem,*args):
1061 _v = checkmenuitem.get_active()
1062 self.prefs.setBoolPref("Compiler","use_relation_sharing",_v)
1063 self.reporter.reportNote("Relation sharing set to "+str(_v))
1064 self.use_binary_compilation.set_sensitive(_v);
1065
1066 def on_use_binary_compilation_toggle(self,checkmenuitem,*args):
1067 _v = checkmenuitem.get_active()
1068 self.prefs.setBoolPref("Compiler","use_binary_compilation",_v)
1069 self.reporter.reportNote("Binary compilation set to "+str(_v))
1070
1071 def on_show_solving_popup_toggle(self,checkmenuitem,*args):
1072 _v = checkmenuitem.get_active()
1073 self.prefs.setBoolPref("SolverReporter","show_popup",_v)
1074
1075 def on_close_on_converged_toggle(self,checkmenuitem,*args):
1076 _v = checkmenuitem.get_active()
1077 self.prefs.setBoolPref("SolverReporter","close_on_converged",_v)
1078
1079 def on_close_on_nonconverged_toggle(self,checkmenuitem,*args):
1080 _v = checkmenuitem.get_active()
1081 self.prefs.setBoolPref("SolverReporter","close_on_nonconverged",_v)
1082
1083 def on_show_variables_near_bounds_activate(self,*args):
1084 _epsilon = 1e-4;
1085 try:
1086 _vars = self.sim.getVariablesNearBounds(_epsilon)
1087 except RuntimeError as e:
1088 self.reporter.reportError("Unable to show variables near bounds:\n%s"%str(e))
1089 return
1090 text = "Variables Near Bounds"
1091 title=text;
1092 text += "\n"
1093 if len(_vars):
1094 for _v in _vars:
1095 text += "\n%s"%_v.getName()
1096 else:
1097 text +="\nnone"
1098 _dialog = InfoDialog(self,self.window,text,title)
1099 _dialog.run()
1100
1101 def on_show_vars_far_from_nominals_activate(self,*args):
1102 _bignum = self.prefs.getRealPref("Browser","far_from_nominals",10);
1103 try:
1104 _vars = self.sim.getVariablesFarFromNominals(_bignum)
1105 except RuntimeError as e:
1106 self.reporter.reportError("Unable to show variables far from nominals:\n%s"%str(e))
1107 return
1108 text = "Variables Far from Nominals"
1109 title=text;
1110 text += "\n"
1111 if len(_vars):
1112 for _v in _vars:
1113 text += "\n%s"%_v.getName()
1114 else:
1115 text +="\nnone"
1116
1117 text+="\n\nAbove calculated using a relative error of %f" % float(_bignum)
1118 text+="\nModify this value in .ascend.ini, section '[Browser]', key 'far_from_nominals'."
1119 _dialog = InfoDialog(self,self.window,text,title)
1120 _dialog.run()
1121
1122 def on_show_config_activate(self,*args):
1123 text = "Configuration"
1124 title=text;
1125 text += "\n\nEnvironment variables:\n"
1126 if len(os.environ):
1127 for _k,_v in sorted(os.environ.items()):
1128 text += " %s=%s\n" % (_k,_v)
1129 else:
1130 text +="\nempty"
1131
1132 _dialog = InfoDialog(self,self.window,text,title)
1133 _dialog.run()
1134
1135
1136 # ----------------------------------
1137 # ERROR PANEL
1138
1139 def get_error_row_data(self,sev,filename,line,msg):
1140 try:
1141 _sevicon = {
1142 0 : self.iconok
1143 ,1 : self.iconinfo
1144 ,2 : self.iconwarning
1145 ,4 : self.iconerror
1146 ,8 : self.iconinfo
1147 ,16 : self.iconwarning
1148 ,32 : self.iconerror
1149 ,64 : self.iconerror
1150 }[sev]
1151 except KeyError:
1152 _sevicon = self.iconerror
1153
1154 _fontweight = Pango.Weight.NORMAL
1155 if sev==32 or sev==64:
1156 _fontweight = Pango.Weight.BOLD
1157
1158 _fgcolor = "black"
1159 if sev==8:
1160 _fgcolor = "#888800"
1161 elif sev==16:
1162 _fgcolor = "#884400"
1163 elif sev==32 or sev==64:
1164 _fgcolor = "#880000"
1165 elif sev==0:
1166 _fgcolor = BROWSER_FIXED_COLOR
1167
1168 if not filename and not line:
1169 _fileline = ""
1170 else:
1171 if(len(filename) > 25):
1172 filename = "..."+filename[-22:]
1173 _fileline = filename + ":" + str(line)
1174
1175 _res = (_sevicon,_fileline,msg.rstrip(),_fgcolor,_fontweight)
1176 #print _res
1177 return _res
1178
1179 def error_callback(self,sev,filename,line,msg):
1180 #print "SEV =",sev
1181 #print "FILENAME =",filename
1182 #print "LINE =",line
1183 #print "MSG =",msg
1184 pos = self.errorstore.append(None, self.get_error_row_data(sev, filename,line,msg))
1185 path = self.errorstore.get_path(pos)
1186 col = self.errorview.get_column(3)
1187 self.errorview.scroll_to_cell(path,col)
1188 return 0;
1189
1190 # --------------------------------
1191 # BUTTON METHODS
1192
1193 def open_click(self,*args):
1194 #loading.print_status("CURRENT FILEOPENPATH is",self.fileopenpath)
1195 dialog = Gtk.FileChooserDialog("Open ASCEND model...",
1196 self.window,
1197 Gtk.FileChooserAction.OPEN,
1198 (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
1199 )
1200 dialog.set_current_folder(self.fileopenpath)
1201 dialog.set_default_response(Gtk.ResponseType.OK)
1202 dialog.set_transient_for(self.window)
1203 dialog.set_modal(True)
1204
1205 filter = Gtk.FileFilter()
1206 filter.set_name("*.a4c, *.a4l")
1207 filter.add_pattern("*.[Aa]4[Cc]")
1208 filter.add_pattern("*.[Aa]4[Ll]")
1209 dialog.add_filter(filter)
1210
1211 filter = Gtk.FileFilter()
1212 filter.set_name("All files")
1213 filter.add_pattern("*")
1214 dialog.add_filter(filter)
1215
1216 response = dialog.run()
1217 _filename = dialog.get_filename()
1218 print(("\nFILENAME SELECTED:",_filename))
1219
1220 _path = dialog.get_current_folder()
1221 if _path:
1222 self.fileopenpath = _path
1223
1224 dialog.hide()
1225
1226 if response == Gtk.ResponseType.OK:
1227 self.reporter.reportNote("File %s selected." % dialog.get_filename() )
1228 self.library.clear()
1229 try:
1230 self.do_open( _filename)
1231 except RuntimeError as e:
1232 self.reporter.reportError(str(e))
1233
1234 def on_reloadwarn_toggled(self,*args):
1235 self.prefs.setBoolPref("Browser","warn_on_reload",self.reloadwarn.get_active())
1236
1237 def reload_click(self,*args):
1238 _type = None
1239
1240 if not self.filename:
1241 self.reporter.reportError("No file loaded yet!")
1242 return
1243
1244 if self.sim:
1245 _type = self.sim.getType().getName().toString();
1246
1247 if self.reloadwarn.get_active() and self.currentobservertab is not None:
1248 _alertwin = ReloadDialog(self)
1249 _reload = _alertwin.run()
1250 if _reload is False:
1251 return
1252 self.library.clear()
1253
1254 try:
1255 self.do_open(self.filename)
1256 if _type:
1257 _t = self.library.findType(_type)
1258 self.do_sim(_t)
1259 except RuntimeError as e:
1260 self.reporter.reportError(str(e))
1261
1262 def props_activate(self,widget,*args):
1263 return self.modelview.props_activate(self,widget,*args)
1264
1265 def observe_activate(self,widget,*args):
1266 return self.modelview.observe_activate(self,widget,*args)
1267
1268 def solve_click(self,*args):
1269 #self.reporter.reportError("Solving simulation '" + self.sim.getName().toString() +"'...")
1270 self.do_solve()
1271
1272 def console_click(self,*args):
1273 self.lowertabs.set_current_page(1)
1274 self.consoletext.grab_focus()
1275
1276 def integrate_click(self,*args):
1277 self.do_integrate()
1278
1279 def check_click(self,*args):
1280 self.do_check()
1281 #self.reporter.reportError("CHECK clicked")
1282
1283 def preferences_click(self,*args):
1284 if not self.sim:
1285 self.reporter.reportError("No simulation created yet!");
1286 self.sim.setSolver(self.solver)
1287 _params = self.sim.getParameters()
1288 _paramswin = SolverParametersWindow(
1289 browser=self
1290 ,params=_params
1291 ,name=self.solver.getName()
1292 )
1293 if _paramswin.run() == Gtk.ResponseType.OK:
1294 print("PARAMS UPDATED")
1295 self.sim.setParameters(_paramswin.params)
1296 else:
1297 print("PARAMS NOT UPDATED")
1298
1299 def methodrun_click(self,*args):
1300 _sel = self.methodsel.get_active_text()
1301 if _sel:
1302 _method = None
1303 _methods = self.sim.getType().getMethods()
1304 for _m in _methods:
1305 if _m.getName()==_sel:
1306 _method = _m
1307 if not _method:
1308 self.reporter.reportError("Method is not valid")
1309 return
1310 self.do_method(_method)
1311 else:
1312 self.reporter.reportError("No method selected")
1313
1314 def auto_toggle(self,button,*args):
1315 self.is_auto = button.get_active()
1316 if hasattr(self,'automenu'):
1317 self.automenu.set_active(self.is_auto)
1318 else:
1319 raise RuntimeError("no automenu")
1320
1321 #if self.is_auto:
1322 # self.reporter.reportSuccess("Auto mode is now ON")
1323 #else:
1324 # self.reporter.reportSuccess("Auto mode is now OFF")
1325
1326 def on_file_quit_click(self,*args):
1327 #self.exit_popup()
1328 self.do_quit()
1329
1330 def on_tools_auto_toggle(self,checkmenuitem,*args):
1331 self.is_auto = checkmenuitem.get_active()
1332 self.autotoggle.set_active(self.is_auto)
1333
1334 def on_help_about_click(self,*args):
1335
1336 self.builder.add_objects_from_file(self.glade_file,["aboutdialog"])
1337 _about = self.builder.get_object("aboutdialog")
1338 _about.set_transient_for(self.window)
1339 _about.set_version(config.VERSION)
1340 _about.run()
1341 _about.destroy()
1342
1343 def on_help_contents_click(self,*args):
1344 _help = Help(HELP_ROOT)
1345 _help.run()
1346
1347 def on_report_a_bug_click(self,*args):
1348 import urllib.request, urllib.parse, urllib.error
1349 import platform
1350 _plat = str(platform.system())
1351 _version = config.VERSION
1352 _help = Help(
1353 url="http://bugs.ascend4.org/bug_report_page.php?project_id=ascend&platform=%s&product_version=%s"
1354 % (_plat,_version)
1355 )
1356 _help.run()
1357
1358 def on_help_check_for_updates_click(self,*args):
1359 v = VersionCheck()
1360 title = "Check for updates"
1361 text = "Your version is %s\n" % config.VERSION
1362 self.prefs.setStringPref("Browser","last_update_check","%s" %time.perf_counter())
1363
1364 try:
1365 v.check()
1366 if config.VERSION==v.latest:
1367 text += "You are running the latest released version"
1368 else:
1369 text += "Latest version is %s\n" % v.latest
1370 if v.info:
1371 text += "Get more info at %s\n" % v.info
1372 if v.download:
1373 text += "Download from %s\n" % v.download
1374 except Exception as e:
1375 text += "\nUnable to check version\n"
1376 text += str(e)
1377
1378 _dialog = InfoDialog(self,self.window,text,title)
1379 _dialog.run()
1380
1381 def on_show_fixable_variables_activate(self,*args):
1382 try:
1383 v = self.sim.getFixableVariables()
1384 except Exception as e:
1385 self.reporter.reportError("Unable to show fixable variables: %s"%str(e))
1386 return
1387 text = "Fixable Variables"
1388 title = text
1389 text += "\n"
1390 if len(v):
1391 for var in v:
1392 text += "\n%s"%var
1393 else:
1394 text += "\nnone"
1395 _dialog = InfoDialog(self,self.window,text,title)
1396 _dialog.run()
1397
1398 def on_show_fixed_vars_activate(self,*args):
1399 try:
1400 v = self.sim.getFixedVariables()
1401 except RuntimeError as e:
1402 self.reporter.reportError("Unable to show fixed variables: %s"%str(e))
1403 return
1404 text = "%d fixed variables:" % len(v)
1405 title = "Fixed Variables"
1406 text += "\n"
1407 if len(v):
1408 for var in v:
1409 text += "\n%s\t= %f"%(str(var),var.getValue())
1410 else:
1411 text += "\nnone"
1412 _dialog = InfoDialog(self,self.window,text,title,tabs=[100,200])
1413 _dialog.run()
1414
1415 def on_show_freeable_variables_activate(self,*args):
1416 try:
1417 v = self.sim.getFreeableVariables()
1418 except RuntimeError as e:
1419 self.reporter.reportError("Unable to show freeable variables: %s"%str(e))
1420 return
1421 text = "Freeable Variables"
1422 title = text
1423 text += "\n"
1424 if len(v):
1425 for var in v:
1426 text += "\n%s" % var
1427 else:
1428 text += "\nnone"
1429 _dialog = InfoDialog(self,self.window,text,title)
1430 _dialog.run()
1431
1432 def on_show_external_functions_activate(self,*args):
1433 v = self.library.getExtMethods()
1434 text = "External Functions"
1435 title = text
1436 text +="\nHere is the list of external functions currently present in"
1437 text +=" the Library:"
1438
1439 if len(v):
1440 for ext in v:
1441 text += "\n\n%s (%d inputs, %d outputs):" % \
1442 (ext.getName(), ext.getNumInputs(), ext.getNumOutputs())
1443 text += "\n%s" % ext.getHelp()
1444 else:
1445 text +="\n\nNone"
1446 _dialog = InfoDialog(self,self.window,text,title)
1447 _dialog.run()
1448
1449 def on_notes_view_activate(self,*args):
1450 t = None
1451 try:
1452 D = self.library.getAnnotationDatabase()
1453 i = self.modelview.get_selected_instance()
1454 if i and i.isModel():
1455 t = i.getType()
1456 else:
1457 self.reporter.reportError("First select a MODEL instance");
1458 return
1459 v = D.getNotes(t)
1460 except RuntimeError as e:
1461 self.reporter.reportError("Unable to show notes: %s"%str(e))
1462 return
1463 text = "Notes for '%s'" % t.getName()
1464 title = text
1465 text += "\nHere are all notes defined within this MODEL:"
1466 nn = {}
1467 if len(v):
1468 for n in v:
1469 text += "\n\n%s (%s):" % (n.getId(), n.getLanguage())
1470 text += "\n\t%s" % n.getText()
1471 else:
1472 text += "\n\nThere are no noted defined locally within in this model"
1473
1474 _dialog = InfoDialog(self,self.window,text,title)
1475 _dialog.run()
1476
1477 def on_maintabs_switch_page(self,notebook,page,pagenum):
1478 #print("Page switched to %d" % pagenum)
1479 if (pagenum in list(self.tabs.keys())) and self.tabs[pagenum].alive:
1480 self.currentobservertab = pagenum
1481 self.currentpage = pagenum
1482 else:
1483 self.currentpage = pagenum
1484 if pagenum == 1:
1485 self.enable_on_enter_sim_tab()
1486 self.modelview.modelview.grab_focus()
1487 else:
1488 self.disable_on_leave_sim_tab()
1489
1490 def create_observer(self,name=None):
1491 _imagelist = []
1492 for i in range(5):
1493 _imagelist.append("image%s" % (i+7))
1494 self.builder.add_objects_from_file(self.glade_file, _imagelist)
1495
1496 self.builder.add_objects_from_file(self.glade_file,["observervbox","observercontext"])
1497
1498 _label = Gtk.Label();
1499 _tab = self.maintabs.append_page(self.builder.get_object("observervbox"),_label);
1500 _obs = ObserverTab(name=name, browser=self, tab=_tab)
1501 _label.set_text(_obs.name)
1502 self.observers.append(_obs)
1503 self.tabs[_tab] = _obs
1504 self.currentobservertab = _tab
1505
1506 self.builder.get_object("copy_observer_matrix").set_sensitive(True)
1507 self.builder.get_object("keep_observed").set_sensitive(True)
1508 return _obs
1509
1510 def sync_observers(self):
1511 for _o in self.observers:
1512 _o.sync()
1513
1514 def delete_event(self, widget, event):
1515 self.do_quit()
1516 return False
1517 #return self.exit_popup()
1518
1519 def exit_popup(self):
1520 dialog = Gtk.MessageDialog(self.window, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO,
1521 Gtk.ButtonsType.YES_NO, "Are you sure you want to Quit?")
1522 dialog.set_title("Exit popup")
1523 #dialog.set_default_size(600,300)
1524 response = dialog.run()
1525 dialog.destroy()
1526 if response == Gtk.ResponseType.YES:
1527 self.do_quit()
1528 return False
1529 else:
1530 return True
1531
1532 def observe(self,instance):
1533 if self.currentobservertab is None:
1534 self.create_observer()
1535 _observer = self.tabs[self.currentobservertab]
1536 _observer.add_instance(instance)
1537
1538 def auto_update_check(self):
1539 _p = self.prefs
1540 _no_auto_check = _p.getBoolPref("Browser", "disable_auto_check_for_updates", False)
1541
1542 if _no_auto_check is True:
1543 return
1544
1545 _time_now = time.perf_counter()
1546 _last_update = float(self.prefs.getStringPref("Browser","last_update_check","0"))
1547 print(("Time since last update check : %f days" %((_time_now-_last_update)/(3600*24))))
1548
1549 if ((_time_now-_last_update)/(3600*24)) < 7:
1550 return
1551
1552 _win = AutoUpdateDialog(self)
1553 _check_now = _win.run()
1554
1555 if _check_now is False:
1556 return
1557
1558 self.on_help_check_for_updates_click()
1559
1560 def on_check_weekly_toggled(self, widget):
1561 _p = self.prefs
1562 _p.setBoolPref("Browser", "disable_auto_check_for_updates", not(widget.get_active()))
1563
1564 def disable_menu(self):
1565 list=["free_variable","fix_variable","sparsity","propsmenuitem","copy_observer_matrix",
1566 "incidencegraph","diagnose_blocks","show_fixed_vars","show_freeable_vars",
1567 "show_fixable_variables","show_variables_near_bounds","show_vars_far_from_nominals1",
1568 "repaint_tree","checkbutton","solvebutton","integratebutton","methodrunbutton",
1569 "check1","solve1","integrate1","units","add_observer","keep_observed","preferences","notes_view"]
1570 for button in list:
1571 self.builder.get_object(button).set_sensitive(False)
1572
1573 def disable_on_leave_sim_tab(self):
1574 list =["free_variable","fix_variable","propsmenuitem","units"]
1575 for button in list:
1576 if self.builder.get_object(button)!=None:
1577 self.builder.get_object(button).set_sensitive(False)
1578
1579 def enable_on_enter_sim_tab(self):
1580 list =["free_variable","fix_variable","propsmenuitem","units"]
1581 for button in list:
1582 self.builder.get_object(button).set_sensitive(False)
1583 if hasattr(self.modelview,'sim'):
1584 _path, _col = self.modelview.modelview.get_cursor()
1585 _instance = None
1586 if _path:
1587 _name,_instance = self.modelview.otank[_path.to_string()]
1588 if _instance is None:
1589 return
1590 if _instance.isReal():
1591 self.builder.get_object("units").set_sensitive(True)
1592 if _instance.getType().isRefinedSolverVar():
1593 self.builder.get_object("propsmenuitem").set_sensitive(True)
1594 if _instance.isFixed():
1595 self.builder.get_object("free_variable").set_sensitive(True)
1596 else:
1597 self.builder.get_object("fix_variable").set_sensitive(True)
1598 elif _instance.isRelation():
1599 self.builder.get_object("propsmenuitem").set_sensitive(True)
1600
1601 def enable_on_sim_build(self):
1602 list=["sparsity","incidencegraph","diagnose_blocks","show_fixed_vars","show_freeable_vars",
1603 "show_fixable_variables","show_variables_near_bounds","show_vars_far_from_nominals1","notes_view"]
1604 for button in list:
1605 if self.builder.get_object(button) != None:
1606 self.builder.get_object(button).set_sensitive(True)
1607 def disable_on_first_run(self):
1608 list=["reloadbutton","reload","show_external_functions","notes_view"]
1609 for button in list:
1610 if self.builder.get_object(button) != None:
1611 self.builder.get_object(button).set_sensitive(True)
1612 def enable_on_file_open(self):
1613 list=["reloadbutton","reload","show_external_functions"]
1614 for button in list:
1615 if self.builder.get_object(button) != None:
1616 self.builder.get_object(button).set_sensitive(True)
1617 def enable_on_model_tree_build(self):
1618 list=["repaint_tree","checkbutton","solvebutton","integratebutton","methodrunbutton",
1619 "check1","solve1","integrate1","units","add_observer","preferences","notes_view"]
1620 for button in list:
1621 if self.builder.get_object(button) != None:
1622 self.builder.get_object(button).set_sensitive(True)
1623 if __name__ == "__main__":
1624 b = Browser();
1625 b.run()
1626
1627 class ReloadDialog:
1628
1629 # Just a dialog to confirm that the user REALLY
1630 # wants to reload the model
1631
1632 def __init__(self, browser):
1633 browser.builder.add_objects_from_file(browser.glade_file, ["reloaddialog"])
1634 self.alertwin = browser.builder.get_object("reloaddialog")
1635 browser.builder.connect_signals(self)
1636
1637 def on_reloaddialog_close(self,*args):
1638 self.alertwin.response(Gtk.ResponseType.CLOSE)
1639
1640 def run(self):
1641 _continue = True
1642 while _continue:
1643 _res = self.alertwin.run()
1644 if _res == Gtk.ResponseType.YES:
1645 self.alertwin.destroy()
1646 return True
1647 else:
1648 self.alertwin.destroy()
1649 return False
1650
1651 class AutoUpdateDialog:
1652
1653 # A dialog to automatically check for updates
1654
1655 def __init__(self, browser):
1656 self.browser = browser
1657 browser.builder.add_objects_from_file(browser.glade_file, ["autoupdatedialog"])
1658 self.win = browser.builder.get_object("autoupdatedialog")
1659 self.checkbutton = browser.builder.get_object("autoupdate")
1660
1661 _p = self.browser.prefs
1662 self.checkbutton.set_active(_p.getBoolPref("Browser", "disable_auto_check_for_updates", False))
1663
1664 browser.builder.connect_signals(self)
1665
1666 def on_autoupdate_toggled(self, widget):
1667 _p = self.browser.prefs
1668 _p.setBoolPref("Browser", "disable_auto_check_for_updates", widget.get_active())
1669 self.browser.check_weekly.set_active(not(widget.get_active()))
1670
1671 def run(self):
1672 _continue = True
1673 while _continue:
1674 _res = self.win.run()
1675 if _res == Gtk.ResponseType.YES:
1676 self.win.destroy()
1677 return True
1678 elif _res == Gtk.ResponseType.NO or _res == Gtk.ResponseType.DELETE_EVENT or _res == Gtk.ResponseType.CLOSE:
1679 self.win.destroy()
1680 return False

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