Subversion Repositories public

Rev

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

Rev Author Line No. Line
224 andreas 1
/***************************************************************************
2
 *   Copyright (C) 2007, 2008 by Andreas Theofilu                          *
3
 *   andreas@theosys.at                                                    *
4
 *                                                                         *
5
 *   This program is free software; you can redistribute it and/or modify  *
6
 *   it under the terms of the GNU General Public License as published by  *
7
 *   the Free Software Foundation version 3 of the License.                *
8
 *                                                                         *
9
 *   This program is distributed in the hope that it will be useful,       *
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12
 *   GNU General Public License for more details.                          *
13
 *                                                                         *
14
 *   You should have received a copy of the GNU General Public License     *
15
 *   along with this program; if not, write to the                         *
16
 *   Free Software Foundation, Inc.,                                       *
17
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18
 ***************************************************************************/
19
#include <time.h>
20
#include <string.h>
21
#include <math.h>
22
 
23
#include <qxml.h>
24
#include <qlistview.h>
25
#include <qgrid.h>
26
#include <qdatetime.h>
27
#include <qxml.h>
28
 
29
#include <klocale.h>
30
 
31
#include "import.h"
32
 
33
#define FLD_NAME		1
34
#define FLD_TOTALTIMESECONDS	2
35
#define FLD_DISTANCEMETERS	3
36
#define FLD_LATITUDEDEGREES	4
37
#define FLD_LONGITUDEDEGREES	5
38
#define FLD_VALUE		6
39
#define FLD_INTENSITY		7
40
#define FLD_TIME		8
41
#define FLD_ALTITUDEMETERS	9
42
#define FLD_SENSORSTATE		10
43
#define FLD_STARTTIME		11
44
#define FLD_AVERAGECADENCE	12
45
#define FLD_SPORTTYPE		13
46
#define FLD_VERSIONMAJOR	14
47
#define FLD_VERSIONMINOR	15
48
#define FLD_BUILDMAJOR		16
49
#define FLD_BUILDMINOR		17
50
#define FLD_TYPE		18
51
#define FLD_BUILDER		19
52
#define FLD_LANGID		20
53
#define FLD_PARTNUMBER		21
54
#define FLD_CADENCE		22
55
#define FLD_MAXSPEED		23
56
#define FLD_CALORIES		24
225 andreas 57
#define FLD_ID			25
58
#define FLD_TRIGGERMETHOD	26
59
#define FLD_TPX			27
60
#define FLD_UNITID		28
61
#define FLD_PRODUCTID		29
62
#define FLD_NOTES		30
224 andreas 63
 
64
#define CON_COURSES		100
65
#define CON_COURSE		101
66
#define CON_LAP			102
67
#define CON_BEGINPOSITION	103
68
#define CON_ENDPOSITION		104
69
#define CON_AVERAGEHEARTRATEBPM	105
70
#define CON_MAXIMUMHEARTRATEBPM	106
71
#define CON_TRACK		107
72
#define CON_TRACKPOINT		108
73
#define CON_POSITION		109
74
#define CON_HEARTRATEBPM	110
75
#define CON_AUTHOR		111
76
#define CON_VERSION		112
77
#define CON_BUILD		113
225 andreas 78
#define CON_ACTIVITY		114
79
#define CON_EXTENSIONS		115
80
#define CON_CREATOR		116
81
#define CON_MULTISPORTSESSION	117
82
#define CON_FIRSTSPORT		118
83
#define CON_NEXTSPORT		119
84
#define CON_TRAINING		120
85
#define CON_QUICKWORKOUTRESULTS	121
224 andreas 86
 
225 andreas 87
#define ATT_CADENCESENSOR	200
88
 
224 andreas 89
#define STOPSTOP		0
90
 
91
KEYS keys[] = {
92
	/* Fields */
93
	{ FLD_NAME,			QString("name") },
94
	{ FLD_TOTALTIMESECONDS,		QString("TotalTimeSeconds") },
95
	{ FLD_DISTANCEMETERS,		QString("DistanceMeters") },
96
	{ FLD_LATITUDEDEGREES,		QString("LatitudeDegrees") },
97
	{ FLD_LONGITUDEDEGREES,		QString("LongitudeDegrees") },
98
	{ FLD_VALUE,			QString("Value") },
99
	{ FLD_INTENSITY,		QString("Intensity") },
100
	{ FLD_TIME,			QString("Time") },
101
	{ FLD_ALTITUDEMETERS,		QString("AltitudeMeters") },
102
	{ FLD_SENSORSTATE,		QString("SensorState") },
103
	{ FLD_STARTTIME,		QString("StartTime") },
104
	{ FLD_AVERAGECADENCE,		QString("AverageCadence") },
105
	{ FLD_SPORTTYPE,		QString("SportType") },
106
	{ FLD_VERSIONMAJOR,		QString("VersionMajor") },
107
	{ FLD_VERSIONMINOR,		QString("VersionMinor") },
108
	{ FLD_BUILDMAJOR,		QString("BuildMajor") },
109
	{ FLD_BUILDMINOR,		QString("BuildMinor") },
110
	{ FLD_TYPE,			QString("Type") },
111
	{ FLD_BUILDER,			QString("Builder") },
112
	{ FLD_LANGID,			QString("LangID") },
113
	{ FLD_PARTNUMBER,		QString("PartNumber") },
114
	{ FLD_CADENCE,			QString("Cadence") },
115
	{ FLD_CALORIES,			QString("Calories") },
116
	{ FLD_MAXSPEED,			QString("MaximumSpeed") },
225 andreas 117
	{ FLD_ID,			QString("Id") },
118
	{ FLD_TRIGGERMETHOD,		QString("TriggerMethod") },
119
	{ FLD_TPX,			QString("TPX") },
120
	{ FLD_UNITID,			QString("UnitId") },
121
	{ FLD_PRODUCTID,		QString("ProductID") },
122
	{ FLD_NOTES,			QString("Notes") },
123
	/* Attributes */
124
	{ ATT_CADENCESENSOR,		QString("CadenceSensor") },
224 andreas 125
	/* Container */
126
	{ CON_COURSES,			QString("Courses") },
127
	{ CON_COURSE,			QString("Course") },
128
	{ CON_LAP,			QString("Lap") },
129
	{ CON_BEGINPOSITION,		QString("BeginPosition") },
130
	{ CON_ENDPOSITION,		QString("EndPosition") },
131
	{ CON_AVERAGEHEARTRATEBPM,	QString("AverageHeartRateBpm") },
132
	{ CON_MAXIMUMHEARTRATEBPM,	QString("MaximumHeartRateBpm") },
133
	{ CON_TRACK,			QString("Track") },
134
	{ CON_TRACKPOINT,		QString("Trackpoint") },
135
	{ CON_POSITION,			QString("Position") },
136
	{ CON_HEARTRATEBPM,		QString("HeartRateBpm") },
137
	{ CON_AUTHOR,			QString("Author") },
138
	{ CON_VERSION,			QString("Version") },
139
	{ CON_BUILD,			QString("Build") },
225 andreas 140
	{ CON_ACTIVITY,			QString("Activity") },
141
	{ CON_EXTENSIONS,		QString("Extensions") },
142
	{ CON_CREATOR,			QString("Creator") },
143
	{ CON_MULTISPORTSESSION,	QString("MultiSportSession") },
144
	{ CON_FIRSTSPORT,		QString("FirstSport") },
145
	{ CON_NEXTSPORT,		QString("NextSport") },
146
	{ CON_TRAINING,			QString("Training") },
147
	{ CON_QUICKWORKOUTRESULTS,	QString("QuickWorkoutResults") },
224 andreas 148
	/* Errors */
149
	{ ERR_OK,			QString("OK") },	// this is no error
150
	{ ERR_NOFILE,			i18n("IMPORT: No file name to parse XML!") },	// but this
151
	{ ERR_TAGS,			i18n("IMPORT: More end tags than open tags! Invalid XML file.") },
152
	{ ERR_ALLOCGMN,			i18n("IMPORT: Error allocating memory for base Garmin structure.") },
153
	{ ERR_ALLOCLAP,			i18n("IMPORT: Error allocating memory for a lap.") },
154
	{ ERR_ALLOCPOINT,		i18n("IMPORT: Error allocating memory for a track point.") },
155
	{ ERR_ALLOCRUN,			i18n("IMPORT: Error allocating memory for running information.") },
156
	{ ERR_ALLOCLIST,		i18n("IMPORT: Error allocating memory for a list node.") },
157
	{ STOPSTOP,			QString::null }
158
};
159
 
160
void gmn_import::Initialize()
161
{
162
	qfstat = false;
163
	qfopen = false;
164
	__error = 0;
165
	gmn = 0;
166
	list_lap = list_track = 0;
167
	ds = 0;
225 andreas 168
	history = false;
224 andreas 169
}
170
 
171
gmn_import::gmn_import (const QFile &qfile)
172
{
173
	Initialize ();
174
	file.setName (qfile.name ());
175
 
176
	if (file.exists ())
177
	   qfstat = true;
178
}
179
 
180
void gmn_import::setFile (const QFile &qfile)
181
{
182
	if (qfopen)
183
	{
184
	   file.close ();
185
	   qfopen = false;
186
	}
187
 
188
	qfstat = false;
189
	file.setName (qfile.name ());
190
 
191
	if (file.exists ())
192
	   qfstat = true;
193
}
194
 
195
void gmn_import::setFile (const QString &sfile)
196
{
197
	if (qfopen)
198
	{
199
	   file.close ();
200
	   qfopen = false;
201
	   __error = 1;
202
	}
203
 
204
	qfstat = false;
205
	file.setName (sfile);
206
 
207
	if (file.exists ())
208
	   qfstat = true;
209
}
210
 
211
/*
212
 * Convert an ISO8601 formated date into garmin epoch.
213
 */
214
unsigned int gmn_import::garmin_time (const QString& tstamp)
215
{
216
QDateTime dt;
217
time_t tval;
218
 
219
	/*
220
	 * tstamp should contain a valid ISO8601 formated date and time stamp.
221
	 * We will convert it to a kind of epoch, but with a garmin specific
222
	 * offset.
223
	 */
224
	dt = dt.fromString(tstamp, Qt::ISODate);
225
 
226
	if (!dt.isValid())
227
	   return 0;
228
 
229
	tval = dt.toTime_t() - TIME_OFFSET;
230
	return (unsigned int)tval;
231
}
232
 
233
/*
234
 * This function initializes the XML parser.
235
 */
236
bool gmn_import::startDocument()
237
{
238
	indent = 0;
239
	con.setAscii("");
240
	subCon.setAscii("");
241
	lpos = tpos = oldLPos = 0;
225 andreas 242
	history = fakeLap = false;
243
	first_tpos = 0;
244
	prun = 0;
245
	plap = 0;
224 andreas 246
	return TRUE;
247
}
248
 
249
/*
250
 * This is called every time a new start element was parsed.
251
 */
252
bool gmn_import::startElement( const QString&, const QString&,
253
                                    const QString& qName,
254
                                    const QXmlAttributes&)
255
{
256
int i = CON_FIRST;
257
 
258
	while (i <= CON_LAST)
259
	{
260
	   if (qName.lower() == getKey(i).lower())
261
	   {
225 andreas 262
	      if (qName.lower() == QString("course") || qName.lower() == QString("activity"))
224 andreas 263
	      {
264
		 memset (&run, 0, sizeof (D1009));
225 andreas 265
 
266
		 if (i == CON_ACTIVITY)
267
		 {
268
		    con.setAscii("activity");
269
		    history = true;
270
		 }
271
		 else
272
		    con.setAscii("course");
273
 
224 andreas 274
		 run.track_index = 0;
275
		 run.first_lap_index = 0;
276
		 run.sport_type = 0;		// Running
277
		 tk = i;
278
	      }
279
 
280
	      if (qName.lower() == QString("lap"))
281
	      {
282
		 memset (&lap, 0, sizeof (D1015));
283
		 lap.index = lpos;
284
		 lap.begin.lat = 0x7fffffff;
285
		 lap.begin.lon = 0x7fffffff;
286
		 lap.end.lat = 0x7fffffff;
287
		 lap.end.lon = 0x7fffffff;
288
		 con.setAscii("lap");
289
		 lpos++;
290
		 tk = i;
291
	      }
292
 
293
	      if (con == QString("lap") && qName.lower() == QString("BeginPosition").lower())
294
		 subCon = qName.lower();
295
	      else if (con == QString("lap") && qName.lower() == QString("EndPosition").lower())
296
		 subCon = qName.lower();
297
	      else if (con == QString("lap") && qName.lower() == QString("AverageHeartRateBpm").lower())
298
		 subCon = qName.lower();
299
	      else if (con == QString("lap") && qName.lower() == QString("MaximumHeartRateBpm").lower())
300
		 subCon = qName.lower();
301
 
225 andreas 302
	      if (history && qName.lower() == QString("track") && con.lower() == QString("lap"))
303
	      {
304
		 first_tpos = tpos + 1;
305
		 endElement (QString::null, QString::null, QString("Lap"));
306
		 indent++;
307
		 con.setAscii("lap");
308
		 fakeLap = true;
309
	      }
310
 
224 andreas 311
	      if (qName.lower() == QString("trackpoint"))
312
	      {
313
		 memset (&point, 0, sizeof (D304));
314
		 point.alt = 1.0e24;
315
		 point.posn.lat = 0x7fffffff;
316
		 point.posn.lon = 0x7fffffff;
317
		 con.setAscii("trackpoint");
318
		 tpos++;
319
		 tk = i;
320
	      }
321
 
322
	      if (con == QString("trackpoint") && qName.lower() == QString("position"))
323
		 subCon = qName.lower();
324
	      else if (con == QString("trackpoint") && qName.lower() == QString("heartratebpm"))
325
		 subCon = qName.lower();
326
	   }
327
 
328
	   i++;
329
	}
330
 
331
	i = FLD_FIRST;
332
 
333
	while (i <= FLD_LAST)
334
	{
335
	   if (qName.lower() == getKey(i).lower())
336
	      tk = i;
337
 
338
	   i++;
339
	}
340
 
341
	indent++;
342
	return TRUE;
343
}
344
 
345
/*
346
 * This is called every time an element is closed.
347
 */
348
bool gmn_import::endElement( const QString&, const QString&, const QString& qName)
349
{
225 andreas 350
	if (!fakeLap)
351
	   indent--;
224 andreas 352
 
353
	if (qName.lower() == QString("lap"))
354
	{
355
	   garmin_data *gdt;
356
	   garmin_list *l;
357
 
225 andreas 358
	   if (!fakeLap)
359
	      con.setAscii("");
224 andreas 360
 
225 andreas 361
	   if (history && fakeLap)
362
	   {
363
	      fakeLap = false;
364
	      return TRUE;
365
	   }
366
 
224 andreas 367
	   if (!gmn)		/* allocating space for first structure */
368
	   {
369
	      if ((gmn = garmin_alloc_data (data_Dlist)) == NULL)
370
	      {
371
		 __error = 3;
372
		 return FALSE;
373
	      }
374
 
375
	      list = (garmin_list *)gmn->data;
376
	      /*
377
	       * This is the first data structure. It contains the total
378
	       * number of laps and the name of the course, if it was
379
	       * named.
380
	       */
381
	      if ((gdt = garmin_alloc_data (data_D1009)) == NULL)
382
	      {
383
		 __error = 6;
384
		 return FALSE;
385
	      }
386
 
387
	      memmove (gdt->data, &run, sizeof (D1009));
388
	      prun = (D1009 *)gdt->data;
389
 
390
	      if (ds)
391
		 ds->garmin_print_data (gdt);
392
 
393
	      if ((l = garmin_list_append (list, gdt)) == NULL)
394
	      {
395
		 __error = 7;
396
		 return FALSE;
397
	      }
398
 
399
	      list = l;
400
	   }
401
 
402
	   if (!list_lap)
403
	   {
404
	      if ((gmn_lap = garmin_alloc_data (data_Dlist)) == NULL)
405
	      {
406
		 __error = 3;
407
		 return FALSE;
408
	      }
409
 
410
	      list_lap = (garmin_list *)gmn_lap->data;
411
 
412
	      if (garmin_list_append (list, gmn_lap) == NULL)
413
	      {
414
		 __error = 7;
415
		 return FALSE;
416
	      }
417
 
418
	      list = list_lap;
419
	   }
420
	   else
421
	      list = list_lap;
422
 
423
	   if ((gdt = garmin_alloc_data (data_D1015)) == NULL)
424
	   {
425
	      __error = 4;
426
	      return FALSE;
427
	   }
428
 
429
	   memmove (gdt->data, &lap, sizeof (D1015));
225 andreas 430
	   plap = (D1015 *)gdt->data;
224 andreas 431
 
432
	   if (ds)
433
	      ds->garmin_print_data (gdt);
434
 
435
	   if ((l = garmin_list_append (list, gdt)) == NULL)
436
	   {
437
	      __error = 7;
438
	      return FALSE;
439
	   }
440
 
441
	   list = l;
442
	}
443
 
225 andreas 444
	if (history && qName.lower() == QString("track"))
445
	   first_tpos = 0;
446
 
224 andreas 447
	if (qName.lower() == QString("trackpoint"))
448
	{
449
	   garmin_data *gdt;
450
	   garmin_list *l;
451
 
452
	   con.setAscii("");
453
 
454
	   if (!gmn)		/* allocating space for first structure */
455
	   {
456
	      if ((gmn = garmin_alloc_data (data_Dlist)) == NULL)
457
	      {
458
		 __error = 3;
459
		 return FALSE;
460
	      }
461
 
462
	      list = (garmin_list *)gmn->data;
463
	      /*
464
	       * This is the first data structure. It contains the total
465
	       * number of laps and the name of the course, if it was
466
	       * named.
467
	       */
468
	      if ((gdt = garmin_alloc_data (data_D1009)) == NULL)
469
	      {
470
		 __error = 6;
471
		 return FALSE;
472
	      }
473
 
474
	      memmove (gdt->data, &run, sizeof (D1009));
475
	      prun = (D1009 *)gdt->data;
476
 
477
	      if (ds)
478
		 ds->garmin_print_data (gdt);
479
 
480
	      if ((l = garmin_list_append (list, gdt)) == NULL)
481
	      {
482
		 __error = 7;
483
		 return FALSE;
484
	      }
485
 
486
	      list = l;
487
	   }
488
 
489
	   if (!list_track)
490
	   {
491
	      if ((gmn_track = garmin_alloc_data (data_Dlist)) == NULL)
492
	      {
493
		 __error = 3;
494
		 return FALSE;
495
	      }
496
 
497
	      list_track = (garmin_list *)gmn_track->data;
498
 
499
	      if (garmin_list_append (list, gmn_track) == NULL)
500
	      {
501
		 __error = 7;
502
		 return FALSE;
503
	      }
504
 
505
	      list = list_track;
506
	   }
507
	   else
508
	      list = list_track;
509
 
510
	   if ((gdt = garmin_alloc_data (data_D304)) == NULL)
511
	   {
512
	      __error = 5;
513
	      return FALSE;
514
	   }
515
 
516
	   memmove (gdt->data, &point, sizeof (D304));
517
 
518
	   if (ds)
519
	      ds->garmin_print_data (gdt);
520
 
521
	   if ((l = garmin_list_append (list, gdt)) == NULL)
522
	   {
523
	      __error = 7;
524
	      return FALSE;
525
	   }
526
 
527
	   list = l;
528
	}
529
 
225 andreas 530
	if (qName.lower() == QString("course") || qName.lower() == QString("activity"))
224 andreas 531
	{
532
	   con.setAscii("");
533
	   run.track_index = tpos - 1;
534
	   run.last_lap_index = lpos - 1;
535
	   memmove (prun, &run, sizeof (D1009));
225 andreas 536
	   history = false;
224 andreas 537
	}
538
 
539
	if (qName.lower() == QString("beginposition") || qName.lower() == QString("endposition") ||
540
	    qName.lower() == QString("averageheartratebpm") || qName.lower() == QString("maximumheartratebpm"))
541
	   subCon.setAscii("");
542
 
543
	if (qName.lower() == QString("heartratebpm") || qName.lower() == QString("position"))
544
	   subCon.setAscii("");
545
 
546
	if (indent < 0)
547
	{
548
	   __error = 2;
549
	   return FALSE;
550
	}
551
 
552
	return TRUE;
553
}
554
 
555
/*
556
 * The reader calls this function when it has parsed a chunk of character data
557
 * - either normal character data or character data inside a CDATA section.
558
 */
559
bool gmn_import::characters (const QString& ch)
560
{
561
int j = FLD_FIRST;
562
 
563
	if (con == QString("course"))
564
	{
565
	   if (tk == FLD_NAME)
566
	   {
567
	      strncpy (run.workout.name, ch.ascii(), 15);
568
	      run.workout.name[15] = 0;
569
	      tk = 0;
570
	   }
571
	}
572
 
225 andreas 573
	if (history && con == QString("activity"))
574
	{
575
	   if (tk == FLD_ID)
576
	   {
577
	      strncpy (run.workout.name, ch.ascii(), 15);
578
	      run.workout.name[15] = 0;
579
	      tk = 0;
580
	   }
581
	}
582
 
224 andreas 583
	if (con == QString("lap"))
584
	{
585
	   if (tk == FLD_DISTANCEMETERS)
586
	   {
587
	      lap.total_dist = (float32)ch.toFloat();
588
	      tk = 0;
589
	   }
590
 
591
	   if (tk == FLD_INTENSITY)
592
	   {
593
	      lap.intensity = (ch.lower() == QString("activ")) ? 0 : 1;
594
	      tk = 0;
595
	   }
596
 
597
	   if (tk == FLD_STARTTIME)
598
	   {
599
	      lap.start_time = garmin_time (ch);
600
	      tk = 0;
601
	   }
602
 
603
	   if (tk == FLD_TOTALTIMESECONDS)
604
	   {
605
	      lap.total_time = (uint32)(ch.toDouble() * 100.0);
606
	      tk = 0;
607
	   }
608
 
609
	   if (tk == FLD_CADENCE)
610
	   {
611
	      lap.avg_cadence = (uint8)ch.toUInt();
612
	      tk = 0;
613
	   }
614
 
615
	   if (tk == FLD_CALORIES)
616
	   {
617
	      lap.calories = (uint16)ch.toUInt();
618
	      tk = 0;
619
	   }
620
 
621
	   if (tk == FLD_MAXSPEED)
622
	   {
623
	      lap.max_speed = (float32)ch.toFloat();
624
	      tk = 0;
625
	   }
626
 
225 andreas 627
	   if (tk == FLD_TRIGGERMETHOD)
628
	   {
629
	      if (ch.lower() == QString("manual"))
630
		 lap.trigger_method = D1011_manual;
631
	      else if (ch.lower() == QString("distance"))
632
		 lap.trigger_method = D1011_distance;
633
	      else if (ch.lower() == QString("location"))
634
		 lap.trigger_method = D1011_location;
635
	      else if (ch.lower() == QString("time"))
636
		 lap.trigger_method = D1011_time;
637
	      else if (ch.lower() == QString("HeartRate"))
638
		 lap.trigger_method = D1011_heart_rate;
639
	   }
640
 
224 andreas 641
	   if (subCon.lower() == QString("BeginPosition").lower())
642
	   {
643
	      if (tk == FLD_LATITUDEDEGREES)
644
	      {
645
		 lap.begin.lat = (ch.toDouble() == 180.0) ? 0x7fffffff : (sint32)DEG2SEMI(ch.toDouble());
646
		 tk = 0;
647
	      }
648
 
649
	      if (tk == FLD_LONGITUDEDEGREES)
650
	      {
651
		 lap.begin.lon = (ch.toDouble() == 180.0) ? 0x7fffffff : (sint32)DEG2SEMI(ch.toDouble());
652
		 tk = 0;
653
	      }
654
	   }
655
	   else if (subCon.lower() == QString("EndPosition").lower())
656
	   {
657
	      if (tk == FLD_LATITUDEDEGREES)
658
	      {
659
		 lap.end.lat = (ch.toDouble() == 180.0) ? 0x7fffffff : (sint32)DEG2SEMI(ch.toDouble());
660
		 tk = 0;
661
	      }
662
 
663
	      if (tk == FLD_LONGITUDEDEGREES)
664
	      {
665
		 lap.end.lon = (ch.toDouble() == 180.0) ? 0x7fffffff : (sint32)DEG2SEMI(ch.toDouble());
666
		 tk = 0;
667
	      }
668
	   }
669
	   else if (subCon.lower() == QString("AverageHeartRateBpm").lower())
670
	   {
671
	      if (tk == FLD_VALUE)
672
	      {
673
		 lap.avg_heart_rate = (uint8)ch.toInt();
674
		 tk = 0;
675
	      }
676
	   }
677
	   else if (subCon.lower() == QString("MaximumHeartRateBpm").lower())
678
	   {
679
	      if (tk == FLD_VALUE)
680
	      {
681
		 lap.max_heart_rate = (uint8)ch.toInt();
682
		 tk = 0;
683
	      }
684
	   }
685
	}
686
 
687
	if (con == QString("trackpoint"))
688
	{
689
	   if (tk == FLD_TIME)
690
	   {
691
	      point.time = garmin_time (ch);
225 andreas 692
 
693
	      if (history && first_tpos == tpos && plap)
694
		 plap->start_time = point.time;
695
 
224 andreas 696
	      tk = 0;
697
	   }
698
 
699
	   if (tk == FLD_ALTITUDEMETERS)
700
	   {
701
	      point.alt = (ch.toFloat() >= 1.0e24) ? 1.0e24 : (float32)ch.toFloat();
702
	      tk = 0;
703
	   }
704
 
705
	   if (tk == FLD_DISTANCEMETERS)
706
	   {
707
	      point.distance = (ch.toFloat() >= 1.0e24) ? 1.0e24 : (float32)ch.toFloat();
708
	      tk = 0;
709
	   }
710
 
711
	   if (tk == FLD_SENSORSTATE)
712
	   {
713
	      point.sensor = (ch.lower() == QString("absent")) ? false : true;
714
	      tk = 0;
715
	   }
716
 
717
	   if (subCon.lower() == QString("position"))
718
	   {
719
	      if (tk == FLD_LATITUDEDEGREES)
720
	      {
721
		 point.posn.lat = (ch.toDouble() == 180.0) ? 0x7fffffff : (sint32)DEG2SEMI(ch.toDouble());
225 andreas 722
 
723
		 if (history && tpos == first_tpos && plap)	// Add mising information to first lap
724
		    plap->begin.lat = point.posn.lat;
725
		 else if (history && point.posn.lat != 0x7fffffff && plap)
726
		    plap->end.lat = point.posn.lat;
727
 
224 andreas 728
		 tk = 0;
729
	      }
730
 
731
	      if (tk == FLD_LONGITUDEDEGREES)
732
	      {
733
		 point.posn.lon = (ch.toDouble() == 180.0) ? 0x7fffffff : (sint32)DEG2SEMI(ch.toDouble());
225 andreas 734
 
735
		 if (history && tpos == first_tpos && plap)	// Add mising information to first lap
736
		    plap->begin.lon = point.posn.lon;
737
		 else if (history && point.posn.lon != 0x7fffffff && plap)
738
		    plap->end.lat = point.posn.lon;
739
 
224 andreas 740
		 tk = 0;
741
	      }
742
	   }
743
	   else if (subCon.lower() == QString("heartratebpm"))
744
	   {
745
	      if (tk == FLD_VALUE)
746
	      {
747
		 point.heart_rate = (unsigned char)ch.toInt();
748
		 tk = 0;
749
	      }
750
	   }
751
	}
752
 
753
	return TRUE;
754
}
755
 
756
/*
757
 * The following function reads a Garmin HST file, parses the XML
758
 * content and creates the gmn files. If there already exists a file,
759
 * it's not overwritten.
760
 */
761
int gmn_import::import ()
762
{
763
QXmlSimpleReader reader;
764
 
765
	if (!qfstat)
766
	   return 1;
767
 
768
	QXmlInputSource source (&file);
769
	reader.setContentHandler (this);
770
	reader.parse (source);
771
	return 0;
772
}
773
 
774
QString gmn_import::getKey (int pos)
775
{
776
int i = 0;
777
 
778
	while (keys[i].id > 0)
779
	{
780
	   if (keys[i].id == pos)
781
	      return keys[i].name;
782
 
783
	   i++;
784
	}
785
 
786
	return QString::null;
787
}
788
 
789
QString gmn_import::getError (int err)
790
{
791
	if (err > eMax || err < 1)
792
	   return 0;
793
 
794
	return getKey (ERR_FIRST + err);
795
}
796
 
797
QString gmn_import::getError ()
798
{
799
	return getKey (ERR_FIRST + __error);
800
}
801