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

Contents of /trunk/pygtk/observer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 852 - (show annotations) (download) (as text)
Tue Sep 19 14:57:42 2006 UTC (17 years, 10 months ago) by johnpye
File MIME type: text/x-python
File size: 13087 byte(s)
More work on observer functionality. Seems to be basically operational now.
1 import pygtk
2 pygtk.require('2.0')
3 import gtk
4 import gtk.glade
5 import pango
6
7 OBSERVER_EDIT_COLOR = "#008800"
8 OBSERVER_NOEDIT_COLOR = "#000088"
9 OBSERVER_NORMAL_COLOR = "black"
10
11 OBSERVER_INITIAL_COLS = 3 # how many cells are at the start of the table?
12 OBSERVER_ICON, OBSERVER_WEIGHT, OBSERVER_EDIT = range(0,OBSERVER_INITIAL_COLS) # column indices for the start of the TreeStore
13 OBSERVER_NULL = 0 # value that gets added to empty cells in a new column
14
15 # This is messy code since it doesn't observe the convention of keeping your model
16 # separate from your view. It's all mixed up together. Yuck. Part of the
17 # difficulty with that was the fact that TreeStores don't support the adding of
18 # columns.
19
20 # Update: there is a technique for doing this, in fact:
21 # http://www.daa.com.au/pipermail/pygtk/2006-February/011777.html
22
23 OBSERVER_NUM=0
24
25 class ObserverColumn:
26 """
27 A class to identify the instance that relates to a specify column
28 and the units of measurement and column title, etc.
29 """
30 def __init__(self,instance,index,name=None,units=None,browser=None):
31 self.instance = instance
32 self.name = name
33 self.index = index
34
35 if name==None:
36 if browser == None:
37 name = "UNNAMED"
38 else:
39 name = browser.sim.getInstanceName(instance)
40
41 if units == None:
42 units = instance.getType().getPreferredUnits()
43 if units == None:
44 units = instance.getType().getDimensions().getDefaultUnits()
45
46 uname = str(units.getName())
47 if uname.find("/")!=-1:
48 uname = "["+uname+"]"
49
50 if uname == "":
51 _title = "%s" % (name)
52 else:
53 _title = "%s / %s" % (name, uname)
54
55 self.title = _title
56 self.units = units
57 self.uname = uname
58 self.name = name
59
60 def __repr__(self):
61 return "ObserverColumn(name="+self.name+")"
62
63 def cellvalue(self, column, cell, model, iter):
64 #print "RENDERING COLUMN",self.index
65 _rowobject = model.get_value(iter,0)
66
67 cell.set_property('editable',False)
68 cell.set_property('weight',400)
69 try:
70 if _rowobject.active:
71 _rawval = self.instance.getRealValue()
72 if self.instance.getType().isRefinedSolverVar():
73 if self.instance.isFixed():
74 cell.set_property('editable',True)
75 cell.set_property('weight',700)
76 cell.set_property('foreground',OBSERVER_EDIT_COLOR)
77 else:
78 cell.set_property('foreground',OBSERVER_NOEDIT_COLOR)
79 else:
80 cell.set_property('foreground',OBSERVER_NORMAL_COLOR)
81 _rawval = _rowobject.values[self.index]
82 _dataval = _rawval / self.units.getConversion()
83 except IndexError:
84 _dataval = "N/A"
85
86 cell.set_property('text', _dataval)
87
88 class ObserverRow:
89 """
90 Just a container for a vector of values, but with columns that
91 should correspond to those in the Observer object's vector of
92 ObserverColumn objects.
93 """
94 def __init__(self,values=None,active=True):
95 if values==None:
96 values={}
97
98 self.values = values
99 self.active = active
100
101 def make_static(self,table):
102 self.active = False
103 print "TABLE COLS:",table.cols
104 print "ROW VALUES:",self.values
105 r=0;
106 for index,col in table.cols.iteritems():
107 print "ROW",r,"; INDEX: ",index,"; COL: ",col
108 try:
109 self.values[index] = col.instance.getRealValue()
110 except KeyError,e:
111 print "Key error: e=",str(e)
112 self.values[index] = None
113 r=r+1
114 print "Made static, values:",self.values
115
116 def get_values(self,table):
117 if not self.active:
118 return self.values.values()
119 else:
120 _v = []
121 for index,col in table.cols.iteritems():
122 _v.append( col.instance.getRealValue() / col.units.getConversion() )
123 return _v
124
125 class ObserverTab:
126
127 def __init__(self,xml,browser,tab,name=None,alive=True):
128 global OBSERVER_NUM
129 self.colindex = 0
130 if name==None:
131 OBSERVER_NUM=OBSERVER_NUM+1
132 name = "Observer %d" % OBSERVER_NUM
133 self.name = name
134 self.browser=browser
135 xml.signal_autoconnect(self)
136 self.view = xml.get_widget('observerview')
137 self.tab = tab
138 self.alive=alive
139 if self.alive:
140 self.browser.reporter.reportNote("New observer is 'alive'")
141
142 self.keptimg = gtk.Image()
143 self.activeimg = gtk.Image()
144 self.activeimg.set_from_file("glade/active.png")
145 # create PixBuf objects from these?
146 self.rows = []
147 _store = gtk.TreeStore(object)
148 self.cols = {}
149
150 # create the 'active' pixbuf column
151 _renderer = gtk.CellRendererPixbuf()
152 _col = gtk.TreeViewColumn()
153 _col.set_title("")
154 _col.pack_start(_renderer,False)
155 _col.set_cell_data_func(_renderer, self.activepixbufvalue)
156 self.view.append_column(_col);
157
158 # initially there will not be any other columns
159
160 if self.alive:
161 # for a 'live' Observer, create the 'active' bottom row
162 self.browser.reporter.reportNote("Adding empty row to store")
163 _row = ObserverRow()
164 self.activeiter = _store.append(None, [_row] )
165 self.rows.append(_row)
166
167 self.view.set_model(_store)
168 self.browser.reporter.reportNote("Created observer '%s'" % self.name)
169
170 def activepixbufvalue(self,column,cell,model,iter):
171 _rowobject = model.get_value(iter,0)
172 if _rowobject.active:
173 cell.set_property('pixbuf',self.activeimg.get_pixbuf())
174 else:
175 cell.set_property('pixbuf',self.keptimg.get_pixbuf())
176
177 def on_add_clicked(self,*args):
178 self.do_add_row()
179
180 def on_clear_clicked(self,*args):
181 _store = self.view.get_model()
182 _store.clear();
183 self.rows = {}
184 self.activeiter = _store.append(None, [ObserverRow()] )
185
186 def do_add_row(self):
187 if self.alive:
188 _row = ObserverRow()
189 self.rows.append(_row)
190 _store = self.view.get_model()
191 _oldrow = _store.get_value(self.activeiter,0)
192 _oldrow.make_static(self)
193 self.activeiter = _store.append(None,[_row])
194 _path = _store.get_path(self.activeiter)
195 _oldpath,_oldcol = self.view.get_cursor()
196 self.view.set_cursor(_path, _oldcol)
197 else:
198 self.browser.reporter.reportError("Can't add row: incorrect observer type")
199
200 def on_view_cell_edited(self, renderer, path, newtext, col):
201 # we can assume it's always the self.activeiter that is edited...
202 if col.instance.isFixed():
203 val = float(newtext) * col.units.getConversion()
204 col.instance.setRealValue( val )
205 self.browser.reporter.reportNote("Updated value to %f" % float(newtext))
206 else:
207 self.browser.reporter.reportError("Can't set a FREE variable from the Observer")
208 return
209 self.browser.do_solve_if_auto()
210
211 def sync(self):
212 self.view.queue_draw()
213 self.browser.reporter.reportNote("SYNC performed")
214
215 def add_instance(self,instance):
216 _col = ObserverColumn(instance,self.colindex,browser=self.browser)
217 self.cols[self.colindex] = _col
218 self.colindex = self.colindex + 1
219
220 # create a new column
221 _renderer = gtk.CellRendererText()
222 _renderer.connect('edited',self.on_view_cell_edited, _col)
223 _tvcol = gtk.TreeViewColumn()
224 _tvcol.set_title(_col.title)
225 _tvcol.pack_start(_renderer,False)
226 _tvcol.set_cell_data_func(_renderer, _col.cellvalue)
227 self.view.append_column(_tvcol);
228 self.browser.reporter.reportError("cols = "+str(self.cols))
229
230 def copy_to_clipboard(self,clip):
231 _s = []
232 _s.append('\t'.join([_v.title for _k,_v in self.cols.iteritems()]))
233 print "COPYING %d ROWS" % len(self.rows)
234 for _r in self.rows:
235 _s.append("\t".join([`_v` for _v in _r.get_values(self)]))
236
237 clip.set_text('\n'.join(_s),-1)
238
239 self.browser.reporter.reportNote("Observer '%s' data copied to clipboard" % self.name)
240
241 #-------------------------------------------------------------------------------
242 # OLD STUFF
243
244 class ObserverTab1:
245 """
246 An 'Observer' tab in the Browser interface. Multiple tabs should be
247 possible.
248 """
249 def __init__(self,xml,name,browser,tab):
250 xml.signal_autoconnect(self);
251
252 self.view = xml.get_widget('observerview')
253 self.tab = tab
254
255 self.activeimg = None
256 self.keptimg = None
257
258 # no instances yet in the observer:
259 self.columninstances = []
260
261 self.columns = [gtk.gdk.Pixbuf,int,bool]
262
263 # units for each data column
264 self.units = []
265 self.titles = []
266
267 _store = gtk.TreeStore(*self.columns)
268 self.rows = []
269
270 # add an empty first row
271 self.rows.append([])
272
273 # work towards having multiple observers for multiple simulations
274 self.name = nameself.view.set_model(_store)
275 self.browser = browser
276
277 # create the 'active' pixbuf columns
278 _renderer = gtk.CellRendererPixbuf()
279 _col = gtk.TreeViewColumn()
280 _col.set_title("")
281 _col.pack_start(_renderer,False)
282 _col.add_attribute(_renderer, 'pixbuf', OBSERVER_ICON)
283 self.view.append_column(_col);
284
285 # create the first row
286 print "Adding row",self.rows[0],"to store"
287 _store.append(None, self.make_row(True, self.rows[0]) )
288
289 self.activerow = 0
290
291 self.view.set_model(_store)
292
293 self.browser.reporter.reportNote("Created observer '%s'" % self.name)
294
295 def on_add_clicked(self,*args):
296 self.do_add_row()
297
298 def do_add_row(self):
299 _rownum = len(self.rows)
300
301 # add a copy of the last row
302 self.rows.append(self.rows[_rownum-1])
303 self.activerow = _rownum
304
305 _m = self.view.get_model()
306 _m.set(self.activeiter,OBSERVER_ICON,self.keptimg,OBSERVER_WEIGHT,pango.WEIGHT_NORMAL,OBSERVER_EDIT,False)
307 self.activeiter = _m.append(None,self.make_row(True,self.rows[_rownum]))
308 self.browser.reporter.reportNote("Kept current values");
309
310 # if the observer is the active tab, move the cursor to the new row.
311 if self.browser.maintabs.get_current_page() == self.tab:
312 self.view.set_cursor(_m.get_path(self.activeiter))
313
314 def on_clear_clicked(self,*args):
315 self.rows = []
316 _r = [_i.getRealValue() for _i in self.columninstances]
317 self.rows.append(_r)
318 self.view.get_model().clear();
319 self.view.get_model().append(None,self.make_row(True,_r))
320 self.browser.reporter.reportNote("Observer '%s' cleared" % self.name)
321
322 def on_view_cell_edited(self, renderer, path, newtext, datacolumn):
323 # we can assume it's always the self.activeiter that is edited...
324 if self.columninstances[datacolumn].isFixed():
325 self.columninstances[datacolumn].setRealValue( float(newtext) * self.units[datacolumn].getConversion() )
326 else:
327 self.browser.reporter.reportError("Can't set a FIXED variable from the Observer")
328 return
329 self.browser.do_solve_if_auto()
330
331 def sync(self):
332 #new row data
333 _r = [self.columninstances[_i].getRealValue() / self.units[_i].getConversion() for _i in range(0,len(self.columninstances)) ]
334
335 _r1 = self.make_row(True,_r)
336
337 # stick the row data into the TreeStore
338 _m = self.view.get_model()
339 _i = 0
340 for _c in _r1:
341 _m.set(self.activeiter, _i, _c)
342 _i = _i + 1
343
344 # keep the data in self.rows as well
345 self.rows[self.activerow] = _r;
346
347 def copy_to_clipboard(self,clip):
348 _s = []
349 _s.append('\t'.join(self.titles))
350 for _r in self.rows:
351 _s.append( '\t'.join([`_c` for _c in _r]) )
352
353 clip.set_text('\n'.join(_s),-1)
354
355 self.browser.reporter.reportNote("Observer '%s' data copied to clipboard" % self.name)
356
357 def make_row(self,isactive,row):
358 # add the initial OBSERVER_INITIAL_COLS fields:
359 if isactive:
360 _r = [self.activeimg, pango.WEIGHT_BOLD, True]
361 else:
362 _r = [self.keptimg, pango.WEIGHT_NORMAL, False]
363
364 for _c in row:
365 _r.append(_c)
366
367 return _r
368
369 def add_instance(self, inst):
370 # TODO big changes here....
371 if not inst.getType().isRefinedSolverVar():
372 self.browser.reporter.reportError("Instance is not a refined solver variable: can't 'observe'.");
373 return
374
375 _colnum = len(self.columns)
376 _colname = self.browser.sim.getInstanceName(inst)
377 _rownum = len(self.rows)-1
378
379 # store the instances in self.columninstances for sync purposes
380 self.columninstances.append(inst)
381
382 # create new TreeStore, copy of old, plus one columm
383 self.columns.append(float)
384 _units = inst.getType().getPreferredUnits()
385 if _units == None:
386 _units = inst.getType().getDimensions().getDefaultUnits()
387
388 _uname = str(_units.getName())
389 if _uname.find("/")!=-1:
390 _uname = "["+_uname+"]"
391
392 if _uname == "":
393 _title = "%s" % (_colname)
394 else:
395 _title = "%s / %s" % (_colname, _uname)
396
397 self.titles.append(_title);
398 self.units.append(_units) # we keep a track of the preferred units for the column at the time of the column creation
399
400 _store = gtk.TreeStore(*(self.columns))
401
402 _iter = None
403 _i = 0
404 _active = False
405 for _r in self.rows:
406 _r.append(OBSERVER_NULL)
407 if _i == _rownum:
408 _active = True
409 _iter = _store.append(None, self.make_row(_active,_r) )
410 _i = _i + 1
411
412 self.activeiter = _iter
413
414 # add newest data point in bottom-right
415 _datacol = _colnum - OBSERVER_INITIAL_COLS
416 _dataval = inst.getRealValue() / self.units[_datacol].getConversion() # convert value to units specified when col created
417 self.rows[_rownum][_datacol] = _dataval
418 _store.set_value(self.activeiter, _colnum, _dataval)
419
420 # re-assign store to TreeView
421 self.view.set_model(_store)
422
423 _renderer = gtk.CellRendererText()
424 _renderer.connect('edited',self.on_view_cell_edited, _datacol)
425 _col = gtk.TreeViewColumn(_title, _renderer)
426 _col.add_attribute(_renderer, 'text', _colnum)
427 _col.add_attribute(_renderer, 'weight', OBSERVER_WEIGHT)
428 _col.add_attribute(_renderer, 'editable', OBSERVER_EDIT)
429 _col.set_alignment(0.0)
430 _col.set_reorderable(True)
431 _col.set_sort_column_id(_colnum)
432
433 self.view.append_column(_col);
434
435 self.browser.reporter.reportNote("Added variable '%s' to observer '%s'" % (_colname,self.name))
436
437

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