Subversion Repositories svn1-original

Rev

Rev 381 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "qmdialogloadexternalteams.h"
//#include "ui_qmdialogloadexternalteams.h"
#include "QFile"
#include "QTextStream"
#include "mainwindow.h"
#include <QRegExp>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWidget>
#include <QHeaderView>
#include <QtWebKit/QtWebKit>

#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" <<e.tagName() << ":" << e.toPlainText();
        //qDebug("-----Row");
        bool has_RefError = hasRefError(e.toPlainText());

        QWebElementCollection td = e.findAll("td");
        QStringList parts;
        
        foreach(QWebElement e, td)
        {
            //qDebug()<< e.tagName() << ":" << e.toPlainText();
            parts.append(e.toPlainText());
        }
        insertParts( parts, has_RefError );
    }

    // Post Load fix up
    tableWidget->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 <<endl;
        }
    }
}

QStringList QmDialogLoadExternalTeams::splitCsvData( const QString str)
{
    QStringList results;

    const QChar *data = str.constData();
    while (!data->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 <<endl;
        }
    }
}

QString QmDialogLoadExternalTeams::toCsv(const QString &str)
{
    QString result = QString(str);
    if ( result.contains("\"") || result.contains(",") )
    {
        result.replace("\"", "\"\"");
        result.prepend("\"");
        result.append("\"");
    }
    return result;
}

QString QmDialogLoadExternalTeams::toCsv(const int data)
{
    return QString::number(data);
}