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