#include "qmdialogloadexternalteams.h" //#include "ui_qmdialogloadexternalteams.h" #include "QFile" #include "QTextStream" #include "mainwindow.h" #include #include #include #include #include #include #include "consts.h" #include "structs.h" #include "proto.h" /*---------------------------------------------------------------------------- ** FUNCTION : QmDialogLoadExternalTeams ** ** DESCRIPTION : Load team data from a CSV file ** ** ** INPUTS : efile - name of file ** parent - parent widget ** ** RETURNS : ** ----------------------------------------------------------------------------*/ QmDialogLoadExternalTeams::QmDialogLoadExternalTeams(const QString &efile,QWidget *parent) : QDialog(parent) { // // Create Windows // createWindow(); fileName->setText(efile); // Open the users file QFile file(efile); if ( ! file.open(QIODevice::ReadOnly | QIODevice::Text) ) { MainWindow::showMessage("Cannot open external data file"); return; } MainWindow::showMessage("Loading External Data"); // Process Each line of the file QTextStream in(&file); QRegExp csv_split("\"?,\"?"); while (!in.atEnd()) { QString line = in.readLine(); line = line.trimmed(); // Remove leading and training White Space line.remove(0xA0); // M$ special uglyness line.remove(0xC2); // M$ special uglyness bool has_RefError = hasRefError(line); QStringList parts = splitCsvData(line); insertParts( parts, has_RefError ); } // Post Load fix up tableWidget->resizeColumnsToContents(); reportErrors( bad_cat, bad_refs); } /*---------------------------------------------------------------------------- ** FUNCTION : QmDialogLoadExternalTeams ** ** DESCRIPTION : Load team data from a Web Page ** ** ** INPUTS : efile - name of file (display only) ** data - Address of the webpage data loaded in memory ** parent - parent widget ** ** RETURNS : ** ----------------------------------------------------------------------------*/ QmDialogLoadExternalTeams::QmDialogLoadExternalTeams(const QString &efile, QByteArray *data ,QWidget *parent) : QDialog(parent) { // Create the basic Window createWindow(); fileName->setText(efile); // Parse the data. It is an html file // MainWindow::showMessage("Parsing HTML"); //qDebug("Data size: %d", data->length()); QWebPage page; QWebFrame * frame = page.mainFrame(); frame->setContent(*data); /* ** Get the first table ** Get all rows ** Get all data items in each row */ QWebElement document = frame->documentElement(); QWebElement firstTable = document.findFirst("table"); QWebElementCollection elements = firstTable.findAll("tr"); foreach(QWebElement e, elements){ //qDebug()<< "e element" <resizeColumnsToContents(); reportErrors( bad_cat, bad_refs); } /*---------------------------------------------------------------------------- ** FUNCTION : createWindow ** ** DESCRIPTION : Create the basic window ** Used in multiple places ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void QmDialogLoadExternalTeams::createWindow(void) { bad_cat = 0; bad_refs = 0; resize(550, 500); setSizeGripEnabled(true); setWindowTitle("Load External Team Data"); QVBoxLayout *verticalLayout; verticalLayout = new QVBoxLayout(this); verticalLayout->setContentsMargins(0, 0, 0, 0); QVBoxLayout *verticalLayout2; verticalLayout2 = new QVBoxLayout(); verticalLayout2->setContentsMargins(5, 5, 5, 5); QHBoxLayout *horizontalLayout; horizontalLayout = new QHBoxLayout(); groupBox = new QGroupBox(this); groupBox->setTitle("Data"); verticalLayout->addWidget(groupBox); groupBox->setLayout(verticalLayout2); tableWidget = new QTableWidget(groupBox); tableWidget->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); tableWidget->setGeometry(QRect(15, 21, 501, 421)); tableWidget->setCornerButtonEnabled(false); tableWidget->verticalHeader()->setVisible(false); tableWidget->verticalHeader()->setDefaultSectionSize(20); tableWidget->verticalHeader()->setHighlightSections(true); verticalLayout2->addWidget(tableWidget); fileName = new QLineEdit(this); fileName->setObjectName(QString::fromUtf8("fileName")); fileName->setGeometry(QRect(20, 470, 331, 20)); fileName->setReadOnly(true); horizontalLayout->addWidget(fileName); load = new QPushButton(this); load->setObjectName(QString::fromUtf8("load")); load->setGeometry(QRect(370, 470, 75, 23)); load->setText("Load"); horizontalLayout->addWidget(load); cancel = new QPushButton(this); cancel->setObjectName(QString::fromUtf8("cancel")); cancel->setGeometry(QRect(460, 470, 75, 23)); cancel->setAutoDefault(false); cancel->setText("Cancel"); horizontalLayout->addWidget(cancel); verticalLayout->addLayout(horizontalLayout); // Insert column headers tableWidget->setColumnCount(3 + ( 2 * config.num_legs) ); QStringList labels; labels << "Team" << "Team Name" << "Cat"; for (int ii = 1; ii <= config.num_legs; ii++ ) { labels += QString("Leg:%1").arg(QString::number(ii)); labels += QString("Age:%1").arg(QString::number(ii)); } tableWidget->setHorizontalHeaderLabels(labels); // Connect up buttons connect (load, SIGNAL(clicked()), this, SLOT(loadData())); connect(cancel, SIGNAL(clicked()), this, SLOT(close())); } /*---------------------------------------------------------------------------- ** FUNCTION : insertParts ** ** DESCRIPTION : Insert raw data into the display table ** ** ** INPUTS : parts - Ref to a list of parts ** has_RefError - Data has Ref Error ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void QmDialogLoadExternalTeams::insertParts(QStringList &parts, bool has_RefError) { QString first = parts.value(0); bool ok; if ( first.isEmpty() ) return; int team = first.toInt(&ok); if ( ! ok || team <= 0 ) return; int ii = tableWidget->rowCount(); tableWidget->setRowCount(1 + ii ); // Insert Team number QTableWidgetItem *item = new QTableWidgetItem(first); tableWidget->setItem(ii, 0, item ); parts.removeFirst(); if ( has_RefError ) { item->setBackgroundColor(QColor(0,0,200,50)); bad_refs++; } // Extract Team Name item = new QTableWidgetItem( parts.value(0) ); tableWidget->setItem(ii, 1, item ); if ( hasRefError(parts.value(0)) ) { item->setBackgroundColor(QColor(0,0,200,50)); } parts.removeFirst(); // Extract Team Cat item = new QTableWidgetItem( parts.value(0)) ; tableWidget->setItem(ii, 2, item ); if (config.lookup_class(qPrintable(parts.value(0)) ) <= 0 ) { item->setBackgroundColor(QColor(200,0,0,50)); bad_cat++; } if ( hasRefError(parts.value(0)) ) { item->setBackgroundColor(QColor(0,0,200,50)); } parts.removeFirst(); int yy = 0; while ( parts.count() > 0) { // Name of competitor item = new QTableWidgetItem( parts.value(0)); tableWidget->setItem(ii, 3+yy, item); if ( hasRefError(parts.value(0)) ) { item->setBackgroundColor(QColor(0,0,200,50)); } parts.removeFirst(); // Not loading age at the moment // Reason: The CSV file is being create with a '0' for the NE teams #if DO_AGE_LOAD // Posible age - if its a number int age = parts.value(0).toInt(&ok); if ( ok ) { if ( age > 0 ) { tableWidget->setItem(ii, 4+yy, new QTableWidgetItem( parts.value(0))); } parts.removeFirst(); } #endif yy += 2; } } /*---------------------------------------------------------------------------- ** FUNCTION : ~QmDialogLoadExternalTeams ** ** DESCRIPTION : Class destructor ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ QmDialogLoadExternalTeams::~QmDialogLoadExternalTeams() { } /*---------------------------------------------------------------------------- ** FUNCTION : loadData ** ** DESCRIPTION : Store the data from the table into the database ** ** ** INPUTS : ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void QmDialogLoadExternalTeams::loadData(void) { qDebug ("LoadData"); team_type team_buf; int bad_cat = 0; int bad_refs = 0; for ( int ii = 0; ii < tableWidget->rowCount(); ii++) { if ( tableWidget->isRowHidden(ii)) { continue; } bool bad = false; QTableWidgetItem *item; item = tableWidget->item(ii,0); if (item) { int team = item->data(Qt::EditRole).toInt(); if ( team > 0 && team <= config.max_team ) { g_record( team, &team_buf ); // Name item = tableWidget->item(ii,1); if (item) { strncpy(team_buf.name , qPrintable(item->data(Qt::EditRole).toString()), sizeof(team_buf.name)); } // Category item = tableWidget->item(ii,2); if (item) { int category = config.lookup_class(qPrintable(item->data(Qt::EditRole).toString()) ); if (category) { team_buf.teamclass = category; } else { bad_cat++; bad = true; } } // Team member names and ages int member = 0; for (int yy = 3; yy < tableWidget->columnCount(); yy+= 2, member++) { if (member > config.num_legs) { break; } item = tableWidget->item(ii,yy); if (item) { strncpy(team_buf.members[member].name , qPrintable(item->data(Qt::EditRole).toString()), sizeof(team_buf.members[member].name)); if ( hasRefError(item->data(Qt::EditRole).toString()) ) { bad = true; bad_refs++; } } item = tableWidget->item(ii,1+yy); if (item) { int age = item->data(Qt::EditRole).toInt(); if (age) { team_buf.members[member].age = age; } } } team_buf.flags.valid = TRUE; put_team_record( team, &team_buf ); } else { bad = true; } } else { bad = true; } if (!bad) { tableWidget->hideRow(ii); } } // Report errors reportErrors( bad_cat, bad_refs); } /*---------------------------------------------------------------------------- ** FUNCTION : reportErrors ** ** DESCRIPTION : Report errors on the main window ** ** ** INPUTS : bad_cat - count of category erors ** bad_refs - count of Reference errors ** ** RETURNS : ** ----------------------------------------------------------------------------*/ void QmDialogLoadExternalTeams::reportErrors( int bad_cat, int bad_refs ) { if ( bad_cat && bad_refs ) { MainWindow::showMessage("Invalid Categories in data and bad REFs"); } else if (bad_cat) { MainWindow::showMessage("Invalid Categories in data"); } else if (bad_refs) { MainWindow::showMessage("Imported data has bad REFs"); } } /*======================================================================== * * Generate team name file * * Purpose: * This function is called to Generate team name file in the format * that can be read by the load command * * The file contains team number,Team name,Team class * The operator is prompted to enter the name of the file * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void QmDialogLoadExternalTeams::storeData(const QString &efile) { QFile file(efile); if ( ! file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) ) { MainWindow::showMessage("Cannot open external data file"); return; } QTextStream out(&file); // Print headings out << toCsv("Team Number"); out << "," << toCsv("Team Name"); out << "," << toCsv("Class Abr"); for( int j = 1; j <= config.num_legs; j++ ) { out << "," << toCsv("Competitor Name"); out << "," << toCsv("Age"); } out << endl; /* * Put the data into the file */ team_type team_buf; for(int i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { /* ** Basic information ** - Team number ** - Full team name */ out << toCsv(team_buf.numb); out << "," << toCsv(team_buf.name); out << "," << toCsv(team_buf.teamclass == 0 ? "" : config.team_class[team_buf.teamclass - 1].abr); for(int j = 1; j <= config.num_legs; j++ ) { out << "," << toCsv(team_buf.members[j-1].name); out << "," << toCsv(team_buf.members[j-1].age); } out <isNull()) { QString result; bool quoted = false; /* ** Extract the next record */ while ( TRUE ) { QChar uch = *data; /* ** End of the field */ if ( uch == '\n' || uch == '\r' || uch == '\0' ) break; data++; /* ** Ugly character from MS CSV files ** Not too sure what the 194 is. It looks like a 0xA0 in the raw data */ if ( uch == (char) 0xA0 || uch == (char)194 ) { continue; } if ( !quoted && uch == ',' ) { break; } /* ** An unquoted " will start scanning for a matching quote */ if ( !quoted && uch == '"' ) { quoted = true; continue; } /* ** A quoted " may be an embedded quote or the end of a quote */ if ( quoted && uch == '"' ) { if ( *data != '"' ) { quoted = FALSE; continue; } /* ** Skip one " and pick up the next */ ++data; } /* ** Save this character */ result += uch; } /* ** Clean up the extracted string */ results += result.trimmed(); } return results; } /*---------------------------------------------------------------------------- ** FUNCTION : hasRefError ** ** DESCRIPTION : Determine if a string contains an Excel Reference ** error: #REF! ** ** ** INPUTS : data - String to test ** ** RETURNS : True: Is an error ** ----------------------------------------------------------------------------*/ bool QmDialogLoadExternalTeams::hasRefError( const QString data) { return data.contains("#REF!"); } /*======================================================================== * * Generate team name file * * Purpose: * This function is called to Generate team name file * * The file contains team number,Team name,Team class * The operator is prompted to enter the name of the file * * Parameters: * None * * Returns: * Nothing * *========================================================================*/ void QmDialogLoadExternalTeams::storeTeamInfo(const QString &efile) { QFile file(efile); if ( ! file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) ) { MainWindow::showMessage("Cannot open external team info file"); return; } QTextStream out(&file); /* * Put the data into the file */ team_type team_buf; for(int i = config.min_team; i <= config.max_team; i++ ) { if( valid_field( i ) && g_record( i, &team_buf ) ) { /* ** Basic information ** - Team number ** - Full team name ** - Category */ out.setFieldAlignment(QTextStream::AlignLeft); out.setFieldWidth(5); out << team_buf.numb; out.setFieldWidth(0); out << ","; out.setFieldWidth(MAX_TM_NAME+1); out << team_buf.name; out.setFieldWidth(0); out << ","; out << (team_buf.teamclass <= 0 ? "" : config.team_class[team_buf.teamclass - 1].abr); out <