1 |
import pygtk |
2 |
pygtk.require('2.0') |
3 |
import gtk |
4 |
import gtk.glade |
5 |
import pango |
6 |
|
7 |
OBSERVER_INITIAL_COLS = 3 # how many cells are at the start of the table? |
8 |
OBSERVER_ICON, OBSERVER_WEIGHT, OBSERVER_EDIT = range(0,OBSERVER_INITIAL_COLS) # column indices for the start of the TreeStore |
9 |
OBSERVER_NULL = 0 # value that gets added to empty cells in a new column |
10 |
|
11 |
# This is messy code since it doesn't observe the convention of keeping your model |
12 |
# separate from your view. It's all mixed up together. Yuck. Part of the |
13 |
# difficulty with that was the fact that TreeStores don't support the adding of |
14 |
# columns. |
15 |
|
16 |
class ObserverTab: |
17 |
def __init__(self,xml,name,browser,tab): |
18 |
xml.signal_autoconnect(self); |
19 |
|
20 |
self.view = xml.get_widget('observerview') |
21 |
self.tab = tab |
22 |
|
23 |
#self.activeimg = gtk.Image() |
24 |
#self.activeimg.set_from_file("icons/active.png") |
25 |
self.activeimg = None |
26 |
self.keptimg = None |
27 |
|
28 |
# no instances yet in the observer: |
29 |
self.columninstances = [] |
30 |
|
31 |
self.columns = [gtk.gdk.Pixbuf,int,bool] |
32 |
|
33 |
# units for each data column |
34 |
self.units = [] |
35 |
self.titles = [] |
36 |
|
37 |
_store = gtk.TreeStore(*self.columns) |
38 |
self.rows = [] |
39 |
|
40 |
# add an empty first row |
41 |
self.rows.append([]) |
42 |
|
43 |
# work towards having multiple observers for multiple simulations |
44 |
self.name = name |
45 |
self.browser = browser |
46 |
|
47 |
# create the 'active' pixvuf columns |
48 |
_renderer = gtk.CellRendererPixbuf() |
49 |
_col = gtk.TreeViewColumn() |
50 |
_col.set_title("") |
51 |
_col.pack_start(_renderer,False) |
52 |
_col.add_attribute(_renderer, 'pixbuf', OBSERVER_ICON) |
53 |
self.view.append_column(_col); |
54 |
|
55 |
# create the first row |
56 |
print "Adding row",self.rows[0],"to store" |
57 |
_store.append(None, self.make_row(True, self.rows[0]) ) |
58 |
|
59 |
self.activerow = 0 |
60 |
|
61 |
self.view.set_model(_store) |
62 |
|
63 |
self.browser.reporter.reportNote("Created observer '%s'" % self.name) |
64 |
|
65 |
def on_add_clicked(self,*args): |
66 |
self.do_add_row() |
67 |
|
68 |
def do_add_row(self): |
69 |
_rownum = len(self.rows) |
70 |
|
71 |
# add a copy of the last row |
72 |
self.rows.append(self.rows[_rownum-1]) |
73 |
self.activerow = _rownum |
74 |
|
75 |
_m = self.view.get_model() |
76 |
_m.set(self.activeiter,OBSERVER_ICON,self.keptimg,OBSERVER_WEIGHT,pango.WEIGHT_NORMAL,OBSERVER_EDIT,False) |
77 |
self.activeiter = _m.append(None,self.make_row(True,self.rows[_rownum])) |
78 |
self.browser.reporter.reportNote("Kept current values"); |
79 |
|
80 |
# if the observer is the active tab, move the cursor to the new row. |
81 |
if self.browser.maintabs.get_current_page() == self.tab: |
82 |
self.view.set_cursor(_m.get_path(self.activeiter)) |
83 |
|
84 |
def on_clear_clicked(self,*args): |
85 |
self.rows = [] |
86 |
_r = [_i.getRealValue() for _i in self.columninstances] |
87 |
self.rows.append(_r) |
88 |
self.view.get_model().clear(); |
89 |
self.view.get_model().append(None,self.make_row(True,_r)) |
90 |
self.browser.reporter.reportNote("Observer '%s' cleared" % self.name) |
91 |
|
92 |
def on_view_cell_edited(self, renderer, path, newtext, datacolumn): |
93 |
# we can assume it's always the self.activeiter that is edited... |
94 |
if self.columninstances[datacolumn].isFixed(): |
95 |
self.columninstances[datacolumn].setRealValue( float(newtext) * self.units[datacolumn].getConversion() ) |
96 |
else: |
97 |
self.browser.reporter.reportError("Can't set a FIXED variable from the Observer") |
98 |
return |
99 |
self.browser.do_solve_if_auto() |
100 |
|
101 |
def sync(self): |
102 |
#new row data |
103 |
_r = [self.columninstances[_i].getRealValue() / self.units[_i].getConversion() for _i in range(0,len(self.columninstances)) ] |
104 |
|
105 |
_r1 = self.make_row(True,_r) |
106 |
|
107 |
# stick the row data into the TreeStore |
108 |
_m = self.view.get_model() |
109 |
_i = 0 |
110 |
for _c in _r1: |
111 |
_m.set(self.activeiter, _i, _c) |
112 |
_i = _i + 1 |
113 |
|
114 |
# keep the data in self.rows as well |
115 |
self.rows[self.activerow] = _r; |
116 |
|
117 |
def copy_to_clipboard(self,clip): |
118 |
_s = [] |
119 |
_s.append('\t'.join(self.titles)) |
120 |
for _r in self.rows: |
121 |
_s.append( '\t'.join([`_c` for _c in _r]) ) |
122 |
|
123 |
clip.set_text('\n'.join(_s),-1) |
124 |
|
125 |
self.browser.reporter.reportNote("Observer '%s' data copied to clipboard" % self.name) |
126 |
|
127 |
def make_row(self,isactive,row): |
128 |
# add the initial OBSERVER_INITIAL_COLS fields: |
129 |
if isactive: |
130 |
_r = [self.activeimg, pango.WEIGHT_BOLD, True] |
131 |
else: |
132 |
_r = [self.keptimg, pango.WEIGHT_NORMAL, False] |
133 |
|
134 |
for _c in row: |
135 |
_r.append(_c) |
136 |
|
137 |
return _r |
138 |
|
139 |
def add_instance(self, inst): |
140 |
if not inst.getType().isRefinedSolverVar(): |
141 |
self.browser.reporter.reportError("Instance is not a refined solver variable: can't 'observe'."); |
142 |
return |
143 |
|
144 |
_colnum = len(self.columns) |
145 |
_colname = self.browser.sim.getInstanceName(inst) |
146 |
_rownum = len(self.rows)-1 |
147 |
|
148 |
# store the instances in self.columninstances for sync purposes |
149 |
self.columninstances.append(inst) |
150 |
|
151 |
# create new TreeStore, copy of old, plus one columm |
152 |
self.columns.append(float) |
153 |
_units = inst.getType().getPreferredUnits() |
154 |
if _units == None: |
155 |
_units = inst.getType().getDimensions().getDefaultUnits() |
156 |
|
157 |
_uname = str(_units.getName()) |
158 |
if _uname.find("/")!=-1: |
159 |
_uname = "["+_uname+"]" |
160 |
|
161 |
_title = "%s / %s" % (_colname, _uname) |
162 |
|
163 |
self.titles.append(_title); |
164 |
self.units.append(_units) # we keep a track of the preferred units for the column at the time of the column creation |
165 |
|
166 |
_store = gtk.TreeStore(*(self.columns)) |
167 |
|
168 |
_iter = None |
169 |
_i = 0 |
170 |
_active = False |
171 |
for _r in self.rows: |
172 |
_r.append(OBSERVER_NULL) |
173 |
if _i == _rownum: |
174 |
_active = True |
175 |
_iter = _store.append(None, self.make_row(_active,_r) ) |
176 |
_i = _i + 1 |
177 |
|
178 |
self.activeiter = _iter |
179 |
|
180 |
# add newest data point in bottom-right |
181 |
_datacol = _colnum - OBSERVER_INITIAL_COLS |
182 |
_dataval = inst.getRealValue() / self.units[_datacol].getConversion() # convert value to units specified when col created |
183 |
self.rows[_rownum][_datacol] = _dataval |
184 |
_store.set_value(self.activeiter, _colnum, _dataval) |
185 |
|
186 |
# re-assign store to TreeView |
187 |
self.view.set_model(_store) |
188 |
|
189 |
_renderer = gtk.CellRendererText() |
190 |
_renderer.connect('edited',self.on_view_cell_edited, _datacol) |
191 |
_col = gtk.TreeViewColumn(_title, _renderer) |
192 |
_col.add_attribute(_renderer, 'text', _colnum) |
193 |
_col.add_attribute(_renderer, 'weight', OBSERVER_WEIGHT) |
194 |
_col.add_attribute(_renderer, 'editable', OBSERVER_EDIT) |
195 |
_col.set_alignment(0.0) |
196 |
_col.set_reorderable(True) |
197 |
_col.set_sort_column_id(_colnum) |
198 |
|
199 |
self.view.append_column(_col); |
200 |
|
201 |
self.browser.reporter.reportNote("Added variable '%s' to observer '%s'" % (_colname,self.name)) |
202 |
|