def tod_context_edit_activate_cb(self, menuitem, data=None): """Run edit time dialog.""" #!!!@ require road race specific editor dialog? sel = self.view.get_selection().get_selected() if sel is not None: i = sel[1] # grab off row iter and read in cur times tst = self.riders.get_value(i, COL_TODSTART) tft = self.riders.get_value(i, COL_TODFINISH) # prepare text entry boxes st = '' if tst is not None: st = tst.timestr() ft = '' if tft is not None: ft = tft.timestr() # run the dialog (ret, st, ft) = uiutil.edit_times_dlg(self.meet.window, st, ft) if ret == 1: stod = tod.str2tod(st) ftod = tod.str2tod(ft) bib = self.riders.get_value(i, COL_BIB) series = self.riders.get_value(i, COL_SERIES) self.settimes(i, tst=stod, tft=ftod) # update model self.log.info('Race times manually adjusted for rider ' + strops.bibser2bibstr(bib, series)) else: self.log.info('Edit race times cancelled.')
def menu_timing_recalc(self, entry, ste, fte, nte): """Update the net time entry for the supplied start and finish.""" st = tod.str2tod(ste.get_text()) ft = tod.str2tod(fte.get_text()) if st is not None and ft is not None: ste.set_text(st.timestr()) fte.set_text(ft.timestr()) nte.set_text((ft - st).timestr())
def loadconfig(self): """Load race config from disk.""" self.riders.clear() #self.results.clear() # defaults # +type specific overrides cr = ConfigParser.ConfigParser({ 'startlist': '', 'start': '', 'lstart': '', 'places': '', 'limit': '' }) cr.add_section('race') cr.add_section('riders') if os.path.isfile(self.configpath): self.log.debug('Attempting to read config from ' + repr(self.configpath)) cr.read(self.configpath) # re-load starters/results for rs in cr.get('race', 'startlist').split(): (r, s) = strops.bibstr2bibser(rs) self.addrider(r, s) if cr.has_option('riders', rs): # bbb.sss = comment,inrace,hcap,finish,mbunch nr = self.getrider(r, s) ril = csv.reader([cr.get('riders', rs)]).next() lr = len(ril) if lr > 0: nr[COL_COMMENT] = ril[0] if lr > 1: nr[COL_INRACE] = strops.confopt_bool(ril[1]) if lr > 2: nr[COL_HCAP] = tod.str2tod(ril[2]) if lr > 3: nr[COL_FINISH] = tod.str2tod(ril[3]) if lr > 4: nr[COL_MBUNCH] = tod.str2tod(ril[4]) if nr[COL_HCAP] is None: nr[COL_HCAP] = tod.ZERO # default to 'scratch' if self.limit_tod is not None: if nr[COL_HCAP] > self.limit_tod: self.log.error('Handicap greater than limit for ' + rs + ' set to limit.') nr[COL_HCAP] = self.limit_tod places = strops.reformat_bibserplacelist(cr.get('race', 'places')) #!!! #self.ctrl_places.set_text(places) #self.ctrl_places.set_sensitive(False) #self.recalculate() # re-join an existing timer state self.set_start(tod.str2tod(cr.get('race', 'start')), tod.str2tod(cr.get('race', 'lstart')))
def loadconfig(self): """Load race config from disk.""" self.riders.clear() #self.results.clear() # defaults # +type specific overrides cr = ConfigParser.ConfigParser({'startlist':'', 'start':'', 'lstart':'', 'places':'', 'limit':'' }) cr.add_section('race') cr.add_section('riders') if os.path.isfile(self.configpath): self.log.debug('Attempting to read config from ' + repr(self.configpath)) cr.read(self.configpath) # re-load starters/results for rs in cr.get('race', 'startlist').split(): (r, s) = strops.bibstr2bibser(rs) self.addrider(r, s) if cr.has_option('riders', rs): # bbb.sss = comment,inrace,hcap,finish,mbunch nr = self.getrider(r, s) ril = csv.reader([cr.get('riders', rs)]).next() lr = len(ril) if lr > 0: nr[COL_COMMENT] = ril[0] if lr > 1: nr[COL_INRACE] = strops.confopt_bool(ril[1]) if lr > 2: nr[COL_HCAP] = tod.str2tod(ril[2]) if lr > 3: nr[COL_FINISH] = tod.str2tod(ril[3]) if lr > 4: nr[COL_MBUNCH] = tod.str2tod(ril[4]) if nr[COL_HCAP] is None: nr[COL_HCAP] = tod.ZERO # default to 'scratch' if self.limit_tod is not None: if nr[COL_HCAP] > self.limit_tod: self.log.error('Handicap greater than limit for ' + rs + ' set to limit.') nr[COL_HCAP] = self.limit_tod places = strops.reformat_bibserplacelist(cr.get('race', 'places')) #!!! #self.ctrl_places.set_text(places) #self.ctrl_places.set_sensitive(False) #self.recalculate() # re-join an existing timer state self.set_start(tod.str2tod(cr.get('race', 'start')), tod.str2tod(cr.get('race', 'lstart')))
def loadconfig(self): """Load race config from disk.""" self.riders.clear() self.resettimer() cr = ConfigParser.ConfigParser({ 'start': '', 'lstart': '', 'id': EVENT_ID, 'finish': '', 'finished': 'No', 'startlist': '' }) cr.add_section('event') cr.add_section('riders') if os.path.isfile(self.configpath): self.log.debug('Attempting to read config from path=' + repr(self.configpath)) cr.read(self.configpath) starters = cr.get('event', 'startlist').split() # for a sportif - always sort by bib starters.sort(cmp=sort_bib) for r in starters: self.addrider(r) if cr.has_option('riders', r): nr = self.getrider(r) # bib = comment,rftod,rfseen... ril = csv.reader([cr.get('riders', r)]).next() lr = len(ril) if lr > 0: nr[COL_COMMENT] = ril[0] if lr > 1: nr[COL_RFTIME] = tod.str2tod(ril[1]) if lr > 2: for i in range(2, lr): laptod = tod.str2tod(ril[i]) if laptod is not None: nr[COL_RFSEEN].append(laptod) self.set_start(cr.get('event', 'start'), cr.get('event', 'lstart')) self.set_finish(cr.get('event', 'finish')) if cr.get('event', 'finished') == 'Yes': self.set_finished() # After load complete - check config and report. This ensures # an error message is left on top of status stack. This is not # always a hard fail and the user should be left to determine # an appropriate outcome. eid = cr.get('event', 'id') if eid != EVENT_ID: self.log.error('Event configuration mismatch: ' + repr(eid) + ' != ' + repr(EVENT_ID))
def loadconfig(self): """Load race config from disk.""" self.riders.clear() self.resettimer() cr = ConfigParser.ConfigParser({'start':'', 'lstart':'', 'id':EVENT_ID, 'finish':'', 'finished':'No', 'startlist':''}) cr.add_section('event') cr.add_section('riders') if os.path.isfile(self.configpath): self.log.debug('Attempting to read config from path=' + repr(self.configpath)) cr.read(self.configpath) starters = cr.get('event', 'startlist').split() # for a sportif - always sort by bib starters.sort(cmp=sort_bib) for r in starters: self.addrider(r) if cr.has_option('riders', r): nr = self.getrider(r) # bib = comment,rftod,rfseen... ril = csv.reader([cr.get('riders', r)]).next() lr = len(ril) if lr > 0: nr[COL_COMMENT] = ril[0] if lr > 1: nr[COL_RFTIME] = tod.str2tod(ril[1]) if lr > 2: for i in range(2, lr): laptod = tod.str2tod(ril[i]) if laptod is not None: nr[COL_RFSEEN].append(laptod) self.set_start(cr.get('event', 'start'), cr.get('event', 'lstart')) self.set_finish(cr.get('event', 'finish')) if cr.get('event', 'finished') == 'Yes': self.set_finished() # After load complete - check config and report. This ensures # an error message is left on top of status stack. This is not # always a hard fail and the user should be left to determine # an appropriate outcome. eid = cr.get('event', 'id') if eid != EVENT_ID: self.log.error('Event configuration mismatch: ' + repr(eid) + ' != ' + repr(EVENT_ID))
def loadconfig(self): """Load race config from disk.""" self.riders.clear() self.results.clear() # failsafe defaults -> dual timer, C0 start, PA/PB # type specific overrides cr = ConfigParser.ConfigParser({ 'startlist': '', 'start': '', 'lstart': '' }) cr.add_section('race') cr.add_section('riders') if os.path.isfile(self.configpath): self.log.debug('Attempting to read config from ' + repr(self.configpath)) cr.read(self.configpath) # re-load starters/results self.onestart = False for rs in cr.get('race', 'startlist').split(): (r, s) = strops.bibstr2bibser(rs) self.addrider(r, s) wst = None tst = None ft = None if cr.has_option('riders', rs): # bbb.sss = comment,wall_start,timy_start,finish,place nr = self.getrider(r, s) ril = csv.reader([cr.get('riders', rs)]).next() lr = len(ril) if lr > 0: nr[COL_COMMENT] = ril[0] if lr > 1: wst = tod.str2tod(ril[1]) if lr > 2: tst = tod.str2tod(ril[2]) if lr > 3: ft = tod.str2tod(ril[3]) nri = self.getiter(r, s) self.settimes(nri, wst, tst, ft, doplaces=False) self.placexfer() # re-join any existing timer state -> no, just do a start self.set_syncstart(tod.str2tod(cr.get('race', 'start')), tod.str2tod(cr.get('race', 'lstart')))
def set_start(self, start='', lstart=None): """Set the start time.""" if type(start) is tod.tod: self.start = start if lstart is not None: self.lstart = lstart else: self.lstart = self.start else: self.start = tod.str2tod(start) if lstart is not None: self.lstart = tod.str2tod(lstart) else: self.lstart = self.start if self.start is not None and self.finish is None: self.set_running()
def loadconfig(self): """Load race config from disk.""" self.riders.clear() self.results.clear() # failsafe defaults -> dual timer, C0 start, PA/PB # type specific overrides cr = ConfigParser.ConfigParser({'startlist':'', 'start':'', 'lstart':'' }) cr.add_section('race') cr.add_section('riders') if os.path.isfile(self.configpath): self.log.debug('Attempting to read config from ' + repr(self.configpath)) cr.read(self.configpath) # re-load starters/results self.onestart = False for rs in cr.get('race', 'startlist').split(): (r, s) = strops.bibstr2bibser(rs) self.addrider(r, s) wst = None tst = None ft = None if cr.has_option('riders', rs): # bbb.sss = comment,wall_start,timy_start,finish,place nr = self.getrider(r, s) ril = csv.reader([cr.get('riders', rs)]).next() lr = len(ril) if lr > 0: nr[COL_COMMENT] = ril[0] if lr > 1: wst = tod.str2tod(ril[1]) if lr > 2: tst = tod.str2tod(ril[2]) if lr > 3: ft = tod.str2tod(ril[3]) nri = self.getiter(r, s) self.settimes(nri, wst, tst, ft, doplaces=False) self.placexfer() # re-join any existing timer state -> no, just do a start self.set_syncstart(tod.str2tod(cr.get('race', 'start')), tod.str2tod(cr.get('race', 'lstart')))
def set_finish(self, finish=''): """Set the finish time.""" if type(finish) is tod.tod: self.finish = finish else: self.finish = tod.str2tod(finish) if self.finish is None: if self.start is not None: self.set_running() else: if self.start is None: self.set_start('0')
def msg_cb(self, m): """Handle message packet in main thread.""" redraw = False if m.header == 'rider': self.append_rider(m.text) elif m.header == 'time': self.elap_lbl.set_text(m.text) elif m.header == 'title': self.lbl_header.set_text(m.text) elif m.header == 'start': self.cur_split = tod.str2tod(m.text) elif m.erp: self.clear() return False
def append_rider(self, msg): sr = msg.split(chr(unt4.US)) if len(sr) == 5: rftime = tod.str2tod(sr[4]) if rftime is not None: if len(self.riders) == 0: # Case 1: Starting a new lap self.cur_lap = (rftime - self.cur_split).truncate(0) self.cur_split = rftime.truncate(0) self.cur_bunchid = 0 self.cur_bunchcnt = 1 self.last_time = rftime nr = [ sr[0], sr[1], sr[2], sr[3], self.cur_lap.rawtime(0), self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0], rftime, ] elif rftime < self.last_time or rftime - self.last_time < tod.tod("1.12"): # Case 2: Same bunch self.last_time = rftime self.cur_bunchcnt += 1 nr = [sr[0], sr[1], sr[2], sr[3], "", self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0], rftime] else: # Case 3: New bunch self.riders.append(["", "", "", "", "", "", "#fefefe", None]) self.cur_bunchid = (self.cur_bunchid + 1) % COLOURMAPLEN self.cur_bunchcnt = 1 self.last_time = rftime nr = [ sr[0], sr[1], sr[2], sr[3], "+" + (rftime - self.cur_split).rawtime(0), self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0], rftime, ] else: # Informative non-timeline record nr = [sr[0], sr[1], sr[2], sr[3], "", "", "#fefefe", None] self.riders.append(nr) self.map_redraw() # update src map self.map_area.queue_draw() # queue copy to screen
def msg_cb(self, m): """Handle message packet in main thread.""" redraw = False if m.header == "rider": self.append_rider(m.text) elif m.header == "time": self.elap_lbl.set_text(m.text) elif m.header == "title": self.lbl_header.set_text(m.text) elif m.header == "start": self.cur_split = tod.str2tod(m.text) elif m.erp: self.clear() return False
def append_rider(self, msg): sr = msg.split(chr(unt4.US)) if len(sr) == 5: rftime = tod.str2tod(sr[4]) if rftime is not None: if len(self.riders) == 0: # Case 1: Starting a new lap self.cur_lap = (rftime-self.cur_split).truncate(0) self.cur_split = rftime.truncate(0) self.cur_bunchid = 0 self.cur_bunchcnt = 1 self.last_time = rftime nr=[sr[0],sr[1],sr[2],sr[3], self.cur_lap.rawtime(0), self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0], rftime] elif rftime < self.last_time or rftime - self.last_time < tod.tod('1.12'): # Case 2: Same bunch self.last_time = rftime self.cur_bunchcnt += 1 nr=[sr[0],sr[1],sr[2],sr[3], '', self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0], rftime] else: # Case 3: New bunch self.riders.append(['','','','','','','#fefefe',None]) self.cur_bunchid = (self.cur_bunchid + 1)%COLOURMAPLEN self.cur_bunchcnt = 1 self.last_time = rftime nr=[sr[0],sr[1],sr[2],sr[3], '+' + (rftime - self.cur_split).rawtime(0), self.cur_bunchcnt, COLOURMAP[self.cur_bunchid][0], rftime] else: # Informative non-timeline record nr=[sr[0],sr[1],sr[2],sr[3], '', '', '#fefefe',None] self.riders.append(nr) self.map_redraw() # update src map self.map_area.queue_draw() # queue copy to screen