Package qubx :: Module trials
[hide private]
[frames] | no frames]

Source Code for Module qubx.trials

  1  """Components for the managing and visualizing L{qubx.trialset.TrialSet}s. 
  2   
  3  Copyright 2012-2014 Research Foundation State University of New York  
  4  This file is part of QUB Express.                                           
  5   
  6  QUB Express is free software; you can redistribute it and/or modify           
  7  it under the terms of the GNU General Public License as published by  
  8  the Free Software Foundation, either version 3 of the License, or     
  9  (at your option) any later version.                                   
 10   
 11  QUB Express is distributed in the hope that it will be useful,                
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of        
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         
 14  GNU General Public License for more details.                          
 15   
 16  You should have received a copy of the GNU General Public License,    
 17  named LICENSE.txt, in the QUB Express program directory.  If not, see         
 18  <http://www.gnu.org/licenses/>.                                       
 19   
 20   
 21  """ 
 22   
 23  import os 
 24  import traceback 
 25   
 26  import gtk 
 27  import gobject 
 28   
 29  import qubx.global_namespace 
 30  import qubx.GTK 
 31  import qubx.model 
 32  import qubx.modelGTK 
 33  import qubx.pyenv 
 34  import qubx.tableGTK 
 35  from qubx.GTK import build_menuitem, pack_item, pack_label 
 36  from qubx.table import COPY_ROWS_ALL, COPY_ROWS_CHECKED, COPY_ROWS_GROUP, COPY_ROWS_CRITERIA 
 37  from qubx.toolspace import ColorInfo 
 38  from qubx.util_types import WeakEvent, Reffer, bind 
 39   
 40  COLOR_TRIALS_BG = ('trials.model.bg', (.92, .96, 1, 1)) 
 41  ColorInfo[COLOR_TRIALS_BG[0]].label = 'Trials model background' 
 42   
 43   
44 -class Trials(object):
45 - def __init__(self, Data, model):
46 self.model = model 47 self.trialsets = [] 48 self.trialset_names = [] 49 self.__recent_by_datapath = {} 50 self.num_indep = 0 51 self.__save_path = "" 52 self.__ref = Reffer() 53 self.__data = None 54 self.__trialset = None 55 self.__table = None 56 self.OnSwitch = WeakEvent() 57 self.OnChangeNames = WeakEvent() 58 Data.OnSwitch += self.__ref(self.__onSwitchData) 59 Data.OnClosing += self.__ref(self.__onClosingData) 60 self.__onSwitchData(Data, Data.file)
61 trialset = property(lambda self: self.__trialset, lambda self, x: self.set_trialset(x)) 62 trialset_by_name = property(lambda self: self.__trialset and self.__trialset.trialset_name or "", lambda self, x: self.set_trialset_by_name(x))
63 - def __onSwitchData(self, Data, file):
64 if self.__data: 65 if self.trialset in self.__data.trials.trialsets: 66 self.trialset = self.trialsets[self.num_indep-1] if self.num_indep else None 67 self.__data.trials.OnInsert -= self.__ref(self.__onInsertTrialset) 68 self.__data.trials.OnRemoving -= self.__ref(self.__onRemovingTrialset) 69 del self.trialsets[self.num_indep:] 70 del self.trialset_names[self.num_indep:] 71 self.__data = file 72 if self.__data: 73 self.__data.trials.OnInsert += self.__ref(self.__onInsertTrialset) 74 self.__data.trials.OnRemoving += self.__ref(self.__onRemovingTrialset) 75 self.trialsets.extend(file.trials.trialsets) 76 self.trialset_names.extend(file.trials.trialset_names) 77 self.OnChangeNames() 78 if self.__data: 79 try: # restore last trialset for data if possible 80 self.trialset = self.trialsets[self.trialset_names.index(self.__recent_by_datapath[self.__data.path])] 81 except: 82 pass 83 if (self.__trialset is None) and self.trialsets: 84 self.trialset = self.trialsets[0]
85 - def __onClosingData(self, ix):
86 data = qubx.global_namespace.QubX.Data.views[ix].file 87 for ts in data.trials.trialsets: 88 if not ts.in_qsf: 89 self.prompt_save(ts, data, can_cancel=False)
90 - def __onInsertTrialset(self, ix, trialset):
91 self.trialsets.insert(self.num_indep+ix, trialset) 92 self.trialset_names.insert(self.num_indep+ix, trialset.trialset_name) 93 self.OnChangeNames() 94 if len(self.trialsets) == 1: 95 self.trialset = trialset
96 - def __onRemovingTrialset(self, ix, trialset):
97 if trialset == self.__trialset: 98 self.__adjust_ts_closing() 99 del self.trialsets[self.num_indep+ix] 100 del self.trialset_names[self.num_indep+ix] 101 self.OnChangeNames()
102 - def set_trialset_by_name(self, x):
103 self.trialset = self.trialsets[self.trialset_names.index(x)]
104 - def set_trialset(self, ts):
105 if ts == self.__trialset: return 106 if not (self.__trialset is None): 107 self.__trialset.OnSelect -= self.__ref(self.__onSelectTrial) 108 self.__trialset.OnDoubleClick -= self.__ref(self.__onDoubleClickTrial) 109 self.__trialset.OnSetInQSF -= self.__ref(self.__onSetInQSF) 110 self.__trialset = ts 111 if not (self.__trialset is None): 112 self.__recent_by_datapath[self.__data.path] = ts.trialset_name 113 self.__trialset.OnSelect += self.__ref(self.__onSelectTrial) 114 self.__trialset.OnDoubleClick += self.__ref(self.__onDoubleClickTrial) 115 self.__trialset.OnSetInQSF += self.__ref(self.__onSetInQSF) 116 qubx.pyenv.env.OnScriptable('QubX.Trials.trialset_by_name = %s' % repr(ts.trialset_name)) 117 if self.__trialset.size: 118 self.__trialset.select(0) 119 self.show_trialset_table(ts) 120 self.OnSwitch(ts)
121 - def get_trialset(self, name, in_qsf=False):
122 try: 123 return self.trialsets[self.trialset_names.index(name)] 124 except ValueError: 125 return self.__data.trials.get_trialset(name, in_qsf)
126 - def remove_trialset(self, name, force=True):
127 try: 128 ix = self.trialset_names.index(name) 129 if ix >= self.num_indep: 130 if force or self.prompt_save(self.trialsets[ix], self.__data): 131 self.__data.trials.remove_trialset(name) 132 else: 133 if (not (self.__trialset is None)) and (name == self.__trialset.trialset_name): 134 self.__adjust_ts_closing() 135 self.trialsets[ix].dispose() 136 del self.trialsets[ix] 137 del self.trialset_names[ix] 138 self.num_indep -= 1 139 self.OnChangeNames() 140 except ValueError: 141 pass
142 - def __adjust_ts_closing(self):
143 if len(self.trialsets) == 1: 144 self.trialset = None 145 else: 146 ix = self.trialsets.index(self.__trialset) 147 if ix == 0: 148 self.trialset = self.trialsets[1] 149 else: 150 self.trialset = self.trialsets[ix-1]
151 - def open(self, path=None):
152 if path is None: 153 return qubx.GTK.Open('Open Trials...', self.__save_path, self.open) 154 qubx.pyenv.env.OnScriptable('QubX.Trials.open(%s)' % repr(path)) 155 base = os.path.splitext(path)[0] 156 self.__save_path, name = os.path.split(base) 157 ts_name = '/%s' % name # to distinguish from per-file trialsets 158 ts = qubx.trialset.TrialSet(ts_name) 159 ts.from_text(open(path, 'r').read(), keep_fields=True) 160 files = "%s_files" % base 161 for i in xrange(ts.size): 162 try: 163 ts.models[i] = qubx.tree.Open(os.path.join(files, "model_%i.qmf" % i), readOnly=True) 164 ts.models[i].close() 165 except: 166 traceback.print_exc() ### pass 167 ix = self.num_indep 168 self.trialsets.insert(ix, ts) 169 self.trialset_names.insert(ix, ts_name) 170 self.num_indep += 1 171 self.OnChangeNames() 172 self.trialset = ts 173 qubx.global_namespace.QubX.Models.index = 0 # request_show()
174 - def save(self, path=None, trialset=None):
175 ts = self.__trialset if (trialset is None) else trialset 176 if ts is None: return 177 if not path: 178 name = ts.trialset_name 179 if name and (name[0] == '/'): 180 name = name[1:] 181 qubx.GTK.SaveAs('Save Trials...', self.__save_path, name, self.save) 182 return 183 if ts == self.__trialset: 184 qubx.pyenv.env.OnScriptable('QubX.Trials.save(%s)' % repr(path)) 185 self.__save_path = os.path.split(path)[0] 186 base = os.path.splitext(path)[0] 187 files = "%s_files" % base 188 self.__save_path, name = os.path.split(base) 189 open(path, 'w').write(ts.to_text()) 190 if not os.path.exists(files): 191 os.makedirs(files) 192 for i in xrange(ts.size): 193 try: 194 ts.models[i].saveAs(os.path.join(files, "model_%i.qmf" % i), as_copy=True) 195 except: 196 traceback.print_exc()
197 - def prompt_save(self, trialset, data, can_cancel=True):
198 if can_cancel: 199 choice_i = qubx.GTK.PromptChoices('Save Trials "%s" of %s?' % (trialset.trialset_name, os.path.split(data.path)[1]), 200 ['Discard', 'Cancel', 'Save...']) 201 else: 202 #choice_i = 0 203 choice_i = qubx.GTK.PromptChoices('Save Trials "%s" of %s?' % (trialset.trialset_name, os.path.split(data.path)[1]), 204 ['Discard', 'Save...']) 205 if choice_i: choice_i = 2 206 if choice_i == 1: 207 return False 208 if choice_i == 2: 209 self.save(trialset=trialset) 210 return True
211 - def __onSelectTrial(self, index, field=None, sender=None):
212 self.model.set_trial(self.trialset.models[index])
213 - def __onDoubleClickTrial(self, index, field_name=None):
214 qubx.global_namespace.QubX.Models.index = 0 # request_show()
215 - def __onSetInQSF(self, ts, in_qsf):
216 self.chkInQSF.set_active(in_qsf)
217 - def __onToggleInQSF(self, chk):
218 in_qsf = chk.get_active() 219 qubx.pyenv.env.OnScriptable('QubX.Trials.trialset.in_qsf = %s' % repr(in_qsf)) 220 self.__table.in_qsf = in_qsf
221 - def show_trialset_table(self, ts):
222 if not (self.__table is None): 223 qubx.global_namespace.QubX.Tables.remove_table(self.__table) 224 self.__table = None 225 if not (ts is None): 226 mnuFile = gtk.Menu() 227 build_menuitem('Open Trials...', self.__ref(self.__onClickOpen), menu=mnuFile) 228 build_menuitem('Save Trials as...', self.__ref(self.__onClickSave), menu=mnuFile) 229 build_menuitem('Close', self.__ref(self.__onClickClose), menu=mnuFile) 230 btnFile = qubx.toolspace.Button_Popup(mnuFile, qubx.tableGTK.COLOR_TABLE_FILE_MENU, "File menu") 231 mnuTrials = qubx.GTK.DynamicComboBox() 232 mnuTrials.OnPopulate += self.__ref(self.__onPopulateTrials) 233 mnuTrials.OnChanged += self.__ref(self.__onChooseTrials) 234 mnuTrials.active_text = ts.trialset_name 235 self.chkInQSF = gtk.CheckButton('keep with data') 236 self.chkInQSF.set_tooltip_text('When checked, the Trials are saved in the QSF (session) file') 237 self.chkInQSF.set_active(ts.in_qsf) 238 self.chkInQSF.connect('toggled', self.__onToggleInQSF) 239 self.chkInQSF.show() 240 controls = qubx.tableGTK.TableViewCtrls(ts, None, 241 btnFile, 'Trials:', mnuTrials, self.chkInQSF, 242 ('Show in Models', bind(qubx.global_namespace.QubX.Models.set_index, 0)), 243 qubx.tableGTK.TableViewCtrls.REMOVE, 244 ('Copy row(s) to...', self.copy_rows), 245 qubx.tableGTK.TableViewCtrls.CALCULATE, 246 qubx.tableGTK.TableViewCtrls.PLOT, 247 qubx.tableGTK.TableViewCtrls.CLOSE) 248 controls.OnClickClose += self.__ref(self.__onClickClose) 249 Tables = qubx.global_namespace.QubX.Tables 250 Tables.add_table(ts, None, controls) 251 self.__table = ts 252 Tables.show_table(ts)
253 - def __onClickOpen(self, item):
254 self.open()
255 - def __onClickSave(self, item):
256 self.save()
257 - def __onClickClose(self, *args):
258 qubx.pyenv.env.OnScriptable('QubX.Trials.remove_trialset(%s)' % repr(self.trialset.trialset_name)) 259 self.remove_trialset(self.trialset.trialset_name, force=False)
260 - def __onPopulateTrials(self, add):
261 for name in self.trialset_names: 262 add(name)
263 - def __onChooseTrials(self, mnu, ts_name):
264 self.trialset = self.trialsets[self.trialset_names.index(ts_name)]
265 - def copy_rows(self, out_name=None, copy_rows_type=None, group=None, inverse=False, criteria=None):
266 tbn, crt, grp, inv, cta = qubx.tableGTK.prompt_copy_rows(self.trialset, self.trialset.trialset_name, self.trialset_names, 267 out_name, copy_rows_type, group, inverse, criteria) 268 if crt is None: # dialog cancel 269 return 270 if crt == COPY_ROWS_ALL: 271 qubx.pyenv.env.OnScriptable('QubX.Trials.copy_rows(out_name=%s, copy_rows_type=COPY_ROWS_ALL)' 272 % repr(tbn)) 273 elif crt == COPY_ROWS_GROUP: 274 qubx.pyenv.env.OnScriptable('QubX.Trials.copy_rows(out_name=%s, copy_rows_type=COPY_ROWS_GROUP, group=%s, inverse=%s)' 275 % (repr(tbn), 276 repr(grp), repr(inv))) 277 elif crt == COPY_ROWS_CRITERIA: 278 qubx.pyenv.env.OnScriptable('QubX.Trials.copy_rows(out_name=%s, copy_rows_type=COPY_ROWS_CRITERIA, criteria=%s)' 279 % (repr(tbn), repr(cta))) 280 elif crt == COPY_ROWS_CHECKED: 281 qubx.pyenv.env.OnScriptable('QubX.Trials.copy_rows(out_name=%s, copy_rows_type=COPY_ROWS_CHECKED)' 282 % repr(tbn)) 283 from_ts = self.trialset 284 ts = self.trialset = self.get_trialset(tbn) 285 gobject.idle_add(qubx.global_namespace.QubX.Tables.show_table, ts) 286 ts.copy_rows_from(from_ts, copy_rows_type=crt, group=grp, inverse=inv, criteria=cta, on_copy=self.__onCopyRow) 287 return ts
288 - def __onCopyRow(self, from_list, from_i, to_list, to_i):
289 to_list.models[to_i] = from_list.models[from_i].clone()
290
291 -class TrialsView(qubx.modelGTK.QubModelView):
292 - def __init__(self, models_table=None, menu_width=32):
293 qubx.modelGTK.QubModelView.__init__(self, models_table, menu_width) 294 self.cBG = COLOR_TRIALS_BG
295 - def set_trial(self, model_tree):
296 self.file.from_tree(model_tree) 297 self.file.undoStack.clear()
298