Subversion Repositories svn1

Rev

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