Subversion Repositories svn1

Rev

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