Subversion Repositories svn1

Rev

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