Exemple #1
0
	def OnPopupAddMissingLastLap( self, event ):
		if not self.entry:
			return
		num = self.entry.num
			
		race = Model.race
		if not race or num not in race.riders:
			return
			
		rider = race.riders[num]
			
		times = [t for t in rider.times]
		if len(times) < 2:
			return
			
		if rider.status != rider.Finisher:
			Utils.MessageOK( self, _('Cannot add Last Lap unless Rider is Finisher'), _('Cannot add Last Lap') )
			return
				
		undo.pushState()
		if rider.autocorrectLaps:
			if Utils.MessageOKCancel( self, _('Turn off Autocorrect first?'), _('Turn off Autocorrect') ):
				rider.autocorrectLaps = False
				
		waveCategory = race.getCategory( num )
		if waveCategory:
			times[0] = waveCategory.getStartOffsetSecs()
		tNewLast = times[-1] + times[-1] - times[-2]
				
		race.numTimeInfo.add( num, tNewLast )
		race.addTime( num, tNewLast )
		race.setChanged()
		
		wx.CallAfter( self.refresh )
Exemple #2
0
	def commitChange( self ):
		num = self.num.GetValue()
		status = self.statusOption.GetSelection()
		relegatedPosition = self.relegatedPosition.GetValue()
		
		wx.CallAfter( Utils.refreshForecastHistory )
		
		undo.pushState();
		with Model.LockRace() as race:
			# Allow new numbers to be added if status is DNS, DNF or DQ.
			if race is None or (num not in race.riders and status not in [Model.Rider.DNS, Model.Rider.DNF, Model.Rider.DQ]):
				return
				
			rider = race.getRider(num)
			oldValues = (rider.status, rider.tStatus, rider.relegatedPosition)

			tStatus = None
			if status not in [Model.Rider.Finisher, Model.Rider.DNS, Model.Rider.DQ]:
				tStatus = Utils.StrToSeconds( self.atRaceTime.GetValue() )
			
			rider.setStatus( status, tStatus )
			rider.relegatedPosition = relegatedPosition

			newValues = (rider.status, rider.tStatus, rider.relegatedPosition)
			if oldValues != newValues:
				race.setChanged()
				wx.CallAfter( Utils.refresh )
Exemple #3
0
	def onOK( self, event ):
		race = Model.race
		if not race or not race.startTime:
			return
			
		secondsNew = self.timeMsEdit.GetSeconds()
		secondsOld = (race.startTime - race.startTime.replace(hour=0, minute=0, second=0)).total_seconds()
		dTime = secondsNew - secondsOld
		
		if dTime == 0:
			return
		
		if dTime > 0.0 and not Utils.MessageOKCancel( self,
				_('Are you Sure you want to change the Race Start to Later?\n(you can always undo).'), _('Are you sure?') ):
			return
		
		undo.pushState()
		for rider in race.riders.itervalues():
			if getattr(rider, 'firstTime', None) is not None:
				rider.firstTime -= dTime
		
			# Adjust all the recorded times to account for the new start time.
			for k in xrange(len(rider.times)):
				rider.times[k] -= dTime
		
		race.numTimeInfo.adjustAllTimes( -dTime )
		race.startTime += datetime.timedelta( seconds = dTime )
		race.setChanged()
		Utils.refresh()
		
		self.EndModal( wx.ID_OK )
Exemple #4
0
def StartRaceNow():
	global undoResetTimer
	if undoResetTimer and undoResetTimer.IsRunning():
		undoResetTimer.Stop()
	undoResetTimer = None
	JChip.reset()
	
	undo.clear()
	undo.pushState()
	with Model.LockRace() as race:
		if race is None:
			return
		
		if not getattr(race, 'enableJChipIntegration', False):
			race.resetStartClockOnFirstTag = False
		Model.resetCache()
		race.startRaceNow()
		
	OutputStreamer.writeRaceStart()
	VideoBuffer.ModelStartCamera()
	
	# Refresh the main window and switch to the Record pane.
	mainWin = Utils.getMainWin()
	if mainWin is not None:
		mainWin.showPageName( _('Record') )
		mainWin.refresh()
	
	# For safety, clear the undo stack after 8 seconds.
	undoResetTimer = wx.CallLater( 8000, undo.clear )
	
	if getattr(race, 'ftpUploadDuringRace', False):
		realTimeFtpPublish.publishEntry( True )
Exemple #5
0
	def onSetDNS( self, evt ):
		if not self.list.GetItemCount() or not Model.race:
			return
		
		nums = [int(self.list.GetItem(i, 0).GetText()) for i in Utils.GetListCtrlSelectedItems(self.list)]
		
		if not nums:
			Utils.MessageOK( self, _('No entrants selected to DNS'), _('No entrants selected to DNS') )
			return
		
		lines = []
		for i in range( 0, len(nums), 10 ):
			lines.append( ', '.join( '{}'.format(n) for n in itertools.islice( nums, i, min(i+10, len(nums)) ) ) )
		message = u'{}\n\n{}'.format(_('DNS the following entrants?'), u',\n'.join(lines))
			
		if not Utils.MessageOKCancel( self, message, _('DNS Entrants') ):
			return
		
		undo.pushState()
		DNS = Model.Rider.DNS
		with Model.LockRace() as race:
			for n in nums:
				if n > 0:
					race.getRider(n).status = DNS
			race.setChanged()
			race.resetAllCaches()
		
		wx.CallAfter( self.refresh )
		wx.CallAfter( Utils.refresh )
		wx.CallAfter( self.list.SetFocus )
Exemple #6
0
	def OnPopupNote( self, event ):
		self.grid.SelectRow( self.eventRow )
		try:
			num = int(self.num.GetValue())
		except:
			return
			
		if not Model.race or num not in Model.race:
			return
			
		lap = self.eventRow + 1
		race = Model.race
		rider = race.riders[num]
			
		race.lapNote = getattr(race, 'lapNote', {})
		dlg = wx.TextEntryDialog( self, u'{}: {}: {}: {}'.format(_("Bib"), num, _("Note on Lap"), lap), _("Lap Note"),
					Model.race.lapNote.get( (num, lap), '' ) )
		ret = dlg.ShowModal()
		value = dlg.GetValue().strip()
		dlg.Destroy()
		if ret != wx.ID_OK:
			return
		
		undo.pushState()
		if value:
			race.lapNote[(self.entry.num, self.entry.lap)] = value
			race.setChanged()
		else:
			try:
				del race.lapNote[(self.entry.num, self.entry.lap)]
				race.setChanged()
			except KeyError:
				pass
		wx.CallAfter( self.refresh )
Exemple #7
0
def AddLapSplits( num, lap, times, splits ):
	undo.pushState()
	with Model.LockRace() as race:
		rider = race.riders[num]
		try:
			tLeft = times[lap-1]
			tRight = times[lap]
			
			# Split the first lap time to the same ratio as the distances.
			category = race.getCategory( num )
			if (	lap == 1 and
					category is not None and
					category.distanceType == category.DistanceByLap and
					category.distance and category.firstLapDistance and
					category.distance != category.firstLapDistance
				):
				flr = float(category.firstLapDistance) / float(category.distance)
				splitTime = (tRight - tLeft) / (flr + (splits-1))
				firstLapSplitTime = splitTime * flr
			else:
				splitTime = firstLapSplitTime = (tRight - tLeft) / float(splits)
			
			newTime = tLeft
			for i in range( 1, splits ):
				newTime += (firstLapSplitTime if i == 1 else splitTime)
				race.numTimeInfo.add( num, newTime, Model.NumTimeInfo.Split )
				race.addTime( num, newTime + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0) )
			return True
		except (TypeError, KeyError, ValueError, IndexError) as e:
			Utils.logException( e, sys.exc_info() )
			return False
Exemple #8
0
    def OnPopupPull(self, event):
        if not hasattr(self, 'rowPopup'):
            return

        entry = self.history[self.colPopup][self.rowPopup]

        if not entry:
            return
        if not Utils.MessageOKCancel(
                self, u'{}: {}  {} {} - {}?'.format(
                    _('Bib'),
                    entry.num,
                    _('Pull after lap'),
                    entry.lap,
                    Utils.formatTime(entry.t + 1, True),
                ), _('Pull Rider')):
            return
        try:
            undo.pushState()
            race = Model.race
            race.getRider(entry.num).setStatus(Model.Rider.Pulled, entry.t + 1)
            race.setChanged()
        except Exception as e:
            Utils.logException(e, sys.exc_info())
        wx.CallAfter(self.refresh)
        wx.CallAfter(Utils.refreshForecastHistory)
Exemple #9
0
	def update( self, race = None ):
		undo.pushState()
		with Model.lock:
			if race is None:
				race = Model.getRace()
			if race is None:
				return
			race.name = self.raceName.GetValue().strip()
			race.city = self.raceCity.GetValue().strip()
			race.stateProv = self.raceStateProv.GetValue().strip()
			race.country = self.raceCountry.GetValue().strip()
			race.discipline = self.raceDiscipline.GetValue().strip()
			race.organizer = self.organizer.GetValue().strip()
			race.date = self.date.GetValue().Format(Properties.dateFormat)
			race.raceNum = self.raceNum.GetValue()
			race.scheduledStart = self.scheduledStart.GetValue()
			race.allCategoriesFinishAfterFastestRidersLastLap = self.allCategoriesFinishAfterFastestRidersLastLap.IsChecked()
			race.isTimeTrial = self.timeTrial.IsChecked()
			race.enableJChipIntegration = self.jchip.IsChecked()
			race.autocorrectLapsDefault = self.autocorrectLapsDefault.IsChecked()
			race.highPrecisionTimes = self.highPrecisionTimes.IsChecked()
			race.distanceUnit = self.distanceUnit.GetSelection()
			race.reverseDirection = self.reverseDirection.IsChecked()
			race.enableUSBCamera = self.enableUSBCamera.IsChecked()
			race.finishTop = self.finishTop.IsChecked()
			race.minutes = self.minutes.GetValue()
			race.commissaire = self.commissaire.GetValue().strip()
			race.memo = self.memo.GetValue().strip()
			race.notes = self.notes.GetValue().strip()
			race.setChanged()
			
		if Utils.getMainWin():
			Utils.getMainWin().record.setTimeTrialInput( race.isTimeTrial )
Exemple #10
0
def AddLapSplits(num, lap, times, splits):
    undo.pushState()
    with Model.LockRace() as race:
        rider = race.riders[num]
        try:
            tLeft = times[lap - 1]
            tRight = times[lap]

            # Split the first lap time to the same ratio as the distances.
            category = race.getCategory(num)
            if (lap == 1 and category is not None
                    and category.distanceType == category.DistanceByLap
                    and category.distance and category.firstLapDistance
                    and category.distance != category.firstLapDistance):
                flr = float(category.firstLapDistance) / float(
                    category.distance)
                splitTime = (tRight - tLeft) / (flr + (splits - 1))
                firstLapSplitTime = splitTime * flr
            else:
                splitTime = firstLapSplitTime = (tRight -
                                                 tLeft) / float(splits)

            newTime = tLeft
            for i in xrange(1, splits):
                newTime += (firstLapSplitTime if i == 1 else splitTime)
                race.numTimeInfo.add(num, newTime, Model.NumTimeInfo.Split)
                race.addTime(
                    num, newTime +
                    ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0))
            return True
        except (TypeError, KeyError, ValueError, IndexError) as e:
            Utils.logException(e, sys.exc_info())
            return False
Exemple #11
0
    def OnPopupDNF(self, event):
        if not hasattr(self, 'rowPopup'):
            return

        entry = self.history[self.colPopup][self.rowPopup]

        if not Utils.MessageOKCancel(
                self, u'{}: {}  {} {} - {}?'.format(
                    _('Bib'),
                    entry.num,
                    _('DNF after lap'),
                    entry.lap,
                    Utils.formatTime(entry.t + 1, True),
                ), _('DNF Rider')):
            return
        try:
            undo.pushState()
            with Model.LockRace() as race:
                race.getRider(entry.num).setStatus(Model.Rider.DNF,
                                                   entry.t + 1)
                race.setChanged()
        except:
            pass
        wx.CallAfter(self.refresh)
        wx.CallAfter(Utils.refreshForecastHistory)
Exemple #12
0
	def onOK( self, event ):
		stOld, ftOld, laps = getStFtLaps(self.rider)
		st, ft = self.startTime.GetSeconds(), self.finishTime.GetSeconds()
		if st is not None and ft is not None and st >= ft:
			Utils.MessageOK( self, _('Start Time must be before Finish Time'), _('Time Error'), wx.ICON_ERROR )
			return
			
		if stOld == st and ftOld == ft:
			Utils.refresh()
			self.EndModal( wx.ID_OK )
			return
		
		undo.pushState()
		self.rider.firstTime = st
		self.rider.ttPenalty = self.penaltyTime.GetSeconds()
		self.rider.ttNote = self.note.GetValue()
		if st and ft:
			rt = ft - st
			if not self.rider.times:
				self.rider.addTime( rt )
			elif len(self.rider.times) == 2:
				self.rider.times[1] = rt
			else:
				self.rider.times = [t for t in self.rider.times if t < rt]
				self.rider.times.append( rt )
		elif st:
			self.rider.firstTime = st
			
		Model.race.setChanged()
		Utils.refresh()
		self.EndModal( wx.ID_OK )
Exemple #13
0
def DeleteEntry(parent, entry):
    if entry.lap == 0:
        return

    race = Model.race
    raceStartTimeOfDay = Utils.StrToSeconds(
        race.startTime.strftime(
            '%H:%M:%S.%f')) if race and race.startTime else None

    dlg = wx.MessageDialog(
        parent, u'{}: {}\n{}: {}\n{}: {}\n{}: {}\n\n{}?'.format(
            _('Bib'), entry.num, _('Lap'), entry.lap, _('Race Time'),
            Utils.formatTime(entry.t, True), _('Clock Time'),
            Utils.formatTime(entry.t + raceStartTimeOfDay, True)
            if raceStartTimeOfDay is not None else u'', _('Confirm Delete')),
        _('Delete Entry'), wx.OK | wx.CANCEL | wx.ICON_QUESTION)
    # dlg.CentreOnParent(wx.BOTH)
    if dlg.ShowModal() == wx.ID_OK:
        undo.pushState()
        with Model.LockRace() as race:
            if race:
                race.numTimeInfo.delete(entry.num, entry.t)
                race.deleteTime(entry.num, entry.t)
        Utils.refresh()
    dlg.Destroy()
Exemple #14
0
	def OnPopupAddMissingLastLap( self, event ):
		if not self.entry:
			return
		num = self.entry.num
			
		race = Model.race
		if not race or num not in race:
			return
			
		rider = race.riders[num]
			
		times = [t for t in rider.times]
		if len(times) < 2:
			return
			
		if rider.status != rider.Finisher:
			Utils.MessageOK( self, _('Cannot add Last Lap unless Rider is Finisher'), _('Cannot add Last Lap') )
			return
				
		undo.pushState()
		if rider.autocorrectLaps:
			if Utils.MessageOKCancel( self, _('Turn off Autocorrect first?'), _('Turn off Autocorrect') ):
				rider.autocorrectLaps = False
				
		waveCategory = race.getCategory( num )
		if waveCategory:
			times[0] = waveCategory.getStartOffsetSecs()
		tNewLast = times[-1] + times[-1] - times[-2]
				
		race.numTimeInfo.add( num, tNewLast )
		race.addTime( num, tNewLast )
		race.setChanged()
		
		wx.CallAfter( self.refresh )
Exemple #15
0
	def onSetDNS( self, evt ):
		if not self.list.GetItemCount() or not Model.race:
			return
		
		# Get all selected items.
		nums = [self.list.GetItemData(row) for row in xrange(self.list.GetItemCount())
						if self.list.GetItem(row).m_state & wx.LIST_STATE_SELECTED]
		
		if not nums:
			Utils.MessageOK( self, _('No entrants selected to DNS'), _('No entrants selected to DNS') )
			return
		
		lines = []
		for i in xrange( 0, len(nums), 10 ):
			lines.append( ', '.join( '{}'.format(n) for n in itertools.islice( nums, i, min(i+10, len(nums)) ) ) )
		message = _('DNS the following entrants?\n\n{}').format(',\n'.join(lines))
			
		if not Utils.MessageOKCancel( self, message, _('DNS Entrants') ):
			return
		
		undo.pushState()
		with Model.LockRace() as race:
			for n in nums:
				rider = race.getRider( n )
				rider.status = rider.DNS
			race.setChanged()
		
		wx.CallAfter( self.refresh )
		wx.CallAfter( Utils.refresh )
		wx.CallAfter( self.list.SetFocus )
Exemple #16
0
    def OnPopupDNF(self, event):
        if self.numSelect is None or not Model.race:
            return
        rider = Model.race.riders.get(self.numSelect, None)
        if rider is None:
            return
        t = rider.getLastKnownTime() + 1
        if not Utils.MessageOKCancel(
                self, u'{}: {}  {} {}?'.format(
                    _('Bib'),
                    self.numSelect,
                    _('DNF at '),
                    Utils.formatTime(t, True),
                ), _('DNF Rider')):
            return
        try:
            undo.pushState()
            with Model.LockRace() as race:
                rider.setStatus(Model.Rider.DNF, t)
                race.setChanged()
        except Exception as e:
            Utils.logException(e, sys.exc_info())

        self.list.Delete(self.item)
        wx.CallAfter(Utils.refresh)
        wx.CallAfter(Utils.refreshForecastHistory)
Exemple #17
0
	def OnPopupLapNote( self, event ):
		if not self.entry or not Model.race:
			return
		Model.race.lapNote = getattr(Model.race, 'lapNote', {})
		dlg = wx.TextEntryDialog( self, u"{} {}: {} {}: {}:".format(
						_('Bib'), self.entry.num, _('Lap'), self.entry.lap, _('Note'), 
					), _("Lap Note"),
					Model.race.lapNote.get( (self.entry.num, self.entry.lap), '' ) )
		ret = dlg.ShowModal()
		value = dlg.GetValue().strip()
		dlg.Destroy()
		if ret != wx.ID_OK:
			return
		undo.pushState()
		with Model.LockRace() as race:
			if value:
				race.lapNote[(self.entry.num, self.entry.lap)] = value
				race.setChanged()
			else:
				try:
					del race.lapNote[(self.entry.num, self.entry.lap)]
					race.setChanged()
				except KeyError:
					pass
		wx.CallAfter( self.refresh )
Exemple #18
0
    def onOK(self, event):
        num1 = self.numEdit1.GetValue()
        num2 = self.numEdit2.GetValue()
        if not num1 or not num2 or num1 == num2:
            return

        t1 = self.entry.t
        t2 = self.entry.t + 0.0001 * random.random()

        undo.pushState()
        with Model.LockRace() as race:
            rider = race.getRider(self.entry.num)

            race.numTimeInfo.delete(self.entry.num, self.entry.t)
            race.numTimeInfo.add(num1, t1)
            race.numTimeInfo.add(num2, t2)

            race.deleteTime(self.entry.num, self.entry.t)
            race.addTime(
                num1,
                t1 + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0))
            race.addTime(
                num2,
                t2 + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0))

        Utils.refresh()

        self.EndModal(wx.ID_OK)
Exemple #19
0
	def OnPopupDelete( self, event ):
		rows = Utils.GetSelectedRows( self.grid )
		
		try:
			self.visibleRow = min( rows )
		except:
			self.visibleRow = None
			
		if len(rows) > 1:
			try:
				num = int(self.num.GetValue())
			except:
				return
			if not Model.race or num not in Model.race:
				return
			rider = Model.race[num]
			times = [rider.times[r] for r in rows]
			timeStr = []
			timesPerRow = 4
			for i in xrange(0, len(times), timesPerRow):
				timeStr.append(
					',  '.join( _('Lap {}: {}').format(rows[j]+1, Utils.formatTime(times[i]))
							for j in xrange(i, min(len(times), i+timesPerRow) ) ) )
			timeStr = ',\n'.join( timeStr )
			message = _('Delete entries of Rider {}:\n\n{}\n\nConfirm Delete?').format(num, timeStr)
			if Utils.MessageOKCancel( self, message, _('Delete Times'), wx.ICON_WARNING ):
				undo.pushState()
				with Model.LockRace() as race:
					if race:
						for t in times:
							race.deleteTime( num, t )
				wx.CallAfter( self.refresh )
		else:
			self.grid.SelectRow( self.eventRow )
			DeleteEntry( self, self.entry )
Exemple #20
0
	def onSetDNS( self, evt ):
		if not self.list.GetItemCount() or not Model.race:
			return
		
		nums = [int(self.list.GetItem(i, 0).GetText()) for i in Utils.GetListCtrlSelectedItems(self.list)]
		
		if not nums:
			Utils.MessageOK( self, _('No entrants selected to DNS'), _('No entrants selected to DNS') )
			return
		
		lines = []
		for i in xrange( 0, len(nums), 10 ):
			lines.append( ', '.join( '{}'.format(n) for n in itertools.islice( nums, i, min(i+10, len(nums)) ) ) )
		message = u'{}\n\n{}'.format(_('DNS the following entrants?'), u',\n'.join(lines))
			
		if not Utils.MessageOKCancel( self, message, _('DNS Entrants') ):
			return
		
		undo.pushState()
		DNS = Model.Rider.DNS
		with Model.LockRace() as race:
			for n in nums:
				if n > 0:
					race.getRider(n).status = DNS
			race.setChanged()
			race.resetAllCaches()
		
		wx.CallAfter( self.refresh )
		wx.CallAfter( Utils.refresh )
		wx.CallAfter( self.list.SetFocus )
Exemple #21
0
	def onOK( self, event ):
		num = self.numEdit.GetValue()
		t = self.timeMsEdit.GetSeconds()
		
		if self.timeChoice.GetSelection() == 1 and Model.race and Model.race.startTime:
			dtStart = Model.race.startTime
			dtInput = datetime.datetime(dtStart.year, dtStart.month, dtStart.day) + datetime.timedelta(seconds = t)
			if dtInput < dtStart:
				Utils.MessageOK( self, _('Cannot Enter Clock Time Before Race Start.\n\n(reminder: clock time is in 24-hour format)'),
										_('Time Entry Error'), iconMask = wx.ICON_ERROR )
				return
			t = (dtInput - dtStart).total_seconds()
			
		if self.entry.num != num or self.entry.t != t:
			undo.pushState()
			with Model.LockRace() as race:
				rider = race.getRider( num )
				if self.entry.lap != 0:
					race.numTimeInfo.change( self.entry.num, self.entry.t, t )
					race.deleteTime( self.entry.num, self.entry.t )
					race.addTime( num, t + (rider.firstTime if getattr(race, 'isTimeTrial', False) and getattr(rider, 'firstTime', None) is not None else 0.0) )
				else:
					race.numTimeInfo.change( self.entry.num, rider.firstTime, t )
					rider.firstTime = t
					race.setChanged()
			Utils.refresh()
		self.EndModal( wx.ID_OK )
Exemple #22
0
	def onUpdateStartWaveNumbers( self, event ):
		self.commit()
		undo.pushState()
		with Model.LockRace() as race:
			race.adjustAllCategoryWaveNumbers()
		wx.CallAfter( self.refresh )
		wx.CallAfter( Utils.refreshForecastHistory )
Exemple #23
0
 def OnPopupLapNote(self, event):
     if not self.entry or not Model.race:
         return
     Model.race.lapNote = getattr(Model.race, 'lapNote', {})
     dlg = wx.TextEntryDialog(
         self, u"{} {}: {} {}: {}:".format(
             _('Bib'),
             self.entry.num,
             _('Lap'),
             self.entry.lap,
             _('Note'),
         ), _("Lap Note"),
         Model.race.lapNote.get((self.entry.num, self.entry.lap), ''))
     ret = dlg.ShowModal()
     value = dlg.GetValue().strip()
     dlg.Destroy()
     if ret != wx.ID_OK:
         return
     undo.pushState()
     with Model.LockRace() as race:
         if value:
             race.lapNote[(self.entry.num, self.entry.lap)] = value
             race.setChanged()
         else:
             try:
                 del race.lapNote[(self.entry.num, self.entry.lap)]
                 race.setChanged()
             except KeyError:
                 pass
     wx.CallAfter(self.refresh)
Exemple #24
0
 def onUpdateStartWaveNumbers(self, event):
     self.commit()
     undo.pushState()
     with Model.LockRace() as race:
         race.adjustAllCategoryWaveNumbers()
     self.state.reset()
     wx.CallAfter(self.refresh)
     wx.CallAfter(Utils.refreshForecastHistory)
def DoImportTTStartTimes( race, excelLink ):
	if not excelLink:
		return ['Missing excelLink']
		
	info = excelLink.read()
	
	startTimes = {}
	errors = []
	for num, data in info.iteritems():
		try:
			startTime = data['StartTime']
		except KeyError:
			errors.append( u'{} {}: {}'.format(_('Bib'), num, _('missing start time')) )
			continue
			
		# Try to make sense of the StartTime (Stopwatch time, not clock time).
		if isinstance(startTime, float):
			t = startTime * 24.0*60.0*60.0	# Excel decimal days.
		elif isinstance(startTime, (str, unicode)):
			# Otherwise, string of format hh:mm:ss.ddd or mm:ss.ddd.
			fields = startTime.split( ':' )
			try:
				hh, mm, ss = [float(f.strip()) for f in fields[:3]]
			except:
				try:
					hh = 0.0
					mm, ss = [float(f.strip()) for f in fields[:2]]
				except:
					errors.append( u'{} {}:  {}: "{}"'.format(_('Bib'), num, _('cannot read time format'), startTime) )
					continue
			t = hh * 60.0*60.0 + mm * 60.0 + ss
		else:
			errors.append( u'{} {}:  {}'.format(_('Bib'), num, _('cannot read start time (neither Excel time nor String)') ) )
			continue
			
		startTimes[num] = t
			
	if startTimes:
		undo.pushState()
		for num, t in startTimes.iteritems():
			rider = race.getRider( num )
			
			# Compute the time change difference.
			try:
				dTime = getattr(rider, 'firstTime', t) - t
			except TypeError:
				dTime = 0.0
				
			rider.firstTime = t
			
			# Adjust the lap times to account for the new start time.
			for k in xrange(len(rider.times)):
				if k != 0:
					rider.times[k] += dTime
		
		race.setChanged()
		
	return errors
Exemple #26
0
    def OnPopupMassPull(self, event):
        if not self.entry:
            return
        if not Utils.MessageOKCancel(
                self, u'{} {}: {} {}, {}.\n{} {}.\n\n{}?'.format(
                    _('Bib'),
                    self.entry.num,
                    _('Pull Rider after lap'),
                    self.entry.lap,
                    Utils.formatTime(self.entry.t + 1, True),
                    _('And, Pull all riders ranked lower after lap'),
                    self.entry.lap,
                    _('Continue'),
                ), _('Mass Pull')):
            return

        try:
            undo.pushState()
            with Model.LockRace() as race:
                if not race:
                    return

                category = race.getCategory(self.entry.num)
                if not category:
                    Utils.MessageOK(
                        self,
                        _('Cannot apply Mass Pull to rider with unknown category.'
                          ),
                        _('Unknown Category'),
                        wx.ICON_ERROR,
                    )
                    return

                results = GetResults(category)

                toPull = []
                Finisher, Pulled = Model.Rider.Finisher, Model.Rider.Pulled
                found = False
                for rr in results:
                    if not found:
                        found = (rr.num == self.entry.num)
                    if found and rr.status == Finisher and rr.raceTimes:
                        toPull.append(rr)

                tSearch = self.entry.t
                for rr in toPull:
                    i = bisect_right(rr.raceTimes, tSearch)
                    try:
                        race.getRider(rr.num).setStatus(
                            Pulled, rr.raceTimes[i] + 1)
                    except IndexError:
                        pass

                race.setChanged()
                wx.CallAfter(self.refresh)

        except Exception as e:
            pass
Exemple #27
0
	def onOK( self, event ):
		fname = self.chipDataFile.GetValue()
		try:
			with open(fname) as f:
				pass
		except IOError:
			Utils.MessageOK( self, u'{}:\n\n"{}"'.format(_('Could not open data file for import'), fname),
									title = _('Cannot Open File'), iconMask = wx.ICON_ERROR)
			return
			
		clearExistingData = (self.importPolicy.GetSelection() == 0)
		timeAdjustment = self.timeAdjustment.GetSeconds()
		if self.behindAhead.GetSelection() == 1:
			timeAdjustment *= -1
		
		# Get the start time.
		if not clearExistingData:
			if not Model.race or not Model.race.startTime:
				Utils.MessageOK( self,
					u'\n\n'.join( [_('Cannot Merge into Unstarted Race.'), _('Clear All Existing Data is allowed.')] ),
					title = _('Import Merge Failed'), iconMask = wx.ICON_ERROR
				)
				return
			startTime = Model.race.startTime.time()
		else:
			if self.manualStartTime.IsChecked():
				startTime = datetime.time(*[int(x) for x in self.raceStartTime.GetValue().split(':')])
			else:
				startTime = None
			
		undo.pushState()
		errors = DoChipImport(	fname, self.parseTagTime, startTime,
								clearExistingData,
								datetime.timedelta(seconds = timeAdjustment) )
		
		if errors:
			# Copy the tags to the clipboard.
			clipboard = wx.Clipboard.Get()
			if not clipboard.IsOpened():
				clipboard.Open()
				clipboard.SetData( wx.TextDataObject('\n'.join(errors)) )
				clipboard.Close()
			
			if len(errors) > 10:
				errors = errors[:10]
				errors.append( '...' )
			tagStr = '\n'.join(errors)
			Utils.MessageOK( self,
							u'{}:\n\n{}\n\n{}.'.format(_('Import File contains errors'), tagStr, _('All errors have been copied to the clipboard')),
							_('Import Warning'),
							iconMask = wx.ICON_WARNING )
		else:
			Utils.MessageOK( self, _('Import Successful'), _('Import Successful') )
		wx.CallAfter( Utils.refresh )
		self.EndModal( wx.ID_OK )
Exemple #28
0
	def onOK( self, event ):
		fname = self.chipDataFile.GetValue()
		try:
			with open(fname) as f:
				pass
		except IOError:
			Utils.MessageOK( self, u'{}:\n\n"{}"'.format(_('Could not open data file for import'), fname),
									title = _('Cannot Open File'), iconMask = wx.ICON_ERROR)
			return
			
		clearExistingData = (self.importPolicy.GetSelection() == 0)
		timeAdjustment = self.timeAdjustment.GetSeconds()
		if self.behindAhead.GetSelection() == 1:
			timeAdjustment *= -1
		
		# Get the start time.
		if not clearExistingData:
			if not Model.race or not Model.race.startTime:
				Utils.MessageOK( self,
					u'\n\n'.join( [_('Cannot Merge into Unstarted Race.'), _('Clear All Existing Data is allowed.')] ),
					title = _('Import Merge Failed'), iconMask = wx.ICON_ERROR
				)
				return
			startTime = Model.race.startTime.time()
		else:
			if self.manualStartTime.IsChecked():
				startTime = datetime.time(*[int(x) for x in self.raceStartTime.GetValue().split(':')])
			else:
				startTime = None
			
		undo.pushState()
		errors = DoChipImport(	fname, self.parseTagTime, startTime,
								clearExistingData,
								datetime.timedelta(seconds = timeAdjustment) )
		
		if errors:
			# Copy the tags to the clipboard.
			clipboard = wx.Clipboard.Get()
			if not clipboard.IsOpened():
				clipboard.Open()
				clipboard.SetData( wx.TextDataObject('\n'.join(errors)) )
				clipboard.Close()
			
			if len(errors) > 10:
				errors = errors[:10]
				errors.append( '...' )
			tagStr = '\n'.join(errors)
			Utils.MessageOK( self,
							u'{}:\n\n{}\n\n{}.'.format(_('Import File contains errors'), tagStr, _('All errors have been copied to the clipboard')),
							_('Import Warning'),
							iconMask = wx.ICON_WARNING )
		else:
			Utils.MessageOK( self, _('Import Successful'), _('Import Successful') )
		wx.CallAfter( Utils.refresh )
		self.EndModal( wx.ID_OK )
Exemple #29
0
	def doCommit( self ):
		undo.pushState()
		with Model.LockRace() as race:
			if race is None:
				return
			for prop, PropClass, name in self.propClassName:
				getattr(self, prop).commit()
			race.setChanged()
			
		if Utils.getMainWin():
			Utils.getMainWin().record.setTimeTrialInput( race.isTimeTrial )
Exemple #30
0
	def onCopyRider( self, event ):
		if not Model.race:
			return
			
		try:
			num = int(self.num.GetValue())
		except:
			return
			
		with Model.LockRace() as race:
			if not num in race:
				return
		
		dlg = wx.TextEntryDialog( self, _("All time entries for {} will be copied to the new bib number.\n\nNew Bib Number:").format(num),
								_('Copy Rider Times'), '{}'.format(self.num.GetValue()) )
		ret = dlg.ShowModal()
		newNum = dlg.GetValue()
		dlg.Destroy()
		if ret != wx.ID_OK:
			return
			
		try:
			newNum = int(re.sub( '[^0-9]', '', newNum))
		except ValueError:
			return
			
		with Model.LockRace() as race:
			inRace = (newNum in race)
		if inRace:
			if num != newNum:
				Utils.MessageOK( self, _("New Bib {} already exists.\nIf you really want to copy times to this number, delete it first.").format(newNum),
								_('New Bib Number Already Exists'), iconMask = wx.ICON_ERROR )
			else:
				Utils.MessageOK( self, _("Cannot copy to the same number ({}).").format(newNum),
								
								_('Cannot Copy to Same Number'), iconMask = wx.ICON_ERROR )
			return
			
		if Utils.MessageOKCancel( self,
				_("Entries from {} will be copied to new Bib {}.\n\nAll entries for {} will be slightly earlier then entries for {}.\nContinue?").format(
					num, newNum, newNum, num),
				_("Confirm Copy Rider Times") ):
			undo.pushState()
			with Model.LockRace() as race:
				race.copyRiderTimes( num, newNum )
				rNew = race.getRider( newNum )
				numTimeInfo = race.numTimeInfo
				for t in rNew.times:
					numTimeInfo.add( newNum, t )
			self.setRider( newNum )
			self.onNumChange()
			wx.CallAfter( Utils.refreshForecastHistory )
			wx.CallAfter( Utils.refresh )
Exemple #31
0
def DoStatusChange( parent, num, message, title, newStatus ):
	if num is None or not Utils.MessageOKCancel(parent, message.format(num), title):
		return False
	undo.pushState()
	with Model.LockRace() as race:
		if not race:
			return False
		rider = race.getRider( num )
		rider.setStatus( newStatus )
		race.setChanged()
	Utils.refresh()
	return True
Exemple #32
0
	def onAutocorrectLaps( self, event ):
		num = self.num.GetValue()
		if not Model.race or num not in Model.race:
			self.autocorrectLaps.SetValue( True )
			return
		undo.pushState()
		with Model.LockRace() as race:
			rider = race.riders[num]
			rider.autocorrectLaps = self.autocorrectLaps.GetValue()
			race.setChanged()
		self.refresh()
		wx.CallAfter( Utils.refreshForecastHistory )
		wx.CallAfter( Utils.refresh )
    def onOK(self, event):
        race = Model.race
        if not race:
            return
        if race.isTimeTrial and race.hasRiderTimes():
            Utils.MessageOKCancel(
                self,
                _('Cannot change Time Trial Start Time') + u'\n\n' +
                _('There are already recorded results.'),
                _('Cannot change Start Time'))
            self.EndModal(wx.ID_OK)

        tOld = race.startTime
        startTimeNew = tOld.replace(hour=0, minute=0, second=0,
                                    microsecond=0) + datetime.timedelta(
                                        seconds=self.timeMsEdit.GetSeconds())
        dTime = (startTimeNew - race.startTime).total_seconds()

        if not dTime:
            return

        if dTime > 0.0 and not Utils.MessageOKCancel(
                self,
                _('Are you Sure you want to change the Race Start to Later?') +
                u'\n' + _('(you can always undo).'), _('Are you sure?')):
            return

        undo.pushState()

        # Adjust all rider times to account for the new start time.
        if not race.isTimeTrial:
            for rider in race.riders.values():
                try:
                    rider.firstTime = max(0.0, rider.firstTime - dTime)
                except TypeError:
                    pass
                rider.times[:] = [max(0.0, v - dTime) for v in rider.times]

            race.numTimeInfo.adjustAllTimes(-dTime)

            # Also fix any unread tags.
            if race.unmatchedTags:
                for times in race.unmatchedTags.values():
                    times[:] = [max(0.0, v - dTime) for v in times]

        race.startTime = startTimeNew
        race.setChanged()
        Utils.refresh()

        self.EndModal(wx.ID_OK)
Exemple #34
0
	def OnPopupSwapAfter( self, event ):
		if not hasattr(self, 'rowPopup'):
			return
		c, r, h = self.colPopup, self.rowPopup, self.history
		success = False
		undo.pushState()
		with Model.LockRace() as race:
			for rNext in xrange( r + 1, len(h[c]) ):
				if not h[c][rNext].interp and (self.category is None or race.inCategory(h[c][rNext].num, self.category)):
					EditEntry.SwapEntry( h[c][r], h[c][rNext] )
					success = True
					break
		if success and Utils.isMainWin():
			Utils.getMainWin().refresh()
Exemple #35
0
def AddLapSplits( num, lap, times, splits ):
	undo.pushState()
	with Model.LockRace() as race:
		try:
			tLeft = times[lap-1]
			tRight = times[lap]
			splitTime = (tRight - tLeft) / float(splits)
			for i in xrange( 1, splits ):
				newTime = tLeft + splitTime * i
				race.numTimeInfo.add( num, newTime, Model.NumTimeInfo.Split )
				race.addTime( num, newTime )
			return True
		except (TypeError, KeyError, ValueError, IndexError):
			return False
Exemple #36
0
	def OnGanttPopupDNF( self, event ):
		if not Utils.MessageOKCancel( self,
			_('DNF Rider {} at {} after lap {}?').format(self.entry.num, Utils.formatTime(self.entry.t+1, True), self.entry.lap),
			_('DNF Rider') ):
			return
		try:
			undo.pushState()
			with Model.LockRace() as race:
				race.getRider(self.entry.num).setStatus( Model.Rider.DNF, self.entry.t + 1 )
				race.setChanged()
		except:
			pass
		wx.CallAfter( self.refresh )
		wx.CallAfter( Utils.refreshForecastHistory )
Exemple #37
0
def DoStatusChange(parent, num, message, title, newStatus, lapTime=None):
    if num is None:
        return False

    race = Model.race
    externalData = []
    try:
        excelLink = race.excelLink
        externalInfo = excelLink.read()
        for f in ['LastName', 'FirstName', 'Team']:
            try:
                externalData.append(unicode(externalInfo[num][f]))
                if f == 'Team':
                    externalData[-1] = u'({})'.format(externalData[-1])
            except KeyError:
                pass
        if len(externalData
               ) == 3:  # Format the team name slightly differently.
            externalData = u'{}: {}'.format(unicode(num), u', '.join(
                externalData[:-1])) + u' ' + externalData[-1]
        else:
            externalData = u'{}: {}'.format(
                unicode(num),
                u', '.join(externalData)) if externalData else None
    except:
        externalData = None

    d = StatusChangeDialog(parent,
                           message=message.format(num),
                           title=title,
                           externalData=externalData,
                           t=lapTime)
    ret = d.ShowModal()
    lapTime = lapTime if d.getSetEntryTime() else None
    d.Destroy()
    if ret != wx.ID_OK:
        return False

    undo.pushState()
    with Model.LockRace() as race:
        if not race:
            return False
        if lapTime:
            race.addTime(num, lapTime)
        rider = race.getRider(num)
        rider.setStatus(newStatus)
        race.setChanged()
    Utils.refresh()
    Utils.refreshForecastHistory()
    return True
Exemple #38
0
	def onCategoryChoice( self, event ):
		if self.num.GetValue() is None:
			return
		num = int(self.num.GetValue())
		catName = self.category.GetStringSelection()
		
		undo.pushState()
		with Model.LockRace() as race:
			if not race:
				return
			for c in race.getCategories( startWaveOnly = False, excludeCustom = True, excludeCombined = True ):
				if c.fullname == catName:
					race.addCategoryException( c, num )
					break
		wx.CallAfter( self.refresh )
Exemple #39
0
	def onOK( self, event ):
		num = self.numEdit.GetValue()
		t = self.timeMsEdit.GetSeconds()
		
		if self.timeChoice.GetSelection() == 1 and Model.race and Model.race.startTime:
			dtStart = Model.race.startTime
			dtInput = datetime.datetime(dtStart.year, dtStart.month, dtStart.day) + datetime.timedelta(seconds = t)
			if dtInput < dtStart:
				Utils.MessageOK( self, u'\n\n'.join( [_('Cannot Enter Clock Time Before Race Start.'), _('(reminder: clock time is in 24-hour format)')] ),
										_('Time Entry Error'), iconMask = wx.ICON_ERROR )
				return
			t = (dtInput - dtStart).total_seconds()

		race = Model.race
		offset = race.getStartOffset( num )
		if t <= offset:
			Utils.MessageOK( self, u'{}: {}\n\n{}\n{}'.format(
				_('Cannot enter a time that is before the Category Start Offset'), Utils.formatTime(offset, highPrecision=True),
				_('All times earlier than the Start Offset are ignored.'),
				_('Please enter a time after the Start Offset.')
				), _('Time Entry Error'), iconMask = wx.ICON_ERROR
			)
			return

		race.lapNote = getattr( race, 'lapNote', {} )
		if self.noteEdit.GetValue() != race.lapNote.get( (self.entry.num, self.entry.lap), u'' ) or self.entry.num != num or self.entry.t != t:
			undo.pushState()
			
			note = self.noteEdit.GetValue().strip()
			if not note:
				race.lapNote.pop( (self.entry.num, self.entry.lap), None )
			else:
				race.lapNote[(self.entry.num, self.entry.lap)] = note
				
			if self.entry.num != num or self.entry.t != t:
				rider = race.getRider( num )
				if self.entry.lap != 0:
					race.numTimeInfo.change( self.entry.num, self.entry.t, t )
					race.deleteTime( self.entry.num, self.entry.t )
					race.addTime( num, t + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0) )
				else:
					race.numTimeInfo.change( self.entry.num, rider.firstTime, t )
					rider.firstTime = t
					
			race.setChanged()
			Utils.refresh()
		
		self.EndModal( wx.ID_OK )
Exemple #40
0
 def OnPopupSwapAfter(self, event):
     if not hasattr(self, 'rowPopup'):
         return
     c, r, h = self.colPopup, self.rowPopup, self.history
     success = False
     undo.pushState()
     with Model.LockRace() as race:
         for rNext in xrange(r + 1, len(h[c])):
             if not h[c][rNext].interp and (
                     self.category is None
                     or race.inCategory(h[c][rNext].num, self.category)):
                 EditEntry.SwapEntry(h[c][r], h[c][rNext])
                 success = True
                 break
     if success and Utils.isMainWin():
         Utils.getMainWin().refresh()
Exemple #41
0
	def onSwapNumber( self, event ):
		if not Model.race:
			return
			
		try:
			num = int(self.num.GetValue())
		except:
			return
			
		with Model.LockRace() as race:
			if not num in race:
				return
		
		dlg = wx.TextEntryDialog( self, _("Number to swap with:"), _('Swap Numbers'), u'{}'.format(self.num.GetValue()) )
		ret = dlg.ShowModal()
		newNum = dlg.GetValue()
		dlg.Destroy()
		if ret != wx.ID_OK:
			return
			
		try:
			newNum = int(re.sub( '[^0-9]', '', newNum))
		except ValueError:
			return
			
		with Model.LockRace() as race:
			inRace = (newNum in race)
		if not inRace:
			Utils.MessageOK(
				self,
				u'{}\n{}'.format(
					_("Cannot swap with specified rider."),
					_("This rider is not in race."),
				),
				_('Cannot Swap Rider Numbers'), iconMask = wx.ICON_ERROR
			)
			return
			
		if Utils.MessageOKCancel( self, u"{}\n\n   {} <==> {}.".format(_('Confirm Swap numbers'), num, newNum), _("Swap Rider Number") ):
			undo.pushState()
			with Model.LockRace() as race:
				race.swapRiders( num, newNum )
				race.numTimeInfo.swapRiders( num, newNum )
			self.setRider( newNum )
			self.refresh()
			wx.CallAfter( Utils.refreshForecastHistory )
			wx.CallAfter( Utils.refresh )
Exemple #42
0
	def OnPopupAutocorrect( self, event ):
		if not self.entry:
			return
		if not Utils.MessageOKCancel( self,
			u'{} {}: {}?'.format(_('Bib'), self.entry.num, _('Turn off Autocorrect')),
			_('Turn off Autocorrect') ):
			return
		try:
			undo.pushState()
			with Model.LockRace() as race:
				if not race:
					return
				race.getRider(self.entry.num).setAutoCorrect( False )
				race.setChanged()
		except:
			pass
		wx.CallAfter( self.refresh )
Exemple #43
0
def DeleteEntry( parent, entry ):
	if entry.lap == 0:
		return
		
	dlg = wx.MessageDialog(parent,
						   _('Num: {}  Lap: {}   RaceTime: {}\n\nConfirm Delete?').format(
								entry.num, entry.lap, Utils.formatTime(entry.t, True)), _('Delete Entry'),
							wx.OK | wx.CANCEL | wx.ICON_QUESTION )
	# dlg.CentreOnParent(wx.BOTH)
	if dlg.ShowModal() == wx.ID_OK:
		undo.pushState()
		with Model.LockRace() as race:
			if race:
				race.numTimeInfo.delete( entry.num, entry.t )
				race.deleteTime( entry.num, entry.t )
		Utils.refresh()
	dlg.Destroy()
Exemple #44
0
	def commit( self ):
		undo.pushState()
		with Model.LockRace() as race:
			self.grid.SaveEditControlValue()
			self.grid.DisableCellEditControl()	# Make sure the current edit is committed.
			if race is None:
				return
			numStrTuples = []
			for r in range(self.grid.GetNumberRows()):
				values = { name:self.grid.GetCellValue(r, c) for name, c in six.iteritems(self.iCol)
																			if name not in self.computedFields }
				values['catType'] = self.CategoryTypeChoices.index(values['catType'])
				values['distanceType'] = self.DistanceTypeChoices.index(values['distanceType'])
				numStrTuples.append( values )
			race.setCategories( numStrTuples )
			race.adjustAllCategoryWaveNumbers()
		wx.CallAfter( Utils.refreshForecastHistory )
Exemple #45
0
	def onOK( self, event ):
		num = self.numEdit.GetValue()
		t = self.getNewTime()
		if self.entry.num != num or self.entry.t != t:
			undo.pushState()
			with Model.LockRace() as race:
				rider = race.getRider( num )
				if self.entry.lap != 0:
					race.numTimeInfo.change( self.entry.num, self.entry.t, t )
					race.deleteTime( self.entry.num, self.entry.t )
					race.addTime( num, t + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0) )
				else:
					race.numTimeInfo.change( self.entry.num, rider.firstTime, t )
					rider.firstTime = t
					race.setChanged()
			Utils.refresh()
		self.EndModal( wx.ID_OK )
Exemple #46
0
	def commit( self ):
		undo.pushState()
		with Model.LockRace() as race:
			self.grid.SaveEditControlValue()
			self.grid.DisableCellEditControl()	# Make sure the current edit is committed.
			if race is None:
				return
			numStrTuples = []
			for r in xrange(self.grid.GetNumberRows()):
				values = { name:self.grid.GetCellValue(r, c) for name, c in self.iCol.iteritems()
																			if name not in self.computedFields }
				values['catType'] = self.CategoryTypeChoices.index(values['catType'])
				values['distanceType'] = self.DistanceTypeChoices.index(values['distanceType'])
				numStrTuples.append( values )
			race.setCategories( numStrTuples )
			race.adjustAllCategoryWaveNumbers()
		wx.CallAfter( Utils.refreshForecastHistory )
Exemple #47
0
	def onOK( self, event ):
		num = self.numEdit.GetValue()
		t = self.getNewTime()
		if self.entry.num != num or self.entry.t != t:
			undo.pushState()
			with Model.LockRace() as race:
				rider = race.getRider( num )
				if self.entry.lap != 0:
					race.numTimeInfo.change( self.entry.num, self.entry.t, t )
					race.deleteTime( self.entry.num, self.entry.t )
					race.addTime( num, t + (rider.firstTime if getattr(race, 'isTimeTrial', False) and getattr(rider, 'firstTime', None) is not None else 0.0) )
				else:
					race.numTimeInfo.change( self.entry.num, rider.firstTime, t )
					rider.firstTime = t
					race.setChanged()
			Utils.refresh()
		self.EndModal( wx.ID_OK )
Exemple #48
0
	def OnPopupAutocorrect( self, event ):
		if not self.entry:
			return
		if not Utils.MessageOKCancel( self,
			u'{} {}: {}?'.format(_('Bib'), self.entry.num, _('Turn off Autocorrect')),
			_('Turn off Autocorrect') ):
			return
		try:
			undo.pushState()
			with Model.LockRace() as race:
				if not race:
					return
				race.getRider(self.entry.num).setAutoCorrect( False )
				race.setChanged()
		except:
			pass
		wx.CallAfter( self.refresh )
Exemple #49
0
	def OnPopupDNF( self, event ):
		if not self.entry:
			return
		if not Utils.MessageOKCancel( self,
			u'{} {}: {} {}, {}?'.format(
				_('Bib'), self.entry.num,
				_('DNF Rider after lap'), self.entry.lap, Utils.formatTime(self.entry.t+1, True)),
			_('DNF Rider') ):
			return
		try:
			undo.pushState()
			with Model.LockRace() as race:
				if not race:
					return
				race.getRider(self.entry.num).setStatus( Model.Rider.DNF, self.entry.t + 1 )
				race.setChanged()
		except:
			pass
		wx.CallAfter( self.refresh )
Exemple #50
0
	def onOK( self, event ):
		num = self.numEdit.GetValue()
		if not num or num == self.entry.num:
			return
			
		tAdjust = 0.0001 + random.random() / 10000.0	# Add some randomness so that all inserted times will be unique.
		if self.beforeAfterBox.GetSelection() == 0:
			tAdjust = -tAdjust
		tInsert = self.entry.t + tAdjust
		
		undo.pushState()
		with Model.LockRace() as race:
			rider = race.getRider( num )
			race.numTimeInfo.add( num, tInsert )
			race.addTime( num, tInsert + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0) )
			
		Utils.refresh()
		
		self.EndModal( wx.ID_OK )
Exemple #51
0
    def swapEntries(self, num, numAdjacent):
        if not num or not numAdjacent:
            return
        with Model.LockRace() as race:
            if (not race or num not in race or numAdjacent not in race.riders):
                return
            e1 = race.getRider(num).interpolate()
            e2 = race.getRider(numAdjacent).interpolate()
            category = FixCategories(self.categoryChoice,
                                     getattr(race, 'ganttCategory', 0))

        riderResults = dict((r.num, r) for r in GetResults(category))
        try:
            laps = riderResults[num].laps
            undo.pushState()
            with Model.LockRace() as race:
                EditEntry.SwapEntry(e1[laps], e2[laps])
            wx.CallAfter(self.refresh)
        except KeyError:
            pass
Exemple #52
0
	def onOK( self, event ):
		race = Model.race
		if not race or not race.startTime:
			return
		
		tNow = datetime.datetime.now()
		startTimeNew = tNow.replace(hour=0, minute=0, second=0) + datetime.timedelta(seconds=self.timeMsEdit.GetSeconds())
		dTime = (startTimeNew - race.startTime).total_seconds()
		
		if dTime == 0:
			return
		
		if dTime > 0.0 and not Utils.MessageOKCancel( self,
				_('Are you Sure you want to change the Race Start to Later?') + u'\n' + _('(you can always undo).'), _('Are you sure?') ):
			return
		
		undo.pushState()
		
		if not race.isTimeTrial:
			for rider in race.riders.itervalues():
				if getattr(rider, 'firstTime', None) is not None:
					rider.firstTime -= dTime
			
				# Adjust all the recorded times to account for the new start time.
				for k in xrange(len(rider.times)):
					rider.times[k] -= dTime
			
			race.numTimeInfo.adjustAllTimes( -dTime )
			
		# Fix any unread tags.
		if race.unmatchedTags:
			for times in race.unmatchedTags.itervalues():
				for k in xrange(len(times)):
					times[k] -= dTime
		
		race.startTime = startTimeNew
		race.setChanged()
		Utils.refresh()
		
		self.EndModal( wx.ID_OK )
Exemple #53
0
	def onAddExceptions( self, event ):
		with Model.LockRace() as race:
			if not race or not race.getAllCategories():
				return
				
		r = self.grid.GetGridCursorRow()
		if r is None or r < 0:
			Utils.MessageOK( self, _('You must select a Category first'), _('Select a Category') )
			return
		
		with Model.LockRace() as race:
			categories = race.getAllCategories()
			category = categories[r]
			
		dlg = wx.TextEntryDialog(
			self,
			u'{}: {}'.format(
				category.name,
				_('''Add Bib Exceptions (comma separated).
This will add the given list of Bibs to this category,
and remove them from other categories.'''),
			),
			_('Add Bib Exceptions')
		)
		good = (dlg.ShowModal() == wx.ID_OK)
		if good:
			response = dlg.GetValue()
		dlg.Destroy()
		if not good:
			return

		undo.pushState()
		response = re.sub( '[^0-9,]', '', response.replace(' ', ',') )
		with Model.LockRace() as race:
			for numException in response.split(','):
				race.addCategoryException( category, numException )

		self.state.reset()
		self.refresh()
Exemple #54
0
def StartRaceNow(page=_('Record')):
    global undoResetTimer
    if undoResetTimer and undoResetTimer.IsRunning():
        undoResetTimer.Stop()
    undoResetTimer = None
    ChipReader.chipReaderCur.reset(
        Model.race.chipReaderType if Model.race else None)

    undo.clear()
    undo.pushState()
    with Model.LockRace() as race:
        if race is None:
            return

        if not race.enableJChipIntegration:
            race.resetStartClockOnFirstTag = False

        Model.resetCache()
        race.startRaceNow()
        isTimeTrial = race.isTimeTrial

    OutputStreamer.writeRaceStart()

    # Refresh the main window and switch to the specified pane.
    mainWin = Utils.getMainWin()
    if mainWin is not None:
        mainWin.showPageName(page)
        mainWin.updateLapCounter()
        mainWin.refresh()

        if isTimeTrial:
            mainWin.menuPublishHtmlTTStart()

    # For safety, clear the undo stack after 8 seconds.
    undoResetTimer = wx.CallLater(8000, undo.clear)

    if race.ftpUploadDuringRace:
        realTimeFtpPublish.publishEntry(True)
Exemple #55
0
    def swapEntries(self, num, numAdjacent):
        if not num or not numAdjacent:
            return
        with Model.LockRace() as race:
            if (not race or num not in race.riders or numAdjacent not in race):
                return
            e1 = race.getRider(num).interpolate()
            e2 = race.getRider(numAdjacent).interpolate()
            category = FixCategories(self.categoryChoice,
                                     getattr(race, 'resultsCategory', 0))

        riderResults = dict((r.num, r) for r in GetResults(category))
        try:
            rr1, rr2 = riderResults[num], riderResults[numAdjacent]
            laps = rr1.laps
            undo.pushState()
            ee1 = next(e for e in e1 if e.t == rr1.raceTimes[laps])
            ee2 = next(e for e in e2 if e.t == rr2.raceTimes[laps])
            with Model.LockRace() as race:
                SwapEntry(ee1, ee2)
            wx.CallAfter(self.refresh)
        except (KeyError, StopIteration):
            pass
Exemple #56
0
	def onOK( self, event ):
		num = self.numEdit.GetValue()
		t = self.timeMsEdit.GetSeconds()
		
		if self.timeChoice.GetSelection() == 1 and Model.race and Model.race.startTime:
			dtStart = Model.race.startTime
			dtInput = datetime.datetime(dtStart.year, dtStart.month, dtStart.day) + datetime.timedelta(seconds = t)
			if dtInput < dtStart:
				Utils.MessageOK( self, u'\n\n'.join( [_('Cannot Enter Clock Time Before Race Start.'), _('(reminder: clock time is in 24-hour format)')] ),
										_('Time Entry Error'), iconMask = wx.ICON_ERROR )
				return
			t = (dtInput - dtStart).total_seconds()
		
		offset = Model.race.getStartOffset( num )
		if t <= offset:
			Utils.MessageOK( self, u'{}: {}\n\n{}\n{}'.format(
				_('Cannot enter a time that is before the Category Start Offset'), Utils.formatTime(offset, highPrecision=True),
				_('All times earlier than the Start Offset are ignored.'),
				_('Please enter a time after the Start Offset.')
				), _('Time Entry Error'), iconMask = wx.ICON_ERROR
			)
			return
			
		if self.entry.num != num or self.entry.t != t:
			undo.pushState()
			with Model.LockRace() as race:
				rider = race.getRider( num )
				if self.entry.lap != 0:
					race.numTimeInfo.change( self.entry.num, self.entry.t, t )
					race.deleteTime( self.entry.num, self.entry.t )
					race.addTime( num, t + ((rider.firstTime or 0.0) if race.isTimeTrial else 0.0) )
				else:
					race.numTimeInfo.change( self.entry.num, rider.firstTime, t )
					rider.firstTime = t
					race.setChanged()
			Utils.refresh()
		self.EndModal( wx.ID_OK )
Exemple #57
0
    def doSet(self, action):
        selections = self.categoryList.GetSelections()
        if not selections:
            Utils.MessageOK(
                self,
                _("No Categories Selected.\n\nSelect some Categories, or Cancel"
                  ), _("No Categories Selected"), wx.ICON_EXCLAMATION)
            return False

        if 0 in selections:
            doAll = True
            selectedCats = set()
        else:
            doAll = False
            selectedCats = set(self.categories[s - 1] for s in selections)

        undo.pushState()
        with Model.LockRace() as race:
            for num, rider in race.riders.iteritems():
                if doAll or race.getCategory(num) in selectedCats:
                    rider.autocorrectLaps = action
                race.setChanged()
        Utils.refresh()
        return True
def DoImportTTStartTimes(race, excelLink):
    startTimes = {}
    errors = []

    if not excelLink:
        errors.append(_('Missing excelLink'))
        return errors, startTimes

    info = excelLink.read()

    for num, data in info.iteritems():
        try:
            startTime = data['StartTime']
        except KeyError:
            errors.append(u'{} {}: {}'.format(_('Bib'), num,
                                              _('missing start time')))
            continue

        # Try to make sense of the StartTime (Stopwatch time, not clock time).
        if isinstance(startTime, float):
            t = startTime * 24.0 * 60.0 * 60.0  # Excel decimal days.
        elif isinstance(startTime, (str, unicode)):
            # Otherwise, string of format hh:mm:ss.ddd or mm:ss.ddd.
            fields = startTime.split(':')
            try:
                hh, mm, ss = [float(f.strip()) for f in fields[:3]]
            except:
                try:
                    hh = 0.0
                    mm, ss = [float(f.strip()) for f in fields[:2]]
                except:
                    errors.append(u'{} {}:  {}: "{}"'.format(
                        _('Bib'), num, _('cannot read time format'),
                        startTime))
                    continue
            t = hh * 60.0 * 60.0 + mm * 60.0 + ss
        else:
            errors.append(u'{} {}:  {}'.format(
                _('Bib'), num,
                _('cannot read start time (neither Excel time nor String)')))
            continue

        startTimes[num] = t

    changeCount = 0
    if startTimes:
        undo.pushState()
        for num, startTime in startTimes.iteritems():
            rider = race.getRider(num)

            # Compute the time change difference.
            try:
                firstTime = getattr(rider, 'firstTime', startTime)
            except TypeError:
                continue

            if rider.times:
                # Convert the race times to time of day by adding the existing first time.
                riderTimeOfDay = [firstTime + rt for rt in rider.times]

                # Compute new lap times by subtracting the new start time.
                rider.times = [rtod - startTime for rtod in riderTimeOfDay]

            if rider.firstTime != startTime:
                rider.firstTime = startTime
                changeCount += 1

        race.setChanged()

    return errors, startTimes, changeCount