/*============================================================================ ** ** Project/Product : ** Filename : qmteamdisplay.cpp ** Author(s) : DDP ** ** Description : Display and Update Team Information ** ** ** Information : ** Compiler : ANSI C++ ** Target : ** ***==========================================================================*/ #include "qmteamdisplay.h" #include "ui_qmteamdisplay.h" #include "spinboxdelegate.h" #include "timedelegate.h" #include "textdelegate.h" #include "mainwindow.h" #include "QmEditAddendum.h" /*---------------------------------------------------------------------------- ** FUNCTION : qmTeamDisplay ** ** DESCRIPTION : Construct a new widget ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ qmTeamDisplay::qmTeamDisplay(QWidget *parent, int initialTeam, bool useDone) : QWidget(parent), ui(new Ui::QmTeamDisplay) { ui->setupUi(this); team = 0; dirty = true; populating = false; enableDone = useDone; /* ** Set delegates to assist in editing the members table ** Name ** Sex ** Age */ ui->members->setItemDelegateForColumn(0, new textDelegate(MAX_PERSON_NAME)); ui->members->setItemDelegateForColumn(2, new SpinBoxDelegate(0,120)); ui->members->verticalHeader()->setVisible(true); QStringList labels; for ( int ii = 0 ; ii < config.num_legs; ii++) { labels << config.leg_name[ii]; } ui->members->setVerticalHeaderLabels(labels); /* ** Insert widgets for the Team Times */ for (int ii = 0; ii <= MAX_LEGS; ii++) { lt[ii] = NULL; } for ( int ii = 1 ; ii <= config.num_legs; ii++) { lt[ii] = new QmLegTimes(ii, config.leg_name[ii-1]); ui->legTime_layout->addWidget(lt[ii]); connect (lt[ii], SIGNAL(dataChanged()), this, SLOT(recalculateTimes()) ); } lt[0] = new QmLegTimes(0, "Overall Event"); ui->legTime_layout->addWidget(lt[0]); /* ** Init initial displayed team */ team = initialTeam ? initialTeam : config.min_team; /* ** Connect up various signals */ connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(save()) ); connect(ui->pushButtonRestore, SIGNAL(clicked()), this, SLOT(cancel()) ); connect(ui->teamNumber, SIGNAL(valueChanged(int)), this, SLOT(populate(int)) ); connect(ui->name, SIGNAL(textEdited(QString)), this, SLOT(changed()) ); connect(ui->category , SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); connect(ui->category , SIGNAL(currentIndexChanged(int)), this, SLOT(updateCategory())); connect(ui->members , SIGNAL(cellChanged(int,int)), this, SLOT(changed())); connect(ui->disqualified , SIGNAL(clicked(bool)), this, SLOT(changed())); connect(ui->nonEquestrian , SIGNAL(clicked(bool)), this, SLOT(recalculateTimes())); connect(ui->disabled , SIGNAL(clicked(bool)), this, SLOT(changed())); connect(ui->VetCheck , SIGNAL(clicked(bool)), this, SLOT(changed())); connect(ui->editNote, SIGNAL(clicked()), this, SLOT(editNote())); updateChanged(false); } /*---------------------------------------------------------------------------- ** FUNCTION : ~qmTeamDisplay ** ** DESCRIPTION : Destructor ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ qmTeamDisplay::~qmTeamDisplay() { delete ui; } /*---------------------------------------------------------------------------- ** FUNCTION : showEvent ** ** DESCRIPTION : Slot that is wired into the main windows widget ** It will be called when the main window widget changes ** If this display is the current display, then load new data ** ** INPUTS : index of the tab that now has focus ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::showEvent ( QShowEvent * event ) { //qDebug("showEvent::showEvent"); if ( ! event->spontaneous() ) { if ( ! dirty) { populate(team); } } } /*---------------------------------------------------------------------------- ** FUNCTION : blockSignals ** ** DESCRIPTION : Block signal from widgets that set Changed ** while populating the display ** ** ** INPUTS : state - New blocking state ** ** RETURNS : Nothing ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::blockSignals(bool state) { // ui->pushButtonSave->blockSignals(state); // ui->pushButtonRestore->blockSignals(state); // ui->teamNumber->blockSignals(state); ui->name->blockSignals(state); ui->category->blockSignals(state); ui->members->blockSignals(state); ui->disqualified->blockSignals(state); ui->nonEquestrian->blockSignals(state); ui->disabled->blockSignals(state); ui->VetCheck->blockSignals(state); for ( int ii = 0 ; ii <= MAX_LEGS; ii++) { if (lt[ii]) { lt[ii]->blockSignals(state); } } } /*---------------------------------------------------------------------------- ** FUNCTION : populate ** ** DESCRIPTION : Populate the widget with data ** ** ** INPUTS : team_number - Team number to use ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::populate(int team_number) { if (MainWindow::shutDown) { return; } /* ** Update the spinner that describes the current team number */ populating = true; blockSignals(true); ui->teamNumber->setMaximum(config.max_team); ui->teamNumber->setMinimum(config.min_team); ui->teamNumber->setValue(team_number); team = team_number; /* ** Read in team data ** This will persist within this widget */ g_record( team, &team_buf ); /* ** Basic Data */ ui->name->setText( team_buf.name ); ui->category_abr->setText( config.team_class[team_buf.teamclass - 1].abr ); /* ** ComboBox for Category selection ** Save category index as data inthe combobox ** Do not show the NE category - it should be selected */ ui->category->clear(); int selectedIndex = -1; for ( int ii = 0; ii < config.num_class ; ii++) { if (config.team_class[ii].abr[0] && (config.nonequestrian_class != ii + 1)) { ui->category->addItem(config.team_class[ii].full_name, ii); if (ii == team_buf.teamclass - 1) { selectedIndex = ui->category->count() - 1; //qDebug("ComboIndex:%d",ii); } } } ui->category->setCurrentIndex(selectedIndex); ui->disqualified->setCheckState(team_buf.flags.disqualified ? Qt::Checked : Qt::Unchecked); ui->nonEquestrian->setCheckState(team_buf.flags.non_equestrian ? Qt::Checked : Qt::Unchecked); ui->disabled->setCheckState( !team_buf.flags.valid ? Qt::Checked : Qt::Unchecked); ui->VetCheck->setCheckState( team_buf.flags.vet_check ? Qt::Checked : Qt::Unchecked); /* ** Team Member data ** Name ** Sex ** Age */ int age_sum = 0; for ( int ii = 0; ii < config.num_legs; ii ++) { QTableWidgetItem *item; ui->members->setItem(ii, 0, new QTableWidgetItem(team_buf.members[ii].name) ); item = new QTableWidgetItem(); item->setFlags(Qt::ItemIsTristate | item->flags()); enum Qt::CheckState sex; switch ( team_buf.members[ii].sex ) { case male: sex = Qt::Unchecked; break; case female: sex = Qt::Checked; break; default: sex = Qt::PartiallyChecked; break; } //qDebug("RSex:%d, %d, %d, %d", team, ii, sex, team_buf.members[ii].sex); item->setCheckState(sex ); ui->members->setItem(ii, 1, item ); item = new QTableWidgetItem(); item->setData(Qt::EditRole,team_buf.members[ii].age); ui->members->setItem(ii, 2, item ); /* ** Sum ages ** -1 indicates invalid age */ if ( age_sum >= 0 ) { ushort age = team_buf.members[ii].age; if ( age > 0 && age < 255 ) { age_sum += age; } else { age_sum = -1; } } } ui->members->resizeColumnsToContents(); /* ** Mainatain the display of total age */ if ( age_sum <= 0 ) { ui->totalAge->setText("--"); } else { ui->totalAge->setText(QString::number(age_sum)); } /* ** Leg Times */ for ( int ii = 0 ; ii <= config.num_legs; ii++) { lt[ii]->setData(&team_buf.leg[ii]); } /* ** Team Note */ populateNote(); updateChanged(false); populating = false; blockSignals(false); } void qmTeamDisplay::updateCategory(void) { int currentIndex = ui->category->currentIndex(); if (currentIndex >= 0) { int itemData = ui->category->itemData(currentIndex).toInt(); ui->category_abr->setText( config.team_class[itemData].abr ); } } /*---------------------------------------------------------------------------- ** FUNCTION : recalculateTimes ** ** DESCRIPTION : Recalculate and update all the times for the legs ** ** ** INPUTS : None ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::recalculateTimes( void ) { for ( int ii = 0 ; ii <= config.num_legs; ii++) { lt[ii]->getData(&team_buf.leg[ii]); } suckData(); set_times( &team_buf ); test_times( &team_buf, 0 ); for ( int ii = 0 ; ii <= config.num_legs; ii++) { lt[ii]->setData(&team_buf.leg[ii]); } // Flag data as changed changed(); } /*---------------------------------------------------------------------------- ** FUNCTION : suckData ** ** DESCRIPTION : Save the data back to memory ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::suckData(void) { /* ** Extract data from the widgets ** The time stuff is done on the fly as it changes */ strncpy(team_buf.name , qPrintable(ui->name->text()), sizeof(team_buf.name)); int currentIndex = ui->category->currentIndex(); if (currentIndex >= 0) { int itemData = ui->category->itemData(currentIndex).toInt(); team_buf.teamclass = itemData + 1; } team_buf.flags.disqualified = ( ui->disqualified->checkState () == Qt::Checked); team_buf.flags.non_equestrian = ( ui->nonEquestrian->checkState () == Qt::Checked); team_buf.flags.valid = ( ui->disabled->checkState () != Qt::Checked); team_buf.flags.vet_check = ( ui->VetCheck->checkState () == Qt::Checked); /* ** Extract Team Member Data */ for ( int ii = 0; ii < config.num_legs; ii ++) { QTableWidgetItem *item; item = ui->members->item ( ii, 0 ); strncpy(team_buf.members[ii].name , qPrintable(item->text()), sizeof(team_buf.members[ii].name)); //TODO: Make Sex edit work item = ui->members->item ( ii, 1 ); enum Qt::CheckState sex = item->checkState(); switch (sex) { case Qt::Unchecked: team_buf.members[ii].sex = male; break; case Qt::Checked: team_buf.members[ii].sex = female; break; default: team_buf.members[ii].sex = unknown; break; } //qDebug("WSex:%d, %d, %d, %d", team, ii, sex, team_buf.members[ii].sex); item = ui->members->item ( ii, 2 ); team_buf.members[ii].age = item->data(Qt::EditRole).toInt(); } } /*---------------------------------------------------------------------------- ** FUNCTION : save ** ** DESCRIPTION : Save the data back to disk ** Also called if nothing to save - ie Done Mode ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::save(void) { if ( dirty ) { /* ** Save the record back to disk */ suckData(); put_team_record( team, &team_buf ); populate(team); } else { if ( enableDone ) emit dialogDone(1); } } /*---------------------------------------------------------------------------- ** FUNCTION : cancel ** ** DESCRIPTION : Kill of any edited data ** Redisplay the team data ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::cancel(void) { populate(team); } void qmTeamDisplay::changed(void) { //QObject * who = sender () ; //qDebug ("Changed: %p", who); if (populating) return; updateChanged(true); } void qmTeamDisplay::updateChanged(bool newDirty) { //qDebug("updateChanged: %d, %d -> %d", populating, dirty, newDirty ); if (newDirty != dirty) { dirty = newDirty; if (dirty) { ui->Changed->setVisible(true); ui->teamNumber->setEnabled(false); ui->pushButtonSave->setEnabled(true); ui->pushButtonSave->setStyleSheet("background-color: rgb(255, 0, 0);"); ui->pushButtonSave->setText("Save"); // Only valid when within a dialog // Now have the dialog swallow //ui->pushButtonSave->setDefault(true); } else { ui->Changed->setVisible(false); ui->teamNumber->setEnabled(true); //ui->pushButtonSave->setEnabled(false); ui->pushButtonSave->setStyleSheet(""); if ( enableDone ) ui->pushButtonSave->setText("Done"); } } } /*---------------------------------------------------------------------------- ** FUNCTION : changeEvent ** ** DESCRIPTION : ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::changeEvent(QEvent *e) { //qDebug("qmTeamDisplay ChangeEvent: %d",e->type()); QWidget::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } /*---------------------------------------------------------------------------- ** FUNCTION : populateNote ** ** DESCRIPTION : Populate the Note area of the team display ** Must be called during populate as ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::populateNote(void) { noteFileName = "TeamNote_" + QString::number(team) + ".txt"; //qDebug("NoteFile:%s",qPrintable(noteFileName)); // Clear combobox before we add text ui->noteText->clear(); QFile noteFile(QString(filepath) + noteFileName); if ( noteFile.open( QIODevice::ReadOnly ) ) { QTextStream stream( ¬eFile ); QString line; do { line = stream.readLine(); if (line.isNull()) break; ui->noteText->addItem(line); } while (true); noteFile.close(); } ui->noteText->setStyleSheet( ui->noteText->count() ? "background-color: #FFFFCB;" : ""); /* ** Delete empy files to keep things clean */ if (noteFile.size() == 0 ) { noteFile.remove(); } } /*---------------------------------------------------------------------------- ** FUNCTION : editNote ** ** DESCRIPTION : Edit the Team Note in a modal dialog box ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void qmTeamDisplay::editNote(void) { QmEditAddendum dialog(QmConfig::getAddendemFile(noteFileName, true), true); dialog.exec(); populateNote(); }