def print_csv(self, pytimer): res = print_times(pytimer, True) # True is to print csv # Display message that was successful md = MsgDialog(pytimer.timewin, 'information', ['ok'], 'Success!', "Results saved to CSV.") md.run() md.destroy()
def print_html(self, btn_unused, pytimer): res = print_times(pytimer, False) # Display message that was successful md = MsgDialog(pytimer.timewin, 'information', ['ok'], 'Success!', "Results saved to HTML.") md.run() md.destroy()
def store_new_project(self, jnk_unused, edit): '''Stores a new project to file and goes to root window''' logger = logging.getLogger('fstimer') logger.debug(self.path) if not edit: os.system('mkdir '+ self.path) regdata = {} regdata['projecttype'] = self.projecttype regdata['numlaps'] = self.numlaps regdata['variablelaps'] = self.variablelaps regdata['fields'] = self.fields regdata['fieldsdic'] = self.fieldsdic regdata['printfields'] = self.printfields regdata['divisions'] = self.divisions regdata['rankings'] = self.rankings logger.debug(regdata) os.makedirs(self.path, exist_ok=True) with open(join(self.path, basename(self.path)+'.reg'), 'w', encoding='utf-8') as fout: json.dump(regdata, fout) if edit: md = MsgDialog(self.rankingswin, 'information', ['ok'], 'Edited!', 'Project '+basename(self.path)+' successfully edited!') else: md = MsgDialog(self.rankingswin, 'information', ['ok'], 'Created!', 'Project '+basename(self.path)+' successfully created!') md.run() md.destroy() self.rankingswin.hide() if not edit: self.introwin.hide() self.rootwin = fstimer.gui.root.RootWin(self.path, self.show_about, self.import_prereg, self.handle_preregistration, self.compreg_window, self.gen_pretimewin, self.define_divisions)
def set_printfields(self, btnlist, btn_time, btn_pace, entry_pace, printfields_m): '''Update self.printfields''' # First check it is valid. if btn_pace.get_active(): try: d = float(entry_pace.get_text()) except ValueError: md = MsgDialog(self.printfieldswin, 'error', ['ok'], 'Error!', 'Distance must be a number.') md.run() md.destroy() return False # It will be valid. Let's continue. self.printfields = {} # re-set # Start with the registration fields for field, btn in zip(self.fields, btnlist): if btn.get_active(): self.printfields[field] = '{' + field + '}' # Then timing button and pace button if btn_time.get_active(): self.printfields['Time'] = '{Time}' if btn_pace.get_active(): self.printfields['Pace'] = '{Time}/' + entry_pace.get_text() # Finally custom fields for field in printfields_m: if field not in self.fields and field not in ['Time', 'Pace']: self.printfields[field] = str(printfields_m[field]) if len(self.printfields) == 0: md = MsgDialog(self.printfieldswin, 'error', ['ok'], 'Error!', 'Must include at least one field.') md.run() md.destroy() return False return True
def rm_clicked(self, jnk_unused): '''Handling click on the 'remove' button of the registration window Throws up an 'are you sure' dialog box, and delete if yes''' selection = self.treeview.get_selection() treeiter = selection.get_selected()[1] # if nothing is selected, do nothing. if treeiter: rmreg_dialog = MsgDialog(self, 'warning', ['yes', 'no'], 'Really delete?', 'Are you sure you want to delete this entry?\nThis cannot be undone.') rmreg_dialog.set_default_response(Gtk.ResponseType.NO) response = rmreg_dialog.run() rmreg_dialog.destroy() if response == Gtk.ResponseType.YES: # Grab the current information. current_info = {} for (colid, field) in enumerate(self.fields): current_info[field] = self.modelfiltersorted.get_value(treeiter, colid) # Find where this is in self.prereg preregiter = self.prereg.index(current_info) # converts the treeiter from sorted to filter to model, and remove self.regmodel.remove(self.modelfilter.convert_iter_to_child_iter(self.modelfiltersorted.convert_iter_to_child_iter(treeiter))) try: self.ids.remove(current_info['ID']) except: pass self.prereg.pop(preregiter) # The latest stuff has no longer been saved. self.regstatus.set_markup('')
def code_edit(self, widget, path, text): '''handles a change of the ranking code''' # Validate the code try: # First make sure all of the variables are Time or a registration field vars_ = re.findall("\{[^}]+\}", text) for var in vars_: name = var[1:-1] if not (name in self.fields or name == 'Time'): raise KeyError('Cannot find variable {}'.format(name)) # Now check that the operations work, by plugging in a float for Time, and a string # for everything else. text_test = str(text) for var in vars_: if var == '{Time}': text_test = text_test.replace(var, "3.14159") elif self.fieldsdic[var[1:-1]]['type'] == 'entrybox_int': text_test = text_test.replace(var, "20") else: # Use a string of a number so that int() works # In the future we will have typed fields. text_test = text_test.replace(var, "'1000000001'") eval(text_test) except Exception as e: md = MsgDialog( self, 'error', ['ok'], 'Error!', 'Invalid code:\n\n{}\n\nSee documentation.'.format(e)) md.run() md.destroy() return treeiter = self.custommodel.get_iter(path) name = self.custommodel.get_value(treeiter, 0) self.custommodel[path][1] = text self.printfields[name] = text return
def resume_times(self, jnk_unused, isMerge): '''Handles click on Resume button''' chooser = Gtk.FileChooserDialog(title='Choose timing results to resume', parent=self, action=Gtk.FileChooserAction.OPEN, buttons=('Cancel', Gtk.ResponseType.CANCEL, 'OK', Gtk.ResponseType.OK)) chooser.set_current_folder(self.path) ffilter = Gtk.FileFilter() ffilter.set_name('Timing results') ffilter.add_pattern('*_times.json') chooser.add_filter(ffilter) response = chooser.run() if response == Gtk.ResponseType.OK: filename = chooser.get_filename() try: with open(filename, 'r', encoding='utf-8') as fin: saveresults = json.load(fin) newrawtimes = saveresults['rawtimes'] if isMerge: if self.rawtimes['ids'] and not self.rawtimes['times']: if newrawtimes['times'] and not newrawtimes['ids']: #Merge! We have IDs, merge in times. self.rawtimes['times'] = list(newrawtimes['times']) else: raise MergeError('Must be pure IDs merged into pure times, or vice versa') elif self.rawtimes['times'] and not self.rawtimes['ids']: if newrawtimes['ids'] and not newrawtimes['times']: #Merge! We have times, merge in IDS. self.rawtimes['ids'] = list(newrawtimes['ids']) else: raise MergeError('Must be pure IDs merged into pure times, or vice versa') else: raise MergeError('Must be pure IDs merged into pure times, or vice versa') else: self.rawtimes['ids'] = newrawtimes['ids'] self.rawtimes['times'] = newrawtimes['times'] #self.timestr = saveresults['timestr'] #We will _not_ overwrite when resuming. self.t0 = saveresults['t0'] GLib.timeout_add(100, self.update_clock) #start the stopwatch # Recompute how many racers have checked in self.racers_in = [0] * self.numlaps for ID in self.rawtimes['ids']: self.update_racers(ID) self.offset = len(self.rawtimes['times']) - len(self.rawtimes['ids']) # Update racers' label self.update_racers_label() self.timemodel.clear() if self.offset >= 0: adj_ids = ['' for i_unused in range(self.offset)] adj_ids.extend(self.rawtimes['ids']) adj_times = list(self.rawtimes['times']) elif self.offset < 0: adj_times = ['' for i_unused in range(-self.offset)] adj_times.extend(self.rawtimes['times']) adj_ids = list(self.rawtimes['ids']) for entry in zip(adj_ids, adj_times): self.timemodel.append(list(entry)) except (IOError, ValueError, TypeError, MergeError) as e: error_dialog = MsgDialog(self, 'error', ['ok'], 'Oops...', 'ERROR: Failed to %s : %s.' % ('merge' if isMerge else 'resume', e)) response = error_dialog.run() error_dialog.destroy() chooser.destroy()
def restart_t0(self, jnk_unused): '''Handles click on restart clock button''' restart_t0_dialog = MsgDialog(self, 'warning', ['yes', 'no'], 'Are you sure?', 'Are you sure you want to restart the race clock?\nThis cannot be undone.') restart_t0_dialog.set_default_response(Gtk.ResponseType.NO) response = restart_t0_dialog.run() restart_t0_dialog.destroy() if response == Gtk.ResponseType.YES: self.t0 = time.time()
def print_excel(self, pytimer): #res = print_times(pytimer, True) res = print_times( pytimer, OutputFormat.EXCEL) # True is to print csv OutputFormat # Display message that was successful md = MsgDialog(pytimer.timewin, 'information', ['ok'], 'Success!', "Results saved to EXCEL.") md.run() md.destroy()
def done_timing(self, source): '''Handles click on the Done button Gives a dialog before closing.''' oktime_dialog2 = MsgDialog(self, 'question', ['yes', 'no', 'cancel'], 'Save?', 'Do you want to save before finishing?\nUnsaved data will be lost.') response2 = oktime_dialog2.run() oktime_dialog2.destroy() if response2 == Gtk.ResponseType.CANCEL: return elif response2 == Gtk.ResponseType.YES: self.save_times(None) self.hide()
def restart_t0(self, jnk_unused): '''Handles click on restart clock button''' restart_t0_dialog = MsgDialog( self, 'warning', ['yes', 'no'], 'Are you sure?', 'Are you sure you want to restart the race clock?\nThis cannot be undone.' ) restart_t0_dialog.set_default_response(Gtk.ResponseType.NO) response = restart_t0_dialog.run() restart_t0_dialog.destroy() if response == Gtk.ResponseType.YES: self.t0 = time.time()
def save_times(self, jnk_unused): '''Handles click on the Save button jsonn dump to the already specified filename''' saveresults = {} saveresults['rawtimes'] = self.rawtimes saveresults['timestr'] = self.timestr saveresults['t0'] = self.t0 with open(os.path.join(self.path, os.path.basename(self.path)+'_'+self.timestr+'_times.json'), 'w', encoding='utf-8') as fout: json.dump(saveresults, fout) md = MsgDialog(self, 'information', ['ok'], 'Saved!', 'Times saved!') md.run() md.destroy()
def done_timing(self, source): '''Handles click on the Done button Gives a dialog before closing.''' oktime_dialog2 = MsgDialog( self, 'question', ['yes', 'no', 'cancel'], 'Save?', 'Do you want to save before finishing?\nUnsaved data will be lost.' ) response2 = oktime_dialog2.run() oktime_dialog2.destroy() if response2 == Gtk.ResponseType.CANCEL: return elif response2 == Gtk.ResponseType.YES: self.save_times(None) self.hide()
def preregister_ok_cb(self, jnk_unused, regid_btn, handle_registration_cb): '''If OK is pushed on the pre-register window.''' #First check if the file already exists regid = regid_btn.get_value_as_int() filename = os.path.join(self.path, os.path.basename(self.path)+'_registration_'+str(regid)+'.json') if os.path.exists(filename): #Raise a warning window md = MsgDialog(self, 'warning', ['ok', 'cancel'], 'Proceed?', "A file with this registration number already exists.\nIf you continue it will be overwritten!") resp = md.run() md.destroy() #Check the result. if resp == Gtk.ResponseType.CANCEL: #Do nothing. return #Else, continue on. handle_registration_cb(regid)
def close_clicked(self, jnk_unused): '''Handles click on the 'close' button on the registration window. Throws up a 'do you want to save' dialog, and close the window''' okreg_dialog = MsgDialog(self, 'question', ['yes', 'no'], 'Save?', 'Do you want to save before finishing?\nUnsaved data will be lost.') okreg_dialog.set_default_response(Gtk.ResponseType.YES) response = okreg_dialog.run() okreg_dialog.destroy() if response == Gtk.ResponseType.YES: # this will save save_res = self.save_clicked(None) if not save_res: return self.hide() # Clear the file setting from pre-reg, in case pre-reg is # re-run without selecting a file del self.prereg[:]
def timing_rm_time(self, jnk_unused): '''Handles click on Drop time comment Throws up an 'are you sure' dialog box, and drop if yes.''' treeselection = self.timeview.get_selection() pathlist = treeselection.get_selected_rows()[1] if len(pathlist) == 0: # we don't load any windows or do anything pass elif len(pathlist) > 1: # this is a one-at-a-time operation pass elif len(pathlist) == 1: # Figure out what row this is in the timeview row = pathlist[0][0] # Now figure out what index in self.rawtimes['times'] it is. timeidx = row - max(0, -self.offset) if timeidx >= 0: # Otherwise, there is no time here so there is nothing to do. # Ask if we are sure. rmtime_dialog = MsgDialog( self, 'warning', ['yes', 'no'], 'Are you sure?', 'Are you sure you want to drop this time and shift all later times down earlier in the list?\nThis cannot be undone.' ) rmtime_dialog.set_default_response(Gtk.ResponseType.NO) response = rmtime_dialog.run() rmtime_dialog.destroy() if response == Gtk.ResponseType.YES: # Make the shift in self.rawtimes and self.offset self.rawtimes['times'].pop(timeidx) self.offset -= 1 # And now shift everything on the display. rowcounter = int(row) for i in range(timeidx - 1, -1, -1): # Write rawtimes[i] into row rowcounter treeiter = self.timemodel.get_iter((rowcounter, )) self.timemodel.set_value( treeiter, 1, str(self.rawtimes['times'][i])) rowcounter -= 1 # Now we tackle the last value - there are two possibilities. if self.offset < 0: # There is a buffer of IDs, and this one should be cleared. treeiter = self.timemodel.get_iter((rowcounter, )) self.timemodel.set_value(treeiter, 1, '') else: # there is a blank row at the top which should be removed. treeiter = self.timemodel.get_iter((rowcounter, )) self.timemodel.remove(treeiter)
def save_times(self, jnk_unused): '''Handles click on the Save button jsonn dump to the already specified filename''' saveresults = {} saveresults['rawtimes'] = self.rawtimes saveresults['timestr'] = self.timestr saveresults['t0'] = self.t0 with open(os.path.join( self.path, os.path.basename(self.path) + '_' + self.timestr + '_times.json'), 'w', encoding='utf-8') as fout: json.dump(saveresults, fout) md = MsgDialog(self, 'information', ['ok'], 'Saved!', 'Times saved!') md.run() md.destroy()
def timing_rm_time(self, jnk_unused): '''Handles click on Drop time comment Throws up an 'are you sure' dialog box, and drop if yes.''' treeselection = self.timeview.get_selection() pathlist = treeselection.get_selected_rows()[1] if len(pathlist) == 0: # we don't load any windows or do anything pass elif len(pathlist) > 1: # this is a one-at-a-time operation pass elif len(pathlist) == 1: # Figure out what row this is in the timeview row = pathlist[0][0] # Now figure out what index in self.rawtimes['times'] it is. timeidx = row-max(0, -self.offset) if timeidx >= 0: # Otherwise, there is no time here so there is nothing to do. # Ask if we are sure. rmtime_dialog = MsgDialog(self, 'warning', ['yes', 'no'], 'Are you sure?', 'Are you sure you want to drop this time and shift all later times down earlier in the list?\nThis cannot be undone.') rmtime_dialog.set_default_response(Gtk.ResponseType.NO) response = rmtime_dialog.run() rmtime_dialog.destroy() if response == Gtk.ResponseType.YES: # Make the shift in self.rawtimes and self.offset self.rawtimes['times'].pop(timeidx) self.offset -= 1 # And now shift everything on the display. rowcounter = int(row) for i in range(timeidx-1, -1, -1): # Write rawtimes[i] into row rowcounter treeiter = self.timemodel.get_iter((rowcounter,)) self.timemodel.set_value(treeiter, 1, str(self.rawtimes['times'][i])) rowcounter -= 1 # Now we tackle the last value - there are two possibilities. if self.offset < 0: # There is a buffer of IDs, and this one should be cleared. treeiter = self.timemodel.get_iter((rowcounter,)) self.timemodel.set_value(treeiter, 1, '') else: # there is a blank row at the top which should be removed. treeiter = self.timemodel.get_iter((rowcounter,)) self.timemodel.remove(treeiter)
def name_edit(self, widget, path, text): '''handles a change of a ranking name''' treeiter = self.custommodel.get_iter(path) old_name = self.custommodel.get_value(treeiter, 0) # Check if it was changed if text != old_name: if text in ['Time', 'Pace']: md = MsgDialog(self, 'error', ['ok'], 'Error!', 'Names "Time" and "Pace" are reserved.') md.run() md.destroy() elif text not in self.printfields and text not in self.fields: self.custommodel[path][0] = text self.printfields[text] = self.printfields[old_name] self.printfields.pop(old_name) else: md = MsgDialog(self, 'error', ['ok'], 'Error!', 'Field name "%s" is already used!' % text) md.run() md.destroy() return
def preregister_ok_cb(self, jnk_unused, regid_btn, handle_registration_cb): '''If OK is pushed on the pre-register window.''' #First check if the file already exists regid = regid_btn.get_value_as_int() filename = os.path.join( self.path, os.path.basename(self.path) + '_registration_' + str(regid) + '.json') if os.path.exists(filename): #Raise a warning window md = MsgDialog( self, 'warning', ['ok', 'cancel'], 'Proceed?', "A file with this registration number already exists.\nIf you continue it will be overwritten!" ) resp = md.run() md.destroy() #Check the result. if resp == Gtk.ResponseType.CANCEL: #Do nothing. return #Else, continue on. handle_registration_cb(regid)
def editsingletimedone(self, treeiter, new_id, new_time): '''Handled result of the editing of a given time''' row = self.timemodel.get_path(treeiter)[0] if not re.match('^[0-9:.]*$', new_time): md = MsgDialog(self, 'error', ['ok'], 'Error!', 'Time is not valid format.') md.run() md.destroy() return if row < self.offset: if new_id: # we are putting an ID in a slot that we hadn't reached yet # Fill in any other missing ones up to this point with ''. ids = [str(new_id)] ids.extend(['' for i_unused in range(self.offset - row - 1)]) ids.extend(self.rawtimes['ids']) self.rawtimes['ids'] = list(ids) self.offset = row #the new offset self.rawtimes['times'][row] = str(new_time) #the new time self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) elif new_time: # we are adjusting the time only. self.rawtimes['times'][row] = str(new_time) #the new time self.timemodel.set_value(treeiter, 1, str(new_time)) else: # we are clearing this entry. pop it from time and adjust offset. self.rawtimes['times'].pop(row) self.offset -= 1 self.timemodel.remove(treeiter) elif row == self.offset and new_time and not new_id: # then we are clearing the most recent ID. # We pop it and adjust self.offset and adjust the time. self.rawtimes['ids'].pop(0) self.rawtimes['times'][row] = str(new_time) self.offset += 1 self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) elif row < -self.offset: # Here we are making edits to a slot where there is an ID, but no time. if new_time: #we are putting a time in a slot that we hadn't reached yet. Fill in any other missing ones up to this point with blanks. times = [str(new_time)] times.extend( ['' for i_unused in range(-self.offset - row - 1)]) times.extend(self.rawtimes['times']) self.rawtimes['times'] = list(times) self.offset = -row #the new offset self.rawtimes['ids'][row] = str(new_id) #the new time self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) elif new_id: #we are adjusting the id only. self.rawtimes['ids'][row] = str(new_id) #the new time self.timemodel.set_value(treeiter, 0, str(new_id)) else: #we are clearing this entry. pop it from id and adjust offset. self.rawtimes['ids'].pop(row) self.offset += 1 self.timemodel.remove(treeiter) else: if not new_time and not new_id: # we are clearing the entry if self.offset > 0: self.rawtimes['ids'].pop(row - self.offset) self.rawtimes['times'].pop(row) elif self.offset <= 0: self.rawtimes['ids'].pop(row) self.rawtimes['times'].pop(row + self.offset) self.timemodel.remove(treeiter) else: # adjust the entry; no changes to the stack otherwise. if self.offset > 0: self.rawtimes['ids'][row - self.offset] = str(new_id) self.rawtimes['times'][row] = str(new_time) elif self.offset <= 0: self.rawtimes['ids'][row] = str(new_id) self.rawtimes['times'][row + self.offset] = str(new_time) self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) #reset lapcounter, if used.. if self.numlaps > 1: self.lapcounter = defaultdict(int) self.lapcounter.update(Counter(self.rawtimes['ids'])) self.winedittime.hide()
def resume_times(self, jnk_unused, isMerge): '''Handles click on Resume button''' chooser = Gtk.FileChooserDialog( title='Choose timing results to resume', parent=self, action=Gtk.FileChooserAction.OPEN, buttons=('Cancel', Gtk.ResponseType.CANCEL, 'OK', Gtk.ResponseType.OK)) chooser.set_current_folder(self.path) ffilter = Gtk.FileFilter() ffilter.set_name('Timing results') ffilter.add_pattern('*_times.json') chooser.add_filter(ffilter) response = chooser.run() if response == Gtk.ResponseType.OK: filename = chooser.get_filename() try: with open(filename, 'r', encoding='utf-8') as fin: saveresults = json.load(fin) newrawtimes = saveresults['rawtimes'] if isMerge: if self.rawtimes['ids'] and not self.rawtimes['times']: if newrawtimes['times'] and not newrawtimes['ids']: #Merge! We have IDs, merge in times. self.rawtimes['times'] = list(newrawtimes['times']) else: raise MergeError( 'Must be pure IDs merged into pure times, or vice versa' ) elif self.rawtimes['times'] and not self.rawtimes['ids']: if newrawtimes['ids'] and not newrawtimes['times']: #Merge! We have times, merge in IDS. self.rawtimes['ids'] = list(newrawtimes['ids']) else: raise MergeError( 'Must be pure IDs merged into pure times, or vice versa' ) else: raise MergeError( 'Must be pure IDs merged into pure times, or vice versa' ) else: self.rawtimes['ids'] = newrawtimes['ids'] self.rawtimes['times'] = newrawtimes['times'] #self.timestr = saveresults['timestr'] #We will _not_ overwrite when resuming. self.t0 = saveresults['t0'] GLib.timeout_add(100, self.update_clock) #start the stopwatch # Recompute how many racers have checked in self.racers_in = [0] * self.numlaps for ID in self.rawtimes['ids']: self.update_racers(ID) self.offset = len(self.rawtimes['times']) - len( self.rawtimes['ids']) # Update racers' label self.update_racers_label() self.timemodel.clear() if self.offset >= 0: adj_ids = ['' for i_unused in range(self.offset)] adj_ids.extend(self.rawtimes['ids']) adj_times = list(self.rawtimes['times']) elif self.offset < 0: adj_times = ['' for i_unused in range(-self.offset)] adj_times.extend(self.rawtimes['times']) adj_ids = list(self.rawtimes['ids']) for entry in zip(adj_ids, adj_times): self.timemodel.append(list(entry)) except (IOError, ValueError, TypeError, MergeError) as e: error_dialog = MsgDialog( self, 'error', ['ok'], 'Oops...', 'ERROR: Failed to %s : %s.' % ('merge' if isMerge else 'resume', e)) response = error_dialog.run() error_dialog.destroy() chooser.destroy()
def editsingletimedone(self, treeiter, new_id, new_time): '''Handled result of the editing of a given time''' row = self.timemodel.get_path(treeiter)[0] if not re.match('^[0-9:.]*$', new_time): md = MsgDialog(self, 'error', ['ok'], 'Error!', 'Time is not valid format.') md.run() md.destroy() return if row < self.offset: if new_id: # we are putting an ID in a slot that we hadn't reached yet # Fill in any other missing ones up to this point with ''. ids = [str(new_id)] ids.extend(['' for i_unused in range(self.offset-row-1)]) ids.extend(self.rawtimes['ids']) self.rawtimes['ids'] = list(ids) self.offset = row #the new offset self.rawtimes['times'][row] = str(new_time) #the new time self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) elif new_time: # we are adjusting the time only. self.rawtimes['times'][row] = str(new_time) #the new time self.timemodel.set_value(treeiter, 1, str(new_time)) else: # we are clearing this entry. pop it from time and adjust offset. self.rawtimes['times'].pop(row) self.offset -= 1 self.timemodel.remove(treeiter) elif row == self.offset and new_time and not new_id: # then we are clearing the most recent ID. # We pop it and adjust self.offset and adjust the time. self.rawtimes['ids'].pop(0) self.rawtimes['times'][row] = str(new_time) self.offset += 1 self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) elif row < -self.offset: # Here we are making edits to a slot where there is an ID, but no time. if new_time: #we are putting a time in a slot that we hadn't reached yet. Fill in any other missing ones up to this point with blanks. times = [str(new_time)] times.extend(['' for i_unused in range(-self.offset-row-1)]) times.extend(self.rawtimes['times']) self.rawtimes['times'] = list(times) self.offset = -row #the new offset self.rawtimes['ids'][row] = str(new_id) #the new time self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) elif new_id: #we are adjusting the id only. self.rawtimes['ids'][row] = str(new_id) #the new time self.timemodel.set_value(treeiter, 0, str(new_id)) else: #we are clearing this entry. pop it from id and adjust offset. self.rawtimes['ids'].pop(row) self.offset += 1 self.timemodel.remove(treeiter) else: if not new_time and not new_id: # we are clearing the entry if self.offset > 0: self.rawtimes['ids'].pop(row-self.offset) self.rawtimes['times'].pop(row) elif self.offset <= 0: self.rawtimes['ids'].pop(row) self.rawtimes['times'].pop(row+self.offset) self.timemodel.remove(treeiter) else: # adjust the entry; no changes to the stack otherwise. if self.offset > 0: self.rawtimes['ids'][row-self.offset] = str(new_id) self.rawtimes['times'][row] = str(new_time) elif self.offset <= 0: self.rawtimes['ids'][row] = str(new_id) self.rawtimes['times'][row+self.offset] = str(new_time) self.timemodel.set_value(treeiter, 0, str(new_id)) self.timemodel.set_value(treeiter, 1, str(new_time)) #reset lapcounter, if used.. if self.numlaps > 1: self.lapcounter = defaultdict(int) self.lapcounter.update(Counter(self.rawtimes['ids'])) self.winedittime.hide()