def handle_delete(self): """Handle delete key press. On delete key press, delete the selection. """ model = self.selectionModel().model() selection_list = self.selectionModel().selectedRows() field_table_model = self.modeldb.field_table_model racer_table_model = self.modeldb.racer_table_model field_count = len(selection_list) racer_count = 0 for selection in selection_list: field_record = field_table_model.record(selection.row()) field_id = field_record.value(FieldTableModel.ID) racer_count += racer_table_model.racer_count_total_in_field( field_id) # Confirm deletion. msg_box = QMessageBox() msg_box.setWindowTitle(common.APPLICATION_NAME) msg_box.setText('Deleting %s' % common.pretty_list([ common.pluralize('field', field_count), common.pluralize('racer', racer_count) ])) msg_box.setInformativeText('Do you really want to delete?') msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) msg_box.setDefaultButton(QMessageBox.Cancel) msg_box.setIcon(QMessageBox.Information) if msg_box.exec() != QMessageBox.Ok: return # Remove rows from large to small, because the rows are removed # immediately, and cause the rest of the rows to shift, invalidating # any row number that's higher than the currently removed one. selection_list.sort(key=lambda selection: selection.row(), reverse=True) for selection in selection_list: field_record = field_table_model.record(selection.row()) field_id = field_record.value(FieldTableModel.ID) racer_in_field_table_view = self.racer_in_field_table_view_dict[ field_id] racer_in_field_table_model = racer_in_field_table_view.model() # Have to remove one row at a time from the proxy model. For some # reason, a ranged removeRows() fails. # Also, the removal is immediate, so we keep removing index 0. for row in reversed(range(racer_in_field_table_model.rowCount())): racer_in_field_table_model.removeRow(row) model.removeRow(selection.row()) # Model retains blank rows until we select() again. self.modeldb.field_table_model.select()
def import_bikereg_file(self): """Import a BikeReg csv racers list export file. This starts a new race and populates the field and racer lists with the stuff from the csv file. """ import_filename = self.import_file_prepare() if not import_filename: return bikereg.import_csv(self.centralWidget().modeldb, import_filename) self.centralWidget().modeldb.add_defaults() # Open the racer and field windows so that the import actually looks like it did something. self.centralWidget().button_row.racer_button.click() self.centralWidget().button_row.field_button.click() # Show import summary. field_table_model = self.centralWidget().modeldb.field_table_model racer_table_model = self.centralWidget().modeldb.racer_table_model if ((field_table_model.rowCount() != 0) or (racer_table_model.rowCount() != 0)): message_text = (('Imported %s. ' % common.pretty_list([common.pluralize('field', field_table_model.rowCount()), common.pluralize('racer', racer_table_model.rowCount())])) + 'Would you like to open the Race Builder to assign start times?') msg_box = QMessageBox() msg_box.setWindowTitle(common.APPLICATION_NAME) msg_box.setText('Import complete.') msg_box.setInformativeText(message_text) msg_box.addButton(QMessageBox.Ok) msg_box.addButton('Later', QMessageBox.RejectRole) msg_box.setDefaultButton(QMessageBox.Ok) msg_box.setIcon(QMessageBox.Question) if msg_box.exec() == QMessageBox.Ok: self.config_builder() self.centralWidget().builder.setCurrentIndex(1)
def import_ontheday_race_config(self): """Call ontheday module to import race config.""" ontheday_import_wizard = ontheday.ImportWizard() if ontheday_import_wizard.exec() == QDialog.Rejected: return if not ontheday_import_wizard.filename: return filename = ontheday_import_wizard.filename auth = ontheday_import_wizard.auth race = ontheday_import_wizard.race try: self.switch_to_main(filename, True) except DatabaseError as e: QMessageBox.warning(self, 'Error', str(e)) self.switch_to_start() return if ontheday_import_wizard.enable_reference_clock: race_table_model = self.centralWidget().modeldb.race_table_model old_datetime = race_table_model.get_reference_clock_datetime() new_datetime = ontheday_import_wizard.reference_clock race_table_model.set_reference_clock_datetime(new_datetime) race_table_model.enable_reference_clock() race_table_model.change_reference_clock_datetime(old_datetime, new_datetime) message = ('Setting reference clock to %s' % new_datetime.toString(defaults.REFERENCE_CLOCK_DATETIME_FORMAT)) QMessageBox.information(self, 'Info', message) try: ontheday.import_race(self.centralWidget().modeldb, auth, race) except requests.exceptions.HTTPError: QMessageBox.warning(self, 'Error', 'Authentication failure') return except (requests.exceptions.ConnectTimeout, requests.exceptions.Timeout): QMessageBox.warning(self, 'Error', 'Import timeout') return self.centralWidget().modeldb.add_defaults() # Show import summary, and ask if we want to set up the remote connection. field_table_model = self.centralWidget().modeldb.field_table_model racer_table_model = self.centralWidget().modeldb.racer_table_model message_text = (('Imported %s. ' % common.pretty_list([common.pluralize('field', field_table_model.rowCount()), common.pluralize('racer', racer_table_model.rowCount())])) + 'Would you like to set up the OnTheDay.net remote connection?') msg_box = QMessageBox() msg_box.setWindowTitle(common.APPLICATION_NAME) msg_box.setText('Import complete.') msg_box.setInformativeText(message_text) msg_box.addButton(QMessageBox.Ok) msg_box.addButton('Later', QMessageBox.RejectRole) msg_box.setDefaultButton(QMessageBox.Ok) msg_box.setIcon(QMessageBox.Question) if msg_box.exec() == QMessageBox.Ok: self.connect_remote(remotes.OnTheDayRemote)
def import_file_prepare(self): """Prepare for importing a race file (exported from some other service). Need to show a file selection dialog to choose the import file. Then, show another file selection dialog to choose where to store the race file (with appropriate warning for selecting an existing file). """ # Pick the import file. dialog = common.FileDialog(self) dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setFileMode(QFileDialog.ExistingFile) dialog.setNameFilter('Bikereg file (*.csv)') if not dialog.exec(): return None import_filename = dialog.selectedFiles()[0] # If we are not yet initialized, pick a new race file. if not self.centralWidget().has_model(): dialog = common.FileDialog(self) dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setDefaultSuffix('rce') dialog.setFileMode(QFileDialog.AnyFile) dialog.setLabelText(QFileDialog.Accept, 'New') dialog.setNameFilter('Race file (*.rce)') try: if dialog.exec(): filename = dialog.selectedFiles()[0] self.switch_to_main(filename, True) return import_filename except DatabaseError as e: QMessageBox.warning(self, 'Error', str(e)) self.switch_to_start() return None # Otherwise, if our current race has stuff in it, confirm to overwrite # before clearing it. # Get Field and Racer tables so we can whine about how much state # we're going to lose if we let the import happen. field_table_model = self.centralWidget().modeldb.field_table_model racer_table_model = self.centralWidget().modeldb.racer_table_model if ((field_table_model.rowCount() != 0) or (racer_table_model.rowCount() != 0)): msg_box = QMessageBox() msg_box.setWindowTitle(common.APPLICATION_NAME) msg_box.setText('Overwriting %s!' % common.pretty_list([common.pluralize('field', field_table_model.rowCount()), common.pluralize('racer', racer_table_model.rowCount())])) msg_box.setInformativeText('Do you really want to overwrite ' + 'this data?') msg_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) msg_box.setDefaultButton(QMessageBox.Cancel) msg_box.setIcon(QMessageBox.Information) if msg_box.exec() != QMessageBox.Ok: return None # Reuse old filename. filename = self.centralWidget().modeldb.filename try: self.switch_to_main(filename, True) except DatabaseError as e: QMessageBox.warning(self, 'Error', str(e)) self.switch_to_start() return None return import_filename