Subversion Repositories svn1

Rev

Rev 388 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
172 - 1
#include "qmconfig.h"
2
#include "mainwindow.h"
3
#include <QFileDialog>
4
#include <QObject>
5
#include <QMessageBox>
174 - 6
#include <QFileInfo>
7
#include <QFile>
199 david 8
#include <QCoreApplication>
380 david 9
#include <QSettings>
172 - 10
 
210 - 11
//#define DISPLAY_STRUCTURES
208 - 12
 
172 - 13
// Global Data
176 - 14
QmConfig    config;
172 - 15
 
380 david 16
// Application Config
17
//  Only use this to store user setting
18
//  Thinks like : 
19
//      Last path for loaded file
20
//      Last entered uploaded leg
21
//      Swim Start: Leg Set up Delta and base
176 - 22
 
380 david 23
QSettings   *appSettings = NULL;
24
 
25
 
174 - 26
/*
27
**  Local definitions
28
*/
389 david 29
QString     DatFile;                            /* Name of the data file */
30
QString     FileBase;                           /* Event file name base */
31
QString     FilePath;
172 - 32
 
380 david 33
/*----------------------------------------------------------------------------
34
** FUNCTION           : QmConfig 
35
**
36
** DESCRIPTION        : Constructor
37
**
38
**
39
** INPUTS             :
40
**
41
----------------------------------------------------------------------------*/
199 david 42
 
380 david 43
QmConfig::QmConfig(void)
44
{
45
}
46
 
47
/*----------------------------------------------------------------------------
48
** FUNCTION           : ~QmConfig
49
**
50
** DESCRIPTION        : Destructor
51
**
52
**
53
----------------------------------------------------------------------------*/
54
 
55
QmConfig::~QmConfig()
56
{
57
    /*
58
    ** This will force the items to be flushed
59
    */
60
    if (appSettings)
61
    {
62
        delete(appSettings);
63
        appSettings = NULL;
64
    }
65
}
66
 
176 - 67
void QmConfig::load(const QString &cnfFile)
172 - 68
{
208 - 69
#ifdef DISPLAY_STRUCTURES
70
    display_structures();
71
#endif
172 - 72
    fileName = cnfFile;
199 david 73
 
172 - 74
    if ( !fileName.endsWith(".cnf",Qt::CaseInsensitive))
75
    {
76
        fileName.append(".cnf");
77
    }
78
    if (cnfFile.isEmpty())
79
    {
80
        fileName = QFileDialog::getOpenFileName(0, "Select Config File",
389 david 81
                                                         FilePath,
387 david 82
                                                         "Data (*.cnf);;All (*.*)"
172 - 83
                                                         );
84
    }
85
 
86
    //  No file selected
87
    //  Just exit
88
    if (fileName.isEmpty())
89
    {
174 - 90
        qDebug("No Config file selected");
172 - 91
        exit(1);
92
    }
93
 
174 - 94
    //
227 - 95
    //  Setup file names
174 - 96
    //
97
    QFileInfo info (fileName);
389 david 98
    FileBase = info.baseName();
99
    DatFile = FileBase + ".dat";
174 - 100
 
389 david 101
    FilePath = info.absolutePath() + "/";
174 - 102
 
389 david 103
    qDebug() << "FilePath:" << FilePath;
104
    qDebug() << "FileBase:" << FileBase;
105
    qDebug() << "DatFile:" << DatFile;
106
 
107
 
388 david 108
    // Locate the .ini file used to store additional information
109
    appSettings = new QSettings(getAddendemFile("mara.ini", true), QSettings::IniFormat);
389 david 110
    //qDebug() << "AppSetting: " << appSettings->fileName();
388 david 111
 
172 - 112
    if ( !open_read_config() )
113
    {
114
        if (QMessageBox::Cancel == QMessageBox::question ( 0,
115
                                                       "Config Load Error",
116
                                                       "Cannot load or read configuration file.\n"
117
                                                       "If you continue a new configuration will be created\n"
118
                                                       "If you cancel then the application will terminate.",
119
                                                       QMessageBox::Ok | QMessageBox::Cancel
120
                                                       ) )
121
        {
174 - 122
            qDebug("Cancel to bad config");
172 - 123
            exit(2);
124
        }
125
    }
126
}
127
 
128
 
129
bool QmConfig::open_read_config( void )
130
{
131
    bool result;
132
    // Open the file
176 - 133
    QFile configFile;
172 - 134
    configFile.setFileName(fileName);
135
    if ( ! configFile.open(QIODevice::ReadOnly) )
136
    {
137
        MainWindow::showMessage("Cannot open config File");
138
        return (false );
139
    }
140
 
176 - 141
    result = read_config(configFile);
172 - 142
    configFile.close();
143
 
144
    if ( result )
145
    {
146
        /*
227 - 147
        **  Post read calculations and fixups
148
        */
176 - 149
        if( datafilename[0] )
172 - 150
        {
389 david 151
            DatFile = QString(datafilename);
152
            DatFile.append(".dat");
172 - 153
        }
176 - 154
        nonequestrian_class = lookup_class( nonequestrian_class_abr );
227 - 155
 
156
        class_ne_winners_by_class = false;
157
        for( int i = 0; i < MAX_CLASS; i++ )
158
        {
159
           if(class_ne_winners[i])
160
           {
161
               class_ne_winners_by_class = true;
162
               break;
163
           }
164
        }
165
 
166
 
172 - 167
    }
168
    return result;
169
}
170
 
171
/*========================================================================
172
 *
173
 *  Read in the configuration file
174
 *
175
 *  Purpose:
176
 *      This function is called to read in the configuration file
177
 *      NOTE: Must be maintained with the Writer function
178
 *
179
 *  Parameters:
180
 *      fcon        File number of the config file
181
 *
182
 *  Returns:
183
 *      FALSE if an error is encountered
184
 *
185
 *========================================================================*/
186
 
176 - 187
bool QmConfig::read_config( QFile &configFile  )
172 - 188
{
189
    int         len;                            /* Length of data read */
190
    int         fsize;                          /* Length of desired data */
191
 
384 david 192
//    qDebug("Reading config");
193
//    qDebug () << "Size of maraTime_t:" << sizeof(maraTime_t) << "\n";
172 - 194
    /*
195
     * Event name
196
     */
210 - 197
//qDebug( "Reading: Event Name" );
176 - 198
    fsize = sizeof( event_name );
199
    len = configFile.read( event_name, fsize );
172 - 200
    if( len != fsize )
201
        return ( FALSE );
202
 
203
    /*
204
     * Leg names
205
     */
210 - 206
//qDebug( "Reading: Leg Names" );
176 - 207
    fsize = sizeof( leg_name );
208
    len = configFile.read( (char *)leg_name, fsize );
172 - 209
    if( len != fsize )
210
        return ( FALSE );
211
 
212
    /*
213
     * Team definitions
214
     */
210 - 215
//qDebug( "Reading: Team Defs" );
176 - 216
    fsize = sizeof( t_def  );
217
    len = configFile.read( (char *)t_def, fsize );
172 - 218
    if( len != fsize )
219
        return ( FALSE );
220
 
221
    /*
222
     * Number of legs
223
     */
210 - 224
//qDebug( "Reading: Leg Nums" );
176 - 225
    fsize = sizeof( num_legs  );
226
    len = configFile.read( (char *)&num_legs, fsize );
172 - 227
    if( len != fsize)
228
        return ( FALSE );
229
 
230
    /*
231
     * Number of team splits
232
     */
210 - 233
//qDebug( "Reading: Team Splits" );
176 - 234
    fsize = sizeof( num_teams  );
235
    len = configFile.read( (char *)&num_teams, fsize );
172 - 236
    if( len != fsize )
237
        return ( FALSE );
238
 
176 - 239
    min_team = t_def[0].start;
240
    max_team = t_def[num_teams - 1].end;
172 - 241
 
242
    /*
243
     * Class information
244
     */
210 - 245
//qDebug( "Reading: Class Data" );
176 - 246
    fsize = sizeof( team_class  );
247
    len = configFile.read( (char *)team_class, fsize );
172 - 248
    if( len != fsize )
249
        return ( FALSE );
176 - 250
    fsize = sizeof( num_class  );
251
    len = configFile.read( (char *)&num_class, fsize);
172 - 252
    if( len != fsize )
253
        return ( FALSE );
254
 
255
    /*
256
     * Country list
257
     */
210 - 258
//qDebug( "Reading: Country Data, Name" );
176 - 259
    fsize = sizeof( country_name  );
260
    len = configFile.read( (char *)country_name, fsize );
172 - 261
    if( len != fsize )
262
        return ( FALSE );
263
 
210 - 264
//qDebug( "Reading: Country Data, Number" );
176 - 265
    fsize = sizeof( num_countries  );
266
    len = configFile.read( (char *)&num_countries, fsize );
172 - 267
    if( len != fsize )
268
        return ( FALSE );
269
 
270
    /*
271
     * Addendum file
272
     */
210 - 273
//qDebug( "Reading: Addendum File" );
176 - 274
    fsize = sizeof( addendum );
275
    len = configFile.read( addendum, fsize );
172 - 276
    if( len != fsize )
277
        return ( configFile.atEnd() );
278
 
279
    /*
280
     * Name of the data file
281
     */
282
 
210 - 283
//qDebug( "Reading: Name of data file" );
176 - 284
    fsize = sizeof( datafilename );
285
    len = configFile.read( datafilename, fsize );
172 - 286
    if( len != fsize )
287
        return ( configFile.atEnd() );
288
 
289
    /*
290
     **  Non-equestrian configuration information
291
     */
210 - 292
//qDebug( "Reading: NonEquest" );
176 - 293
    fsize = sizeof( nonequestrian_class_abr );
294
    len = configFile.read( nonequestrian_class_abr, fsize );
172 - 295
    if( len != fsize )
296
        return ( configFile.atEnd() );
297
 
210 - 298
//qDebug( "Reading: NonEquest-2" );
176 - 299
    fsize = sizeof( equestrian_leg );
300
    len = configFile.read( (char *)&equestrian_leg, fsize );
172 - 301
    if( len != fsize )
302
        return ( FALSE );
303
 
304
    /*
305
    **  .txt file output control. Lines per page and perf-skipping
306
    */
210 - 307
//qDebug( "Reading: Output Control" );
176 - 308
    fsize = sizeof( lines_per_page );
309
    len = configFile.read( (char *)&lines_per_page, fsize );
172 - 310
    if( len != fsize )
311
        return ( configFile.atEnd() );
312
 
210 - 313
//qDebug( "Reading: Output Control-2" );
176 - 314
    fsize = sizeof( perf_skip );
315
    len = configFile.read( (char *)&perf_skip, fsize );
172 - 316
    if( len != fsize )
317
        return ( FALSE );
318
 
210 - 319
//qDebug( "Reading: Winners Info" );
176 - 320
    fsize = sizeof( class_winners );
321
    len = configFile.read( (char *)&class_winners, fsize );
172 - 322
    if( len != fsize )
323
        return ( FALSE );
324
 
210 - 325
//qDebug( "Reading: Hall of Fame Info" );
176 - 326
    fsize = sizeof( hall_fame );
327
    len = configFile.read( (char *)&hall_fame, fsize );
172 - 328
    if( len != fsize )
329
        return ( FALSE );
330
 
210 - 331
//qDebug( "Reading: Hall of Fame Numbers" );
208 - 332
    fsize = sizeof( num_fame );
176 - 333
    len = configFile.read( (char *)&num_fame, fsize );
172 - 334
    if( len != fsize )
335
        return ( configFile.atEnd() );
336
 
227 - 337
//qDebug( "Reading: NE Winners Info" );
380 david 338
    fsize = sizeof( class_ne_winners );
339
    len = configFile.read( (char *)&class_ne_winners, fsize );
340
    if( len != fsize )
341
         return ( configFile.atEnd() );
172 - 342
 
380 david 343
//qDebug( "Reading: Web Import Url" );
344
    fsize = sizeof( webUrl );
345
    len = configFile.read( (char *)&webUrl, fsize );
346
    if( len != fsize )
347
        return ( configFile.atEnd() );
348
 
349
//qDebug( "Reading: Awards Text File" );
350
    fsize = sizeof( awardsfilename );
351
    len = configFile.read( (char *)&awardsfilename, fsize );
352
    if( len != fsize )
353
        return ( configFile.atEnd() );
354
 
172 - 355
    return ( TRUE );
356
}
357
 
199 david 358
/*----------------------------------------------------------------------------
359
** FUNCTION           : getAddendemFile
360
**
361
** DESCRIPTION        : Returns the full path the the addemdum file
380 david 362
**                      The function will look for the file in a number of
199 david 363
**                      locations
364
**
365
**
366
** INPUTS             : name    - Name of the addenum file
367
**                      create  - True. Allow file to be created
368
**
369
** RETURNS            : NULL    - No addendum name, or file not found
370
**                                If create' is true then the preferred
371
**                                location will be returned.
372
**
373
----------------------------------------------------------------------------*/
172 - 374
 
199 david 375
 
380 david 376
const QString QmConfig::getAddendemFile(const QString &name, bool create )
199 david 377
{
378
    if (name.isEmpty())
379
        return NULL;
380
 
381
    QFile file;
382
    QString addendumFileName;
389 david 383
    addendumFileName = FilePath;
199 david 384
    addendumFileName.append(name);
385
    QString addendumFileNamePreferred(addendumFileName);
386
    file.setFileName(addendumFileName);
200 david 387
    //qDebug("Try:%s", qPrintable(addendumFileName));
199 david 388
    if ( !file.exists())
389
    {
390
        addendumFileName = QCoreApplication::applicationDirPath ();
391
        addendumFileName.append("/");
392
        addendumFileName.append(name);
393
        file.setFileName(addendumFileName);
200 david 394
        //qDebug("Try:%s", qPrintable(addendumFileName));
199 david 395
        if ( !file.exists())
396
        {
397
             addendumFileName = QDir::currentPath ();
398
             addendumFileName.append("/");
399
             addendumFileName.append(name);
400
             file.setFileName(addendumFileName);
200 david 401
             //qDebug("Try:%s", qPrintable(addendumFileName));
199 david 402
             if ( !file.exists())
403
             {
200 david 404
                 //qDebug("Addeddum File not found");
199 david 405
                 if (create)
406
                 {
407
                     addendumFileName = addendumFileNamePreferred;
408
                 }
409
                 else
410
                 {
411
                     return NULL;
412
                 }
413
             }
414
        }
415
    }
380 david 416
    return addendumFileName;
199 david 417
}
418
 
172 - 419
/*========================================================================
420
 *
421
 *  Write out the configuration file
422
 *
423
 *  Purpose:
424
 *      This function is called to write the configuration file
425
 *      NOTE: Must be maintained with the Reader function
426
 *
427
 *  Parameters:
428
 *      None
429
 *
430
 *  Returns:
431
 *      FALSE   : Error encountered
432
 *
433
 *========================================================================*/
434
 
435
bool QmConfig::write_config( void )
436
{
174 - 437
    if (fileName.isEmpty())
438
    {
439
        qDebug("No Config file selected");
440
        return(false);
441
    }
172 - 442
    /*
443
     **  Open as a binary file
444
     */
174 - 445
    QFile file;
446
    file.setFileName(fileName);
172 - 447
    if ( ! file.open(QIODevice::WriteOnly | QIODevice::Truncate) )
448
    {
174 - 449
        qDebug("File error: %s", qPrintable(file.errorString()));
218 david 450
        MainWindow::showMessage("Cannot write config file");
172 - 451
        return (false);
452
    }
453
 
454
     /*
455
     **  Write out multiple structures
456
     **     Event name
457
     **     Leg names
458
     **     Team definitions
459
     **     Number of legs
460
     **     Number fo team splits
461
     **     Class information
462
     **     Number of defined classes
463
     **     Country list
464
     **     Number of defined countries
176 - 465
     **     Legend addendum file name
172 - 466
     **     Data file name
467
     */
468
 
176 - 469
    file.write( (const char *) event_name, sizeof( event_name ) );
470
    file.write( (const char *) leg_name, sizeof( leg_name ) );
471
    file.write( (const char *) t_def, sizeof( t_def ) );
472
    file.write( (const char *) &num_legs, sizeof( num_legs ) );
473
    file.write( (const char *) &num_teams, sizeof( num_teams ) );
474
    file.write( (const char *) team_class, sizeof( team_class ) );
475
    file.write( (const char *) &num_class, sizeof( num_class ) );
476
    file.write( (const char *) country_name, sizeof( country_name ) );
477
    file.write( (const char *) &num_countries, sizeof( num_countries ) );
478
    file.write( (const char *) addendum, sizeof( addendum ) );
479
    file.write( (const char *) datafilename, sizeof( datafilename ) );
480
    file.write( (const char *) nonequestrian_class_abr, sizeof( nonequestrian_class_abr ) );
481
    file.write( (const char *) &equestrian_leg, sizeof( equestrian_leg ) );
482
    file.write( (const char *) &lines_per_page, sizeof( lines_per_page ) );
483
    file.write( (const char *) &perf_skip, sizeof( perf_skip ) );
484
    file.write( (const char *) &class_winners, sizeof( class_winners ) );
485
    file.write( (const char *) &hall_fame, sizeof( hall_fame ) );
486
    file.write( (const char *) &num_fame, sizeof( num_fame ) );
227 - 487
    file.write( (const char *) &class_ne_winners, sizeof( class_ne_winners ) );
380 david 488
    file.write( (const char *) &webUrl, sizeof( webUrl ) );
489
    file.write( (const char *) &awardsfilename, sizeof( awardsfilename ) );
172 - 490
 
491
    file.close();
492
    return ( TRUE );
493
}
174 - 494
 
495
/*========================================================================
496
 *
497
 *  Qsort callback: Sort by team
498
 *
499
 *  Purpose:
500
 *      Function used by the team definition sort operation
501
 *      It will compare two entries of the team def structure and return an
502
 *      integer for gt eq lt conditions.
503
 *      Note : If the start is 0 the team entry does exist and is placed at the
504
 *      end of the sorted list.
505
 *
506
 *  Parameters:
507
 *      a           comparision entry
508
 *      b           comparision entry
509
 *
510
 *  Returns:
511
 *      gt, eq, lt as required
512
 *
513
 *========================================================================*/
514
 
515
int f_comp_int( const void *aa, const void *bb )
516
{
517
    const ty_t_def *a = (ty_t_def *)aa;
518
    const ty_t_def *b = (ty_t_def *)bb;
519
 
520
    if( a->start == 0 )
521
        return ( 1 );
522
    else if( b->start == 0 )
523
        return ( -1 );
524
    else
525
        return ( a->start - b->start );
526
}
527
 
528
/*========================================================================
529
 *
530
 *  Compact a string
531
 *
532
 *  Purpose:
533
 *      This function is called remove leading and trailing spaces from
534
 *      a string. Treats other non-printing characters as leading
535
 *      spaces. This solves a problem when importing data from a
536
 *      Microsoft CSV file with empty fields.
537
 *
538
 *  Parameters:
539
 *      str     Address of the string to compact
540
 *
541
 *  Returns:
542
 *      Nothing
543
 *
544
 *========================================================================*/
545
 
546
void compact( char *str )
547
{
548
    char       *ptr;
549
 
550
    ptr = str;
551
    while( *str && ( isspace( *str ) || !isprint( *str ) ) )
552
        str++;
553
    strcpy( ptr, str );
554
}
555
 
556
/*========================================================================
557
 *
558
 *  Validate a team number
559
 *
560
 *  Purpose:
561
 *      This function is called to validate a team number
562
 *
563
 *  Parameters:
564
 *      x       Number to validate
565
 *
566
 *  Returns:
567
 *      TRUE    : Valid
568
 *      FALSE   : Not valid
569
 *
570
 *========================================================================*/
571
 
572
bool valid_field( int x )
573
{
574
    int         i;
575
 
576
    for( i = 0; i < config.num_teams; i++ )
577
    {
578
        if( x <= config.t_def[i].end && x >= config.t_def[i].start )
579
            return ( TRUE );
580
        if( x < config.t_def[i].start )
581
            break;                               /* Because the list is sorted */
582
    }
583
    return ( FALSE );
584
}
585
 
586
/*========================================================================
587
 *
588
 *  Get a class descriptor from existing text
589
 *
590
 *  Purpose:
591
 *      This function is called to Get a class descriptor
592
 *
593
 *  Parameters:
594
 *      text    - User text to examine
595
 *      config  - configuration dtaa to use
596
 *
597
 *  Returns:
598
 *      An integer which is the index into the  config.team_class array
599
 *      The integer is in the range 1 .. num_class
600
 *      A value fo zero indicates the text was not found.
601
 *
602
 *========================================================================*/
603
 
176 - 604
int QmConfig::lookup_class( const char *text )
174 - 605
{
606
    int         i;
607
 
176 - 608
//    if( config_ptr == NULL )
609
//        config_ptr = &config;
174 - 610
 
611
    /*
612
     * Attempt to locate the entered class in the list of defined classes
613
     */
614
 
176 - 615
    for( i = 0; i < num_class; i++ )
174 - 616
    {
176 - 617
        if( toupper(text[0]) == toupper(team_class[i].abr[0]) &&
618
            toupper(text[1]) == toupper(team_class[i].abr[1]) )
174 - 619
            return ( ++i );
620
    }
621
    return ( 0 );
622
}
177 - 623
 
624
#ifdef DISPLAY_STRUCTURES
625
/*============================================================================
626
**
627
**  Display structure information
628
**
629
**  Purpose:    Display internal structure information
630
**
631
**  Parameters: Nothing
632
**
633
**  Returns:    Nothing directly
634
**
635
**===========================================================================*/
636
 
637
/*
638
**  esize - A macro to return the size of a structure element
639
**  element - print element information
640
*/
641
#define esize( st, el) ( sizeof(((st *)0)->el))
642
#define element( st, el) \
208 - 643
    printf( "Offset of %-15s :%4d, Size:%d", #el, offsetof( st, el), esize(st, el) );
209 - 644
#define element2( st, el) \
645
    printf( "Size of %-15s :%4d", #el, esize(st, el) );
177 - 646
 
647
void display_structures(void)
648
{
208 - 649
    printf( "Structure: leg_type" );
177 - 650
    element( leg_type, start    );
651
    element( leg_type, end      );
652
    element( leg_type, elapsed  );
653
    element( leg_type, l_place  );
654
    element( leg_type, le_place );
655
    element( leg_type, lc_place );
656
    element( leg_type, lec_place);
657
    element( leg_type, manual   );
208 - 658
    printf( "Sizeof %-18s :%4d", "leg_type", sizeof(leg_type) );
177 - 659
 
660
 
208 - 661
    printf( "" );
662
    printf( "Structure: team_type" );
177 - 663
    element( team_type, numb   );
664
    element( team_type, name   );
665
    element( team_type, leg    );
666
    element( team_type, members);
208 - 667
    element( team_type, teamclass  );
177 - 668
    element( team_type, country);
669
    element( team_type, flags  );
208 - 670
    printf( "Sizeof %-18s :%4d", "team_type", sizeof(team_type) );
177 - 671
 
209 - 672
#if 1
208 - 673
    printf( "" );
674
    printf( "Structure: MARA_CFG" );
209 - 675
    element2( QmConfig, event_name      );
676
    element2( QmConfig, leg_name        );
677
    element2( QmConfig, t_def           );
678
    element2( QmConfig, num_legs        );
679
    element2( QmConfig, num_teams       );
680
    element2( QmConfig, max_team        );
681
    element2( QmConfig, min_team        );
682
    element2( QmConfig, team_class      );
683
    element2( QmConfig, num_class       );
684
    element2( QmConfig, country_name    );
685
    element2( QmConfig, num_countries   );
686
    element2( QmConfig, addendum        );
687
    element2( QmConfig, datafilename    );
688
    printf( "Sizeof %-18s :%4d", "QmConfig", sizeof(QmConfig) );
208 - 689
#endif
177 - 690
}
691
#endif