Subversion Repositories public

Rev

Rev 149 | Rev 152 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
88 andreas 1
/***************************************************************************
119 andreas 2
 *   Copyright (C) 2007, 2008 by Andreas Theofilu                          *
3
 *   andreas@theosys.at                                                    *
88 andreas 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
 
119 andreas 20
#include "config.h"
88 andreas 21
#include "managefile.h"
22
#include "sportwatcherwidget.h"
23
#include "settingswidget.h"
96 andreas 24
#include "progresswidget.h"
151 andreas 25
// #undef GDAL
26
#include <string.h>
96 andreas 27
 
137 andreas 28
#include <iostream>
88 andreas 29
#include <kfiledialog.h>
30
#include <kmessagebox.h>
31
#include <ksimpleconfig.h>
32
#include <klocale.h>
33
#include <klistview.h>
100 andreas 34
#include <kaboutdialog.h>
35
#include <kaboutdata.h>
128 andreas 36
#include <kglobalsettings.h>
88 andreas 37
#include <qstring.h>
38
#include <qdatetime.h>
109 andreas 39
#include <qtoolbutton.h>
132 andreas 40
#include <qcursor.h>
151 andreas 41
#include <qcstring.h>
42
 
137 andreas 43
#include "copy.h"
88 andreas 44
 
151 andreas 45
// #define DEBUG	1
46
 
137 andreas 47
using std::cout;
48
using std::endl;
49
 
50
 
104 andreas 51
typedef struct
52
{
53
	double lon;
54
	double lat;
55
} posn_type;
56
 
88 andreas 57
sportwatcherWidget::sportwatcherWidget(QWidget* parent, const char* name, WFlags fl)
58
: sportwatcherWidgetBase(parent,name,fl)
59
{
60
	mama = parent;
61
	gmn = 0;
62
	min_hr = max_hr = avg_hr = 0;
63
	min_height = max_height = 0.0;
64
	max_time = 0;
65
	index = 0;
104 andreas 66
	zfactor = 0;
132 andreas 67
	mapLap = 0;
68
	mapPan = QRect(0, 0, 0, 0);
69
	stateHand = stateFlag = stateGlas = false;
70
	oldTransX = oldTransY = 0.0;
71
	lmbPressed = 0;
72
 
88 andreas 73
	// Load the config parameters
74
	KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"), true);
75
	cfg->setGroup(QString("SportWatcher"));
143 andreas 76
	lower1 = cfg->readNumEntry("lower1", 0);
77
	lower2 = cfg->readNumEntry("lower2", 0);
78
	lower3 = cfg->readNumEntry("lower3", 0);
79
	upper1 = cfg->readNumEntry("upper1", 0);
80
	upper2 = cfg->readNumEntry("upper2", 0);
81
	upper3 = cfg->readNumEntry("upper3", 0);
82
	MaxHr = cfg->readNumEntry("maxHr", 180);
83
	restHr = cfg->readNumEntry("restHr", 60);
84
	vo2max = cfg->readNumEntry("vo2max", 50);
85
	weight = cfg->readNumEntry("weight", 70);
86
	sampleTime = cfg->readNumEntry("seconds", 15);
149 andreas 87
	Serial = cfg->readBoolEntry("Serial", false);
88 andreas 88
	Device = cfg->readEntry("Device", "/dev/ttyUSB0");
143 andreas 89
	Data = cfg->readEntry("Data", QDir::home().absPath() + "/.sportwatcher");
90
	HRM = cfg->readEntry("HRM", QDir::home().absPath() + "/polar");
151 andreas 91
	MAP = cfg->readEntry("MAP", QDir::home().absPath() + "/.sportwatcher/track.wms");
149 andreas 92
	Units = cfg->readNumEntry("Units", 0);
88 andreas 93
	delete cfg;
132 andreas 94
	// Set some widget settings
95
	btHand->setToggleButton(true);
96
	btGlas->setToggleButton(true);
88 andreas 97
	// Fill the activities
98
	getActivities();
151 andreas 99
#ifdef GDAL
100
	// Initialize the GDAL
101
	GDALAllRegister();
102
 
103
	if (QFile(MAP).exists())
104
	{
105
	   poDataset = (GDALDataset *)GDALOpen (MAP.ascii(), GA_ReadOnly);
106
 
107
	   if (poDataset == NULL)
108
	      KMessageBox::error(this, i18n("Error opening or initializing the MAP-Database!\nThere will be no map available."));
109
 
110
	   GDALClose (poDataset);
111
	}
112
 
113
	poDataset = 0;
114
#endif
88 andreas 115
}
116
 
117
sportwatcherWidget::~sportwatcherWidget()
118
{
104 andreas 119
	destroy();
88 andreas 120
}
121
 
100 andreas 122
void sportwatcherWidget::destroy()
123
{
124
	if (gmn)
125
	   garmin_free_data (gmn);
126
 
127
	if (index)
128
	{
129
	INDEX *n, *akt = index;
130
 
131
	   while (akt)
132
	   {
133
	      n = akt;
134
	      akt = akt->next;
135
	      delete n;
136
	   }
137
	}
138
 
139
	index = 0;
140
	gmn = 0;
132 andreas 141
	oldTransX = oldTransY = 0.0;
100 andreas 142
}
143
 
132 andreas 144
bool sportwatcherWidget::findIndex(const QString &key)
145
{
146
INDEX *akt = index;
147
 
148
	while (akt)
149
	{
150
	   if (akt->path == key || akt->activ == key)
151
	      return true;
152
 
153
	   akt = akt->next;
154
	}
155
 
156
	return false;
157
}
158
 
88 andreas 159
/*
160
 * Search for a directory named .sportwatcher in the home directory of
161
 * the user and search for *.gmn files. Open the files and read the header
162
 * to find the basic data of activities. Then add the information into
163
 * the activities KListView.
164
 */
165
void sportwatcherWidget::getActivities()
166
{
167
QString path, txt;
132 andreas 168
QDir mdir, dir = QDir::homeDirPath();
88 andreas 169
QFileInfo *entries;
170
QStringList years, months;
128 andreas 171
KListViewItem *running, *biking, *other;
172
KListViewItem *el;
88 andreas 173
int anz;
174
RUN_NODE *rn;
175
LAP *lap;
176
 
177
	if (Data.isEmpty())
178
	{
128 andreas 179
	   path = dir.homeDirPath();
88 andreas 180
	   path.append("/.sportwatcher");
181
	}
182
	else
183
	   path = Data;
184
 
185
	dir.setPath(path);
132 andreas 186
	dir.refresh();
88 andreas 187
 
188
	if (!dir.exists())
189
	{
190
	   dir.mkdir(path);
191
	   return;
192
	}
193
 
132 andreas 194
	destroy();
100 andreas 195
	liActivities->clear();
88 andreas 196
	liActivities->setRootIsDecorated(true);
197
	liActivities->setSortColumn(-1);
128 andreas 198
	other = new KListViewItem(liActivities, i18n("Others"));
199
	biking = new KListViewItem(liActivities, i18n("Biking"));
200
	running = new KListViewItem(liActivities, i18n("Running"));
201
 
202
	other->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
203
	biking->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
204
	running->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
205
 
88 andreas 206
	liActivities->insertItem(other);
207
	liActivities->insertItem(biking);
208
	liActivities->insertItem(running);
209
 
210
	dir.cd(path);
211
	dir.setFilter(QDir::Dirs | QDir::NoSymLinks);
212
	dir.setSorting(QDir::Name);
132 andreas 213
	dir.refresh();
128 andreas 214
	QFileInfoList *list = (QFileInfoList *)dir.entryInfoList();
88 andreas 215
 
216
	if (!list)
217
	   return;
218
 
219
	QFileInfoListIterator it(*list);
220
 
221
	while ((entries = it.current()) != 0)		// Years
222
	{
223
	   if (entries->fileName() == QString(".") || entries->fileName() == QString(".."))
224
	   {
225
	      ++it;
226
	      continue;
227
	   }
228
 
229
	   years += entries->absFilePath();
230
	   ++it;
231
	}
232
 
233
	for (QStringList::Iterator strit = years.begin(); strit != years.end(); ++strit)
234
	{
235
	   if (months.count() > 0)
236
	      months.clear();
237
 
238
	   dir.setPath(*strit);
132 andreas 239
	   dir.refresh();
128 andreas 240
	   list = (QFileInfoList *)dir.entryInfoList();
88 andreas 241
 
242
	   if (!list)
243
	      continue;
244
 
245
	   it = QFileInfoListIterator (*list);
246
 
247
	   while ((entries = it.current()) != 0)	// Months
248
	   {
249
	      if (entries->fileName() == QString(".") || entries->fileName() == QString(".."))
250
	      {
251
		 ++it;
252
		 continue;
253
	      }
254
 
255
	      months += entries->absFilePath();
256
	      ++it;
257
	   }
258
 
259
	   for (QStringList::Iterator strit1 = months.begin(); strit1 != months.end(); ++strit1)
260
	   {
261
	      mdir.setPath(*strit1);
262
	      mdir.cd(*strit1);
263
	      mdir.setFilter(QDir::Files | QDir::NoSymLinks);
264
	      mdir.setNameFilter(QString("*.gmn"));
132 andreas 265
	      mdir.refresh();
128 andreas 266
	      list = (QFileInfoList *)mdir.entryInfoList();
88 andreas 267
 
268
	      if (!list)
269
		 continue;
270
 
271
	      it = QFileInfoListIterator (*list);
272
	      anz = 0;
273
 
274
	      while ((entries = it.current()) != 0)		// Files
275
	      {
276
		 files += entries->absFilePath();
277
		 ++it;
278
	      }
279
	   }
280
	}
281
 
282
	INDEX *akt, *n;
283
	// Open every file and read its head
284
	for (QStringList::Iterator strfl = files.begin(); strfl != files.end(); ++strfl)
285
	{
132 andreas 286
	   if (findIndex(*strfl))	// avoid duplicate entries
287
	      continue;
288
 
88 andreas 289
	   spw.destroy();
290
 
291
	   if (spw.setFileName(*strfl) == -1)
292
	      return;
293
 
294
	   if (gmn)
295
	      garmin_free_data (gmn);
296
 
297
	   gmn = spw.readFile();
298
	   ds.destroy();
299
	   ds.garmin_print_data(gmn);
300
	   rn = ds.getRunNode();
301
 
302
	   lap = ds.getLap(rn->run->first_lap_index);
303
	   const QDateTime *qt = garmin_dtime (lap->start_time);
304
	   QString idx = qt->toString("dd.MM.yyyy hh:mm.ss");
305
 
306
	   if (!index)
307
	   {
308
	      index = new INDEX;
309
	      index->path = *strfl;
310
	      index->activ = idx;
311
	      index->next = 0;
312
	   }
313
	   else
314
	   {
315
	      n = new INDEX;
316
	      n->path = *strfl;
317
	      n->activ = idx;
318
	      n->next = 0;
319
	      akt = index;
320
 
321
	      while (akt->next)
322
		 akt = akt->next;
323
 
324
	      akt->next = n;
325
	   }
326
 
327
	   switch (rn->run->sport_type)
328
	   {
329
	      case D1000_running:
128 andreas 330
		 el = new KListViewItem(running, idx);
331
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("run.png")));
88 andreas 332
		 running->insertItem(el);
333
	      break;
334
 
335
	      case D1000_biking:
128 andreas 336
		 el = new KListViewItem(biking, idx);
337
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("bike.png")));
88 andreas 338
		 biking->insertItem(el);
339
	      break;
340
 
341
	      case D1000_other:
128 andreas 342
		 el = new KListViewItem(other, idx);
343
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("other.png")));
88 andreas 344
		 other->insertItem(el);
345
	      break;
346
 
347
	      default:
128 andreas 348
		 el = new KListViewItem(other, idx);
349
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("other.png")));
88 andreas 350
		 other->insertItem(el);
351
	   }
352
 
353
	   delete qt;
354
	}
355
 
356
	running->setOpen(true);
357
 
358
	if (gmn)
359
	   garmin_free_data (gmn);
360
 
361
	gmn = 0;
362
}
363
 
364
/*$SPECIALIZATION$*/
365
void sportwatcherWidget::btFullscreenSlot()
366
{
132 andreas 367
	oldTransX = oldTransY = 0.0;
368
	mapPan.setCoords(0, 0, 0, 0);
104 andreas 369
	showTrack(0);
88 andreas 370
}
371
 
372
void sportwatcherWidget::btGlasMinusSlot()
373
{
132 andreas 374
bool sh = stateHand;
375
 
376
	stateHand = false;
104 andreas 377
	showTrack(zfactor - 1000);
132 andreas 378
	stateHand = sh;
88 andreas 379
}
380
 
381
void sportwatcherWidget::btGlasPlusSlot()
382
{
132 andreas 383
bool sh = stateHand;
384
 
385
	stateHand = false;
104 andreas 386
	showTrack(zfactor + 1000);
132 andreas 387
	stateHand = sh;
88 andreas 388
}
389
 
390
void sportwatcherWidget::btHandSlot()
391
{
132 andreas 392
QCursor cs;
393
 
394
	if (stateGlas)
395
	{
396
	   stateGlas = false;
397
	   btGlas->toggle();
398
	}
399
 
400
	stateHand = (stateHand) ? false : true;
401
 
402
	if (stateHand)
403
	   cs.setShape(QCursor::PointingHandCursor);
404
	else
405
	   cs.setShape(QCursor::ArrowCursor);
406
 
407
	imgMap->setCursor(cs);
88 andreas 408
}
409
 
410
void sportwatcherWidget::btGlasSlot()
411
{
132 andreas 412
QCursor cs;
413
 
414
	if (stateHand)
415
	{
416
	   stateHand = false;
417
	   btHand->toggle();
418
	}
419
 
420
	stateGlas = (stateGlas) ? false : true;
421
 
422
	if (stateGlas)
423
	   cs.setShape(QCursor::ForbiddenCursor);
424
	else
425
	   cs.setShape(QCursor::ArrowCursor);
426
 
427
	imgMap->setCursor(cs);
88 andreas 428
}
429
 
430
void sportwatcherWidget::btFlagSlot()
431
{
432
}
433
 
132 andreas 434
void sportwatcherWidget::liLapsSlot(QListViewItem *item)
88 andreas 435
{
132 andreas 436
QString sl;
437
int l;
438
int idx;
439
RUN_NODE *rn;
440
LAP *lap;
441
 
442
	if (!item)
443
	   return;
444
 
445
	sl = item->text(0).mid(4, 3);
446
	l = sl.toInt();
447
 
448
	if (l <= 0)
449
	{
450
	   showTrack(zfactor, mapPan, 0);
148 andreas 451
	   showCurves(0);
132 andreas 452
	   return;
453
	}
454
 
455
	rn = ds.getRunNode();
456
	idx = rn->run->first_lap_index;
457
	lap = ds.getLap(idx + l - 1);
458
	showTrack(zfactor, mapPan, lap);
148 andreas 459
	showCurves(lap);
88 andreas 460
}
461
 
462
void sportwatcherWidget::liActivitiesSlot(QListViewItem *item)
463
{
464
INDEX *akt;
465
 
466
	if (!item)
467
	   return;
468
 
469
	akt = index;
470
 
471
	while (akt)
472
	{
473
	   if (akt->activ == item->text(0))
474
	   {
475
	      spw.destroy();
476
 
477
              if (spw.setFileName(akt->path.ascii()) == -1)
478
		 return;
479
 
480
	      if (gmn)
481
		 garmin_free_data (gmn);
482
 
483
	      gmn = spw.readFile();
104 andreas 484
	      zfactor = 0;
88 andreas 485
	      showLaps();
100 andreas 486
	      showTrack();
88 andreas 487
	      showCurves();
488
	      return;
489
	   }
490
 
491
	   akt = akt->next;
492
	}
493
}
494
 
495
void sportwatcherWidget::helpAbout()
496
{
119 andreas 497
KAboutData about("SportWatcher", "SportWatcher", VERSION);
100 andreas 498
QString ab = ("About");
499
QString liz = ("License");
500
 
501
	KAboutDialog *info = new KAboutDialog(KAboutDialog::AbtProduct|KAboutDialog::AbtTabbed,
137 andreas 502
		QString("SportWatcher"), KAboutDialog::Close, KAboutDialog::Close, 0,
100 andreas 503
		i18n("About"), false, false, QString::null, QString::null, QString::null);
119 andreas 504
	info->setProduct("SportWatcher", QString("Version %1").arg(VERSION), "Andreas Theofilu", "2007, 2008");
100 andreas 505
	KAboutContainer *infoAppl = info->addContainerPage(ab, AlignCenter, AlignCenter);
119 andreas 506
	infoAppl->addTitle(QString("SportWatcher"), AlignCenter, false, false);
137 andreas 507
//	infoAppl->addTitle(QString("(C) 2007, 2008, Andreas Theofilu <andreas@theosys.at>"));
508
	infoAppl->addPerson(QString("Andreas Theofilu"), QString("andreas@theosys.at"), QString("http://www.theosys.at"), NULL);
509
	infoAppl->addTitle(I18N_NOOP("\nRead out the data of a Garmin GPS device over USB, and visualize them on screen"));
510
	about.setLicense(KAboutData::License_Custom);
511
	about.setLicenseText(I18N_NOOP(gpl3));
100 andreas 512
	info->addLicensePage(liz, about.license(), 10);
137 andreas 513
	info->setGeometry(0, 0, 800, 400);
100 andreas 514
	info->centerOnScreen(info, 0);
515
	info->exec();
516
	delete info;
88 andreas 517
}
518
 
519
void sportwatcherWidget::helpContents()
520
{
521
}
522
 
523
void sportwatcherWidget::helpIndex()
524
{
525
}
526
 
527
void sportwatcherWidget::fileExit()
528
{
529
	if (mama)
530
	   mama->close();
531
}
532
 
533
void sportwatcherWidget::filePrint()
534
{
535
}
536
 
104 andreas 537
/*
538
 * This function allows the user to choose a file name, where we save the
539
 * actual lap in Garmins own TCX format. This format is simply a XML-file.
540
 * For details about the schema of this file look at
541
 * http://developer.garmin.com/schemas/tcx/v2/
542
 */
88 andreas 543
void sportwatcherWidget::fileSaveAs()
544
{
104 andreas 545
QString fname;
546
QFile fn;
547
QString buffer;
548
RUN_NODE *rn, *rakt;
549
LAP *lap;
550
POINT *point;
551
int indent, i;
552
QDateTime *qt;
553
 
554
	if (!gmn)
555
	{
556
	   KMessageBox::error(this, i18n("Currently no activity is selected!"));
557
	   return;
558
	}
559
 
560
	fname = KFileDialog::getSaveFileName(0, QString("*.tcx"), this, QString("SportWatcher"));
561
 
562
	if (fname.isEmpty())
563
	   return;
564
 
565
	fn.setName(fname);
566
 
567
	if (fn.exists())
568
	{
569
	   if (KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
570
	      return;
571
	}
572
 
573
	rn = ds.getRunNode();
574
	lap = ds.getLap(rn->run->first_lap_index);
575
 
576
	if ((point = ds.getPoint(lap->start_time)) == 0)
577
	{
578
	   KMessageBox::error(this, i18n("No data to save!"));
579
	   return;
580
	}
581
 
582
	if (!fn.open(IO_ReadWrite | IO_Truncate))
583
	{
584
	   KMessageBox::error(this, i18n("Error creating file " + QString(fname) + "!\nPlease check permissions"));
585
	   return;
586
	}
587
 
588
	buffer = QString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
589
	buffer.append("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\" ");
590
	buffer.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
591
	buffer.append("xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 ");
592
	buffer.append("http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd\">\n\n");
593
	writeTag (fn, buffer, indent);
594
	buffer = QString("<folders/>\n\n");
595
	writeTag (fn, buffer, indent);
596
 
597
	// Open a course
598
	QFileInfo finfo(fname);
599
	buffer = QString("<Courses>\n   <Course>\n      <name>%1</name>\n").arg(finfo.baseName(true));
600
	writeTag (fn, buffer, indent);
601
	indent = 2;
602
 
603
	rakt = rn;
604
 
605
	while (rakt)
606
	{
607
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
608
	   	rakt->run->type != data_D1010)
609
	   {
610
	      rakt = rakt->next;
611
	      continue;
612
	   }
613
 
614
	   for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
615
	   {
616
	      if ((lap = ds.getLap(i)) == NULL)
617
		 continue;
618
 
619
	      // Write the information of the lap
620
	      writeTag (fn, QString("<Lap>\n"), indent);
621
	      indent++;
622
	      buffer.sprintf("<TotalTimeSeconds>%f</TotalTimeSeconds>\n", (double)lap->total_time / 100.0);
623
	      writeTag (fn, buffer, indent);
624
	      buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", lap->total_distance);
625
	      writeTag (fn, buffer, indent);
626
 
627
	      writeTag (fn, QString("<BeginPosition>\n"), indent);
628
	      indent++;
629
	      buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->begin.lat));
630
	      writeTag (fn, buffer, indent);
631
	      buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->begin.lon));
632
	      writeTag (fn, buffer, indent);
633
	      indent--;
634
	      writeTag (fn, QString("</BeginPosition>\n"), indent);
635
 
636
	      writeTag (fn, QString("<EndPosition>\n"), indent);
637
	      indent++;
638
	      buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->end.lat));
639
	      writeTag (fn, buffer, indent);
640
	      buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->end.lon));
641
	      writeTag (fn, buffer, indent);
642
	      indent--;
643
	      writeTag (fn, QString("</EndPosition>\n"), indent);
644
 
645
	      writeTag (fn, QString("<AverageHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
646
	      indent++;
647
	      buffer.sprintf("<Value>%d</Value>\n", lap->avg_heart_rate);
648
	      writeTag (fn, buffer, indent);
649
	      indent--;
650
	      writeTag (fn, QString("</AverageHeartRateBpm>\n"), indent);
651
 
652
	      writeTag (fn, QString("<MaximumHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
653
	      indent++;
654
	      buffer.sprintf("<Value>%d</Value>\n", lap->avg_heart_rate);
655
	      writeTag (fn, buffer, indent);
656
	      indent--;
657
	      writeTag (fn, QString("</MaximumHeartRateBpm>\n"), indent);
658
 
659
	      buffer = QString("<Intensity>%1</Intensity>\n").arg((!lap->intensity) ? "Active" : "");
660
	      writeTag (fn, buffer, indent);
661
	      indent--;
662
	      writeTag (fn, QString("</Lap>\n"), indent);
663
 
664
	      point = ds.getPoint(lap->start_time);
665
	      writeTag (fn, QString("<Track>\n"), indent);
666
	      indent++;
667
 
668
	      while (point)
669
	      {
670
		 if (point->time > (lap->start_time + (lap->total_time / 100)))
671
		    break;
672
 
673
		 writeTag (fn, QString("<Trackpoint>\n"), indent);
674
		 indent++;
675
		 qt = garmin_dtime(point->time);
676
		 buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
677
		 writeTag (fn, buffer, indent);
678
		 delete qt;
679
		 writeTag (fn, QString("<Position>\n"), indent);
680
		 indent++;
681
		 buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(point->posn.lat));
682
		 writeTag (fn, buffer, indent);
683
		 buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(point->posn.lon));
684
		 writeTag (fn, buffer, indent);
685
		 indent--;
686
		 writeTag (fn, QString("</Position>\n"), indent);
687
 
688
		 if (point->alt < 20000.0)
689
		 {
690
		    buffer.sprintf("<AltitudeMeters>%f</AltitudeMeters>\n", point->alt);
691
		    writeTag (fn, buffer, indent);
692
		 }
693
 
694
		 buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", point->distance);
695
		 writeTag (fn, buffer, indent);
696
 
697
		 if (point->heart_rate > 0 && point->heart_rate < 250)
698
		 {
699
		    writeTag (fn, QString("<HeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
700
		    indent++;
701
		    buffer.sprintf("<Value>%d</Value>\n", point->heart_rate);
702
		    writeTag (fn, buffer, indent);
703
		    indent--;
704
		    writeTag (fn, QString("</HeartRateBpm>\n"), indent);
705
		 }
706
 
707
		 buffer.sprintf("<SensorState>%s</SensorState>\n", (!point->sensor) ? "Absent" : "");
708
		 writeTag (fn, buffer, indent);
709
		 indent--;
710
		 writeTag (fn, QString("</Trackpoint>\n"), indent);
711
		 point = ds.getPoint(point->time + 1);
712
	      }
713
 
714
	      indent--;
715
	      writeTag (fn, QString("</Track>\n"), indent);
716
	   }
717
 
718
	   indent--;
719
	   writeTag (fn, QString("</Course>\n"), indent);
720
	   indent--;
721
	   writeTag (fn, QString("</Courses>\n"), indent);
722
	   rakt = rakt->next;
723
	}
724
 
725
	// Write information about device
726
	// Here my personal signature is written :-)
727
	writeTag (fn, QString("<Author xsi:type=\"Application_t\">\n"), indent);
728
	indent++;
729
	writeTag (fn, QString("<Name>SportWatcher</Name>\n"), indent);
730
	writeTag (fn, QString("<Build>\n"), indent);
731
	indent++;
732
	writeTag (fn, QString("<Version>\n"), indent);
733
	indent++;
734
	writeTag (fn, QString("<VersionMajor>0</VersionMajor>\n"), indent);
735
	writeTag (fn, QString("<VersionMinor>1</VersionMinor>\n"), indent);
736
	writeTag (fn, QString("<BuildMajor>0</BuildMajor>\n"), indent);
737
	writeTag (fn, QString("<BuildMinor>0</BuildMinor>\n"), indent);
738
	indent--;
739
	writeTag (fn, QString("</Version>\n"), indent);
740
	writeTag (fn, QString("<Type>Beta</Type>\n"), indent);
741
	writeTag (fn, QString("<Time>Jan 31 2008, 00:00:00</Time>\n"), indent);
742
	writeTag (fn, QString("<Builder>theosys</Builder>\n"), indent);
743
	indent--;
744
	writeTag (fn, QString("</Build>\n"), indent);
745
	writeTag (fn, QString("<LangID>EN</LangID>\n"), indent);
746
	writeTag (fn, QString("<PartNumber>000-00000-00</PartNumber>\n"), indent);
747
	indent--;
748
	writeTag (fn, QString("</Author>\n"), indent);
749
	writeTag (fn, QString("</TrainingCenterDatabase>\n"), indent);
750
 
751
	fn.close();
752
	KMessageBox::information(this, i18n("File ") + fname + i18n(" was written successfully."));
88 andreas 753
}
754
 
755
void sportwatcherWidget::fileSave()
756
{
757
}
758
 
759
void sportwatcherWidget::fileOpen()
760
{
761
QString fname = KFileDialog::getOpenFileName(Data, QString("*.gmn"), this, QString("SportWatcher"));
137 andreas 762
int m;
88 andreas 763
 
764
        if (fname.isEmpty())
765
           return;
766
 
767
	spw.destroy();
768
 
769
        if (spw.setFileName(fname.ascii()) == -1)
770
	   return;
771
 
772
	if (gmn)
773
	   garmin_free_data (gmn);
774
 
775
	gmn = spw.readFile();
104 andreas 776
	zfactor = 0;
137 andreas 777
 
778
	if ((m = garmin_count_error()) > 0)
779
	{
780
	int i, key = -1;
781
 
782
	   for (i = 0; i < m; i++)
783
	      KMessageBox::error(this, QString(garmin_get_next_error(&key)));
784
 
785
	   garmin_clear_errors();
786
	   return;
787
	}
788
 
88 andreas 789
	showLaps();
100 andreas 790
	showTrack();
88 andreas 791
	showCurves();
792
}
793
 
794
void sportwatcherWidget::fileNew()
795
{
132 andreas 796
progressWidget *dlg = new progressWidget(this, "progressWidgetBase");
96 andreas 797
 
100 andreas 798
	dlg->show();
137 andreas 799
 
800
	if (!dlg->Download())
801
	{
802
	int m, key;
803
 
804
	   key = -1;
805
 
806
	   for (m = 0; m < garmin_count_error(); m++)
807
	      KMessageBox::error(this, QString(garmin_get_next_error(&key)));
808
	}
809
	else
810
	   getActivities();
811
 
812
	garmin_clear_errors();
96 andreas 813
	delete dlg;
88 andreas 814
}
815
 
816
/*
817
 * This function is called, when the user clicks at the menu point
818
 * "Save Heart Rate".
819
 * First, a file dialog box is displayed, where the user can choose a
820
 * directory and a file name to save the heart rate.
821
 * If the file could successfully be created, the heart rate is saved
137 andreas 822
 * in the "HRM"-format. This is the native format Polar uses to store
88 andreas 823
 * heart rate data. I've choosen this format, because it's popular and
824
 * used by many other software too.
825
 */
826
void sportwatcherWidget::extrasSaveHR()
827
{
828
QString fname, str1, str2;
829
QFile fdfile;
830
QDateTime *qt, *oldqt;
831
QDate dat;
832
QTime t;
833
QDir dir = QDir::home();
834
char hv0[256];
835
RUN_NODE *rn;
836
LAP *lap, *alap;
837
POINT *point;
838
int samples, smp, seconds, anz, nsec, samsec;
839
int avgHeart, minHeart, maxHeart, aktHeart;
840
int secRange1, secRange2, secRange3, secAbove, secBeyond;
841
 
842
	if (!gmn)
843
	{
844
	   KMessageBox::information(this, i18n("There is no activity open"));
845
	   return;
846
	}
847
 
848
	if (HRM.isEmpty())
849
	   str1 = dir.path();
850
	else
851
	   str1 = HRM;
852
 
853
	str1 +=  "/" + StartTime.toString("yyyyMMddThhmmss.zzz.hrm");
854
	fname = KFileDialog::getSaveFileName(str1, QString("*.hrm"), this, QString("SportWatcher"));
855
 
856
	if (fname.isEmpty())
857
	   return;
858
 
859
	fdfile.setName(fname);
860
 
861
	if (fdfile.exists())
862
	{
863
	   if (KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
864
	      return;
865
	}
866
 
867
	if (!fdfile.open(IO_ReadWrite | IO_Truncate))
868
	{
869
	   KMessageBox::error(this, i18n("Error creating a file!\nPlease check permissions."));
870
	   return;
871
	}
872
 
873
	rn = ds.getRunNode();
874
	lap = ds.getLap(rn->run->first_lap_index);
875
	t = StartTime.time();
876
	dat = StartTime.date();
877
 
878
	if ((point = ds.getPoint(lap->start_time)) == 0)
879
	{
880
	   fdfile.close();
881
	   return;
882
	}
883
 
884
	strcpy (hv0, "[Params]\n");
885
	write(fdfile.handle(), &hv0[0], strlen(hv0));
886
	str1 = dat.toString("yyyyMMdd");
887
	str2 = t.toString("hh:mm:ss.z");
888
	sprintf(hv0, "Version=106\nMonitor=11\nSMode=000000000\nDate=%s\nStartTime=%s\n",
889
		str1.ascii(), str2.ascii());
890
	write(fdfile.handle(), &hv0[0], strlen(hv0));
891
	t.setHMS(0, 0, 0);
892
	t = t.addSecs(max_time);
893
	str2 = t.toString("hh:mm:ss.z");
894
 
895
	switch (sampleTime)
896
	{
897
	   case 0: samsec = 5; break;
898
	   case 1: samsec = 15; break;
899
	   case 2: samsec = 30; break;
900
	   case 3: samsec = 60; break;
901
	   default:
902
	      samsec = 15;
903
	}
904
 
905
	sprintf(hv0, "Length=%s\nInterval=%d\nUpper1=%d\nLower1=%d\nUpper2=%d\n",
906
	   str2.ascii(), samsec, upper1, lower1, upper2);
907
	write(fdfile.handle(), &hv0[0], strlen(hv0));
908
	sprintf(hv0, "Lower2=%d\nUpper3=%d\nLower3=%d\nTimer1=00:00:00.0\n",
909
		lower2, upper3, lower3);
910
	write(fdfile.handle(), &hv0[0], strlen(hv0));
911
	strcpy(hv0, "Timer2=00:00:00.0\nTimer3=00:00:00.0\nActiveLimit=0\n");
912
	write(fdfile.handle(), &hv0[0], strlen(hv0));
913
	sprintf(hv0, "MaxHR=%d\nRestHR=%d\nStartDelay=0\nVO2max=%d\nWeight=%d\n\n",
914
		MaxHr, restHr, vo2max, weight);
915
	write(fdfile.handle(), &hv0[0], strlen(hv0));
916
 
917
	// Write the intervall times. One block for every lap
918
	secRange1 = secRange2 = secRange3 = secAbove = secBeyond = 0;
919
	strcpy(hv0, "[IntTimes]\n");
920
	write(fdfile.handle(), &hv0[0], strlen(hv0));
921
	t.setHMS(0, 0, 0);
922
 
923
	for (unsigned int i = rn->run->first_lap_index; i < rn->run->last_lap_index; i++)
924
	{
925
	   alap = ds.getLap(i);
926
	   point = ds.getPoint(alap->start_time);
927
	   oldqt = garmin_dtime(point->time);
928
	   avgHeart = minHeart = maxHeart = aktHeart = 0;
929
	   anz = 0;
930
	   unsigned long lastTime = point->time;
931
	   int totSec = 0;
932
 
933
	   while (point)
934
	   {
935
	      if (point->time > (alap->start_time + (alap->total_time / 100)))
936
		 break;
937
 
938
	      if (point->heart_rate > 0)
939
	      {
940
		 avgHeart += point->heart_rate;
941
		 nsec = point->time - lastTime;
942
		 totSec += nsec;
943
 
944
		 if (minHeart == 0 || minHeart > point->heart_rate)
945
		    minHeart = point->heart_rate;
946
 
947
		 if (maxHeart < point->heart_rate)
948
		    maxHeart = point->heart_rate;
949
 
950
		 if (aktHeart == 0 && totSec >= samsec)
951
		    aktHeart = avgHeart / (anz + 1);
952
 
953
		 if (point->heart_rate < lower1)
954
		    secBeyond += nsec;
955
		 else if (point->heart_rate < lower2)
956
		    secRange1 += nsec;
957
		 else if (point->heart_rate < lower3)
958
		    secRange2 += nsec;
959
		 else if (point->heart_rate < upper3)
960
		    secRange3 += nsec;
961
		 else
962
		    secAbove += nsec;
963
 
964
		 lastTime = point->time;
965
		 anz++;
966
	      }
967
 
968
	      point = ds.getPoint(point->time+1);
969
	   }
970
 
971
	   t = t.addSecs(alap->total_time / 100);
972
	   str1 = t.toString("hh:mm:ss.z");
973
	   sprintf(hv0, "%s\t %d\t %d\t %d\t %d\n",
974
	      str1.ascii(), aktHeart, minHeart, avgHeart / anz, maxHeart);
975
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
976
	   strcpy(hv0, "32\t 0\t 0\t 0\t 0\t 0\n");
977
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
978
	   strcpy(hv0, "0\t 0\t 0\t 0\t 0\n");
979
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
980
	   sprintf(hv0, "0\t %d\t 0\t 0\t 0\t 0\n", (int)alap->total_distance);
981
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
982
	   strcpy(hv0, "0\t 0\t 0\t 0\t 0\t 0\n");
983
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
984
	}
985
 
986
	strcpy(hv0, "\n[IntNotes]\n\n[ExtraData]\n\n");
987
	write(fdfile.handle(), &hv0[0], strlen(hv0));
988
 
989
	strcpy(hv0, "[Summary-123]\n");
990
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
991
	smp = max_time - secBeyond - secRange1 - secRange2 - secRange3 - secAbove;
992
	sprintf(hv0, "%u\t %u\t %u\t %u\t %u\n",
993
		max_time, secRange1, secRange2 + secRange3,
994
		secAbove + secBeyond, smp);
995
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 1
996
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
997
		MaxHr, upper1, lower1, restHr);
998
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
999
	sprintf(hv0, "%u\t %u\t %u\t %u\t %u\n",
1000
		max_time, secRange2, secRange1 + secRange3,
1001
		secAbove + secBeyond, smp);
1002
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 2
1003
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
1004
		MaxHr, upper2, lower2, restHr);
1005
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 2
1006
	sprintf(hv0, "%u\t %u\t %u\t %u\t %u\n",
1007
		max_time, secRange3, secRange1 + secRange2,
1008
		secAbove + secBeyond, smp);
1009
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 3
1010
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
1011
		MaxHr, upper3, lower3, restHr);
1012
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 3
1013
	samples = max_time / samsec;
1014
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
1015
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1016
 
1017
	strcpy(hv0, "[Summary-TH]\n");
1018
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1019
	sprintf(hv0, "%u\t 0\t %u\t %d\t %d\t 0\n", max_time, max_time - max_hr - restHr, max_hr, restHr);
1020
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1021
	sprintf(hv0, "%d\t %d\t %d\t %d\n", MaxHr, upper3, lower1, restHr);
1022
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1023
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
1024
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1025
 
1026
	sprintf(hv0, "[HRZones]\n%d\n%d\n%d\n%d\n%d\n%d\n0\n0\n0\n0\n0\n\n",
1027
		MaxHr, upper3, upper2, upper1, lower1, restHr);
1028
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1029
 
1030
	strcpy(hv0, "[HRData]\n");
1031
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1032
 
1033
	smp = 0;		// average heart rate of 15 seconds
1034
	seconds = 0;
1035
	anz = 0;
1036
	nsec = samsec;
1037
	oldqt = garmin_dtime(lap->start_time);
1038
	qt = 0;
1039
	point = ds.getPoint(lap->start_time);
1040
 
1041
	while (point)
1042
	{
1043
	   if (seconds >= nsec)
1044
	   {
1045
	      if (anz > 0)
1046
	      {
1047
		 sprintf(hv0, "%d\n", smp / anz);
1048
		 write(fdfile.handle(), &hv0[0], strlen(hv0));
1049
	      }
1050
 
1051
	      if (smp > 0 && seconds >= (nsec + samsec))
1052
	      {
1053
		 if (anz <= 0)
1054
		    anz = 0;
1055
 
1056
		 for (int x = nsec; x < seconds; x += samsec)
1057
		 {
1058
		    sprintf(hv0, "%d\n", smp / anz);
1059
		    write(fdfile.handle(), &hv0[0], strlen(hv0));
1060
		    nsec += samsec;
1061
		 }
1062
	      }
1063
 
1064
	      anz = 0;
1065
	      smp = 0;
1066
	      nsec += samsec;
1067
	   }
1068
 
1069
	   qt = garmin_dtime (point->time);
1070
	   seconds += oldqt->secsTo(*qt);
1071
 
1072
	   if (point->heart_rate > 0)
1073
	   {
1074
	      smp += point->heart_rate;
1075
	      anz++;
1076
	   }
1077
 
1078
	   delete oldqt;
1079
	   oldqt = qt;
1080
	   point = ds.getPoint(point->time + 1);
1081
	}
1082
 
1083
	fdfile.close();
1084
	KMessageBox::information(this, i18n("File successfully written."));
1085
}
1086
 
1087
void sportwatcherWidget::extrasSettings()
1088
{
1089
settingsWidget *dlg = new settingsWidget(this, "settingsWidgetBase", TRUE, 0);
1090
 
1091
	if (dlg->exec() == QDialog::Accepted)
1092
	{
1093
	   KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"), true);
1094
	   cfg->setGroup(QString("SportWatcher"));
1095
	   lower1 = cfg->readNumEntry("lower1");
1096
	   lower2 = cfg->readNumEntry("lower2");
1097
	   lower3 = cfg->readNumEntry("lower3");
1098
	   upper1 = cfg->readNumEntry("upper1");
1099
	   upper2 = cfg->readNumEntry("upper2");
1100
	   upper3 = cfg->readNumEntry("upper3");
1101
	   MaxHr = cfg->readNumEntry("maxHr");
1102
	   restHr = cfg->readNumEntry("restHr");
1103
	   vo2max = cfg->readNumEntry("vo2max");
1104
	   weight = cfg->readNumEntry("weight");
1105
	   sampleTime = cfg->readNumEntry("seconds");
149 andreas 1106
	   Serial = cfg->readBoolEntry("Serial");
88 andreas 1107
	   Device = cfg->readEntry("Device");
1108
	   Data = cfg->readEntry("Data");
1109
	   HRM = cfg->readEntry("HRM");
151 andreas 1110
	   MAP = cfg->readEntry("MAP");
149 andreas 1111
	   Units = cfg->readNumEntry("Units");
88 andreas 1112
	   delete cfg;
1113
	}
1114
 
1115
	delete dlg;
151 andreas 1116
 
1117
	if (poDataset)
1118
	   GDALClose (poDataset);
1119
 
1120
	poDataset = (GDALDataset *)GDALOpen (MAP.ascii(), GA_ReadOnly);
1121
 
1122
	if( poDataset == NULL )
1123
	   KMessageBox::error(this, i18n("Error opening or initializing the MAP-Database!\nThere will be no map available."));
88 andreas 1124
}
1125
 
1126
/*
1127
 * Functions to fill in the boxes of the main mask.
1128
 */
1129
void sportwatcherWidget::showLaps()
1130
{
1131
QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
1132
QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
1133
QDateTime dt;
1134
QTime t, st;
1135
QDateTime *qt;
1136
LAP *lap;
1137
POINT *point;
1138
RUN_NODE *rakt, *rn;
149 andreas 1139
int laps, i, anz, men, cad;
1140
double alt_asc, alt_dsc, sum_asc, sum_dsc, old_asc, old_dsc;
88 andreas 1141
 
1142
	if (!gmn)
1143
	{
1144
	   KMessageBox::error(0, i18n("No data were loaded!"));
1145
	   return;
1146
	}
1147
 
1148
	if (gmn->type == data_Dnil)
1149
	{
1150
	   KMessageBox::error(0, i18n("No data found!"));
1151
	   return;
1152
	}
1153
 
1154
	if (gmn->type != data_Dlist)     /* List of data */
1155
	{
1156
	   KMessageBox::error(0, QString("Found unexpected data type %1!").arg(gmn->type));
1157
	   return;
1158
	}
1159
 
1160
	ds.destroy();
1161
	min_hr = max_hr = 0;
1162
	min_height = max_height = 0.0;
1163
	liLaps->clear();
100 andreas 1164
	liLaps->setAllColumnsShowFocus(true);
88 andreas 1165
	ds.garmin_print_data(gmn);
1166
	rn = ds.getRunNode();
1167
	rakt = rn;
1168
	liLaps->setRootIsDecorated(true);
128 andreas 1169
	liLaps->setAlternateBackground(KGlobalSettings::alternateBackgroundColor());
88 andreas 1170
	liLaps->setColumnAlignment(1, Qt::AlignRight);
1171
	liLaps->setColumnAlignment(2, Qt::AlignRight);
1172
	liLaps->setColumnAlignment(3, Qt::AlignRight);
1173
	liLaps->setColumnAlignment(4, Qt::AlignRight);
1174
	liLaps->setColumnAlignment(5, Qt::AlignRight);
1175
	liLaps->setColumnAlignment(6, Qt::AlignRight);
1176
	liLaps->setColumnAlignment(7, Qt::AlignRight);
1177
	liLaps->setColumnAlignment(8, Qt::AlignRight);
1178
	liLaps->setColumnAlignment(9, Qt::AlignRight);
1179
	liLaps->setColumnAlignment(10, Qt::AlignRight);
1180
	liLaps->setColumnAlignment(11, Qt::AlignRight);
1181
 
1182
	qs_name = qs_distance = qs_etime = qs_avgpace = qs_avgspeed = qs_maxspeed = QString("");
1183
	qs_calories = qs_avghr = qs_maxhr = qs_avgcadence = qs_ascent = qs_descent = QString("");
1184
	men = 0;
149 andreas 1185
	cad = 0;
88 andreas 1186
 
1187
	while (rakt)
1188
	{
1189
	   if (rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
1190
	   	rakt->run->type == data_D1010)
1191
	   {
1192
	   int lt, cal, ahr, mhr;
1193
	   double distance, speed, mspeed;
1194
	   QDate dat;
1195
 
1196
	      switch (rakt->run->sport_type)
1197
	      {
1198
		 case D1000_running: qs_name = QString("Running: "); break;
1199
		 case D1000_biking:  qs_name = QString("Biking: "); break;
1200
		 case D1000_other:   qs_name = QString("Other: "); break;
1201
		 default:
1202
		    qs_name = QString("Unknown: ");
1203
	      }
1204
 
1205
	      lap = ds.getLap(rakt->run->first_lap_index);
1206
	      qt = garmin_dtime (lap->start_time);
1207
	      StartTime = *qt;
1208
	      st = qt->time();
1209
	      dat = qt->date();
1210
	      delete qt;
1211
	      lap = ds.getLap(rakt->run->last_lap_index);
1212
	      qt = garmin_dtime (lap->start_time);
1213
	      t = qt->addSecs(lap->total_time / 100).time();
1214
	      lt = st.secsTo(t);
1215
	      t.setHMS(0, 0, 0);
1216
	      t = t.addSecs(lt);
1217
	      qt->setDate(dat);
1218
	      qt->setTime(t);
1219
	      qs_name.append(dat.toString("dd.MM.yyyy"));
1220
	      qs_name.append(" ");
1221
	      qs_name.append(st.toString("hh:mm:ss"));
1222
	      max_time = lt;
1223
	      qs_etime = QString(qt->toString("hh:mm:ss.zzz"));
1224
 
1225
	      distance = 0.0;
1226
	      cal = 0;
1227
	      mspeed = 0;
1228
	      ahr = mhr = 0;
1229
	      anz = 0;
149 andreas 1230
	      cad = 0;
1231
	      sum_asc = sum_dsc = old_asc = old_dsc = 0;
88 andreas 1232
 
1233
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
1234
	      {
1235
		 if ((lap = ds.getLap(i)) == NULL)
1236
		    continue;
1237
 
1238
		 distance += lap->total_distance;
1239
		 cal += lap->calories;
149 andreas 1240
 
1241
		 if (lap->avg_cadence != 0xff)
1242
		    cad += lap->avg_cadence;
1243
 
88 andreas 1244
		 ahr += lap->avg_heart_rate;
1245
		 anz++;
1246
 
1247
		 if (lap->max_speed > mspeed)
1248
		    mspeed = lap->max_speed;
1249
 
1250
		 if (lap->max_heart_rate > mhr)
1251
		    mhr = lap->max_heart_rate;
1252
	      }
1253
 
149 andreas 1254
	      if (Units == 1)		// Statute?
1255
		 qs_distance.sprintf("%.2f ft", distance / 0.304);
1256
	      else
1257
	         qs_distance.sprintf("%.2f m", distance);
1258
 
104 andreas 1259
	      total_distance = distance;
88 andreas 1260
 
1261
	      if (distance > 0)
1262
	      {
1263
		 QTime tt = qt->time();
1264
		 long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0 * (1000.0 / distance * 100.0);
1265
		 int h = secs / 3600;
1266
		 int m = (secs - (h * 3600)) / 60;
1267
		 int s = secs - ((h * 3600) + (m * 60));
1268
		 t = QTime(h, m, s, 0);
1269
		 qs_avgpace = t.toString("  hh:mm:ss");
149 andreas 1270
//		 qs_avgpace.append(QString(" /lap"));
88 andreas 1271
	      }
1272
 
149 andreas 1273
	      if (Units == 1)		// Statute?
1274
		 speed = distance / lt;
1275
	      else
1276
		 speed = distance / lt * 3.6;
1277
 
1278
	      qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mi/h" : "km/h");
1279
	      qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed : mspeed * 3.6, (Units == 1) ? "mi/h" : "km/h");
88 andreas 1280
	      qs_calories.sprintf("%d", cal);
1281
	      qs_avghr.sprintf("%d bpm", ahr / anz);
1282
	      qs_maxhr.sprintf("%d bpm", mhr);
1283
 
149 andreas 1284
	      if (cad > 0)
1285
		 qs_avgcadence.sprintf("%d", cad / anz);
1286
 
128 andreas 1287
	      KListViewItem *element = new KListViewItem(liLaps, qs_name, qs_distance,
88 andreas 1288
		qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed, qs_calories, qs_avghr);
1289
	      element->setText(8, qs_maxhr);
1290
	      element->setText(9, qs_avgcadence);
1291
	      element->setText(10, qs_ascent);
1292
	      element->setText(11, qs_descent);
1293
	      element->sortChildItems(0, false);
1294
	      element->setOpen(true);
128 andreas 1295
	      element->setPixmap(0, QPixmap::fromMimeSource(QString("activity.png")));
88 andreas 1296
	      liLaps->insertItem(element);
1297
	      delete qt;
1298
	      /* Get the laps. */
1299
	      laps = 1;
1300
 
1301
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
1302
	      {
149 andreas 1303
		 double spd;
1304
		 char *un;
1305
 
88 andreas 1306
		 if ((lap = ds.getLap(i)) == NULL)
1307
		    continue;
1308
 
1309
		 qt = garmin_dtime (lap->start_time);
1310
		 qs_name.sprintf("Lap %03d - ", laps);
1311
		 qs_name.append(qt->toString("hh:mm:ss"));
149 andreas 1312
		 qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
88 andreas 1313
		 t = QTime(0, 0, 0, 0);
1314
		 t = t.addMSecs(lap->total_time * 10);
1315
		 qs_etime = t.toString("hh:mm:ss.zzz");
149 andreas 1316
		 spd = lap->total_distance / (lap->total_time / 100.0);
1317
 
1318
		 if (Units == 0)
1319
		 {
1320
		    un = (char *)"km/h";
1321
		    spd *= 3.6;
1322
		 }
1323
		 else
1324
		    un = (char *)"mi/h";
1325
 
1326
		 qs_avgspeed.sprintf("%.2f %s", spd, un);
1327
		 qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? lap->max_speed : lap->max_speed * 3.6, un);
88 andreas 1328
		 qs_calories.sprintf("%d", lap->calories);
1329
 
1330
		 if (lap->total_distance > 0 && lap->total_time != 0)
1331
		 {
1332
		    long secs = (double)lap->total_time / 10000.0 * (1000.0 / lap->total_distance * 100.0);
1333
		    int h = secs / 3600;
1334
		    int m = (secs - (h * 3600)) / 60;
1335
		    int s = secs - ((h * 3600) + (m * 60));
1336
		    t = QTime(h, m, s, 0);
1337
		    qs_avgpace = t.toString("hh:mm:ss");
149 andreas 1338
//		    qs_avgpace.append(QString(" /lap"));
88 andreas 1339
		 }
1340
 
1341
		 qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
1342
		 qs_maxhr.sprintf("%d bpm", lap->max_heart_rate);
1343
 
1344
		 anz = 0;
1345
		 alt_asc = alt_dsc = 0;
1346
 
1347
		 if ((point = ds.getPoint(lap->start_time)) != 0)
1348
		 {
1349
		    if (point->alt < 20000)
149 andreas 1350
		    {
88 andreas 1351
		       alt_dsc = alt_asc = point->alt;
149 andreas 1352
 
1353
		       if (old_asc == 0)
1354
			  old_asc = alt_asc;
1355
 
1356
		       if (old_dsc == 0)
1357
			  old_dsc = alt_dsc;
1358
		    }
88 andreas 1359
		    else
1360
		       alt_dsc = alt_asc = 0;
1361
 
1362
		    while (point)
1363
		    {
1364
		       if (point->time > (lap->start_time + (lap->total_time / 100)))
1365
			 break;
1366
 
1367
		       if (point->alt > alt_asc && point->alt < 20000)
1368
		       {
1369
			  alt_asc = point->alt;
1370
 
1371
			  if (alt_dsc == 0)
1372
			     alt_dsc = point->alt;
1373
		       }
1374
 
1375
		       if (point->alt < alt_dsc)
1376
			  alt_dsc = point->alt;
1377
 
1378
		       // save the min and max values. We need this information to
1379
		       // build the graphics.
1380
		       if (point->heart_rate > max_hr)
1381
			  max_hr = point->heart_rate;
1382
 
1383
		       if ((min_hr == 0 && point->heart_rate > 0) || (point->heart_rate > 0 && point->heart_rate < min_hr))
1384
			  min_hr = point->heart_rate;
1385
 
1386
		       if (point->alt < 20000 && max_height < point->alt)
1387
			  max_height = point->alt;
1388
 
1389
		       if (point->alt < 20000 && (min_height == 0.0 || min_height > point->alt))
1390
			  min_height = point->alt;
1391
 
1392
		       if (point->heart_rate > 0)
1393
		       {
1394
			  avg_hr += point->heart_rate;
1395
			  men++;
1396
		       }
1397
 
1398
		       point = ds.getPoint(point->time + 1);
1399
		    }
1400
 
149 andreas 1401
		    if (old_asc < alt_asc)
1402
		       sum_asc += (alt_asc - old_asc);
1403
 
1404
		    if (old_dsc > alt_dsc)
1405
		       sum_dsc += (old_dsc - alt_dsc);
1406
 
1407
		    old_asc = alt_asc;
1408
		    old_dsc = alt_dsc;
1409
		    qs_ascent.sprintf("%.2f %s", (Units == 1) ? (alt_asc / 0.304) : alt_asc, (Units == 1) ? "ft" : "m");
1410
		    qs_descent.sprintf("%.2f %s", (Units == 1) ? (alt_dsc / 0.304) : alt_dsc, (Units == 1) ? "ft" : "m");
88 andreas 1411
		 }
1412
 
1413
		 if (lap->avg_cadence != 0xff)
1414
		    qs_avgcadence.sprintf("%d", lap->avg_cadence);
1415
 
128 andreas 1416
		 KListViewItem *edetail = new KListViewItem(element, qs_name, qs_distance,
88 andreas 1417
			qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed, qs_calories, qs_avghr);
1418
		 edetail->setText(8, qs_maxhr);
1419
		 edetail->setText(9, qs_avgcadence);
1420
		 edetail->setText(10, qs_ascent);
1421
		 edetail->setText(11, qs_descent);
128 andreas 1422
		 edetail->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
1423
 
1424
		 switch (rakt->run->sport_type)
1425
		 {
1426
		    case D1000_running: edetail->setPixmap(0, QPixmap::fromMimeSource(QString("run.png"))); break;
1427
		    case D1000_biking:  edetail->setPixmap(0, QPixmap::fromMimeSource(QString("bike.png"))); break;
1428
		    case D1000_other:   edetail->setPixmap(0, QPixmap::fromMimeSource(QString("other.png"))); break;
1429
		    default:
1430
		       edetail->setPixmap(0, QPixmap::fromMimeSource(QString("other.png")));
1431
		 }
1432
 
88 andreas 1433
		 liLaps->clearSelection();
1434
		 element->insertItem(edetail);
1435
		 delete qt;
1436
		 laps++;
1437
	      }
149 andreas 1438
 
1439
	      qs_ascent.sprintf("%.2f %s", (Units == 1) ? sum_asc / 0.304 : sum_asc, (Units == 1) ? "ft" : "m");
1440
	      qs_descent.sprintf("%.2f %s", (Units == 1) ? sum_dsc / 0.304 : sum_dsc, (Units == 1) ? "ft" : "m");
1441
      	      element->setText(10, qs_ascent);
1442
	      element->setText(11, qs_descent);
88 andreas 1443
	   }
1444
 
1445
	   rakt = rakt->next;
1446
	}
1447
 
1448
	if (men > 0)
1449
	   avg_hr /= men;
1450
}
1451
 
100 andreas 1452
void sportwatcherWidget::showTrack()
1453
{
132 andreas 1454
	showTrack(0, QRect(0, 0, 0, 0), 0);
104 andreas 1455
}
1456
 
1457
void sportwatcherWidget::showTrack(int zoom)
1458
{
132 andreas 1459
	showTrack(zoom, mapPan, mapLap);
1460
}
1461
 
1462
void sportwatcherWidget::showTrack(int zoom, const QRect &pan, LAP *lap)
1463
{
100 andreas 1464
int width, height;
1465
double x1, y1, x2, y2;
132 andreas 1466
int a, top, left, panX, panY;
1467
uint32 i;
109 andreas 1468
double coordW, coordH, tick;
128 andreas 1469
double meterW, dist;
100 andreas 1470
QPainter paint;
104 andreas 1471
posn_type posNW, posSE;
100 andreas 1472
POINT *point;
151 andreas 1473
#ifdef GDAL
1474
GDALDataset *poDataset;
1475
//double adfGeoTransform[6];
1476
GDALRasterBand *poBand;
1477
unsigned char *pafScanline;
1478
unsigned char *pafScanlineRed;
1479
unsigned char *pafScanlineGreen;
1480
unsigned char *pafScanlineBlue;
1481
int nXSize, nYSize;
1482
#endif
100 andreas 1483
 
109 andreas 1484
	if (!gmn)
1485
	   return;
1486
 
104 andreas 1487
	if (zoom != zfactor)
1488
	   zfactor = zoom;
1489
 
132 andreas 1490
	if (mapLap != lap)
1491
	   mapLap = lap;
1492
 
148 andreas 1493
	width = imgMap->width() - 2;
1494
	height = imgMap->height();
100 andreas 1495
	pmMap.resize(width, height);
1496
	paint.begin(&pmMap);
1497
 
132 andreas 1498
	panX = panY = 0;
1499
 
1500
	if (stateHand && mapPan != pan)
1501
	{
1502
	   mapPan = pan;
1503
	   panX = mapPan.right() - mapPan.left();
1504
	   panY = mapPan.bottom() - mapPan.top();
1505
	   oldTransX += (double)panX;
1506
	   oldTransY += (double)panY;
1507
//	   paint.translate(oldTransX, oldTransY);
1508
	}
1509
 
104 andreas 1510
	memset(&posNW, 0, sizeof(posn_type));
1511
	memset(&posSE, 0, sizeof(posn_type));
100 andreas 1512
 
1513
	posSE.lat = 9999.0;
1514
	posNW.lon = 9999.0;
1515
 
1516
	/*
1517
	 * Find out the corners of our track (NW, NE, SE, SW)
1518
	 */
132 andreas 1519
	if (mapLap)
1520
	   i = mapLap->start_time;
1521
	else
1522
	   i = 0;
100 andreas 1523
 
1524
	while ((point = ds.getPoint(i)) != 0)
1525
	{
132 andreas 1526
	   if (mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
1527
	      break;
1528
 
100 andreas 1529
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1530
	   {
132 andreas 1531
	      i = point->time + 1;
100 andreas 1532
	      continue;
1533
	   }
1534
 
1535
	   if (SEMI2DEG(point->posn.lat) > posNW.lat)
1536
	      posNW.lat = SEMI2DEG(point->posn.lat);
1537
 
1538
	   if (SEMI2DEG(point->posn.lat) < posSE.lat)
1539
	      posSE.lat = SEMI2DEG(point->posn.lat);
1540
 
1541
	   if (SEMI2DEG(point->posn.lon) < posNW.lon)
1542
	      posNW.lon = SEMI2DEG(point->posn.lon);
1543
 
1544
	   if (SEMI2DEG(point->posn.lon) > posSE.lon)
1545
	      posSE.lon = SEMI2DEG(point->posn.lon);
1546
 
132 andreas 1547
	   i = point->time + 1;
100 andreas 1548
	}
104 andreas 1549
 
1550
	coordW = (posNW.lon > posSE.lon) ? posNW.lon - posSE.lon : posSE.lon - posNW.lon;
1551
	coordH = (posNW.lat > posSE.lat) ? posNW.lat - posSE.lat : posSE.lat - posNW.lat;
109 andreas 1552
	meterW = ds.earth_distance(posNW.lat, posNW.lon, posNW.lat, posSE.lon);
104 andreas 1553
 
1554
	// define the ticks to translate the GPS coordinates into pixels.
1555
	// The track should be centered and we have to calculate the
1556
	// rectangular within we draw the track.
100 andreas 1557
	if (width > height)
1558
	{
109 andreas 1559
	   if (coordW > coordH)
1560
	      tick = (double)height / coordW + (double)zoom;
1561
	   else
1562
	      tick = (double)height / coordH + (double)zoom;
1563
 
1564
	   left = (width - tick * coordW) / 2;
1565
	   top = (height - tick * coordH) / 2;
100 andreas 1566
	}
1567
	else
1568
	{
109 andreas 1569
	   if (coordW > coordH)
1570
	      tick = (double)width / coordW + (double)zoom;
1571
	   else
1572
	      tick = (double)width / coordH + (double)zoom;
1573
 
1574
	   left = (width - tick * coordW) / 2;
1575
	   top = (height - tick * coordH) / 2;
100 andreas 1576
	}
104 andreas 1577
 
132 andreas 1578
	a = tick * coordW;
1579
	dist = meterW / a;
151 andreas 1580
#ifdef GDAL
146 andreas 1581
	/*
1582
	 * If we have a map file, we try to read it and if successfull,
1583
	 * we should get a map painted.
1584
	 */
151 andreas 1585
	if (!MAP.isEmpty())
146 andreas 1586
	{
151 andreas 1587
	   if (writeWMSTag(posNW.lon, posNW.lat, posSE.lon, posSE.lat, width, height))
1588
	   {
1589
	      if ((poDataset = (GDALDataset *)GDALOpen (MAP.ascii(), GA_ReadOnly)) != NULL)
1590
	      {
1591
		 QPixmap bild;
1592
//		 int nRasterXSize = poDataset->GetRasterXSize();
1593
//		 int nRasterYSize = poDataset->GetRasterYSize();
1594
		 int nRasterCount = poDataset->GetRasterCount();
1595
		 int nXBlock, nYBlock;
1596
		 BMP_HEADER bmpH;
1597
		 BMP_INFO bmpI;
1598
		 int bmpSize = sizeof(BMP_HEADER) + sizeof(BMP_INFO) + 2;
146 andreas 1599
 
151 andreas 1600
//		 int             nBlockXSize, nBlockYSize;
1601
		 int             bGotMin, bGotMax;
1602
		 int		 tTypeLen, tColor, tColorEntrys;
1603
		 GDALDataType    tRasterType;
1604
		 double          adfMinMax[2];
1605
 
1606
		 for (a = 1; a <= nRasterCount; a++)
1607
		 {
1608
		    poBand = poDataset->GetRasterBand (a);
1609
		    poBand->GetBlockSize (&nXBlock, &nYBlock);
1610
		    nXSize = poBand->GetXSize();
1611
		    nYSize = poBand->GetYSize();
1612
		    tRasterType = poBand->GetRasterDataType ();
1613
		    tTypeLen = GDALGetDataTypeSize (tRasterType) / 8;	// We need Bytes not Bits!
1614
		    tColor = poBand->GetColorInterpretation ();
1615
 
1616
		    adfMinMax[0] = poBand->GetMinimum (&bGotMin);
1617
		    adfMinMax[1] = poBand->GetMaximum (&bGotMax);
1618
 
1619
		    if (!(bGotMin && bGotMax))
1620
		       GDALComputeRasterMinMax ((GDALRasterBandH)poBand, TRUE, adfMinMax);
1621
 
1622
		    if (poBand->GetColorTable() != NULL)
1623
		       tColorEntrys = poBand->GetColorTable()->GetColorEntryCount();
1624
 
1625
		    switch (a)
1626
		    {
1627
		       case 1: pafScanlineRed   = new unsigned char[tTypeLen * nXBlock * nYBlock]; pafScanline = pafScanlineRed; break;
1628
		       case 2: pafScanlineGreen = new unsigned char[tTypeLen * nXBlock * nYBlock]; pafScanline = pafScanlineGreen; break;
1629
		       case 3: pafScanlineBlue  = new unsigned char[tTypeLen * nXBlock * nYBlock]; pafScanline = pafScanlineBlue; break;
1630
		    }
1631
 
1632
		    memset (pafScanline, 0, tTypeLen * nXBlock * nYSize);
1633
 
1634
		    if (poBand->RasterIO (GF_Read, 0, 0, nXSize, nYSize, pafScanline, nXBlock, nYBlock, tRasterType, 0, 0) == CE_Failure)
1635
		       KMessageBox::error(this, i18n("Error reading a raster band!"));
1636
		 }
1637
 
1638
		 unsigned char *pCombinedBytes = new unsigned char[(tTypeLen * nXBlock * nYBlock * nRasterCount) + bmpSize];
1639
		 int offset;
1640
 
1641
		 for (a = 0; a < nYSize; a++)
1642
		 {
1643
		    for (int j = 0; j < nXBlock; j++)
1644
		    {
1645
		       offset = a * nXBlock * 3 + (j * 3) + bmpSize;
1646
		       pCombinedBytes[offset]     = *(pafScanlineBlue + ((nYSize - a) * nXBlock + j));
1647
		       pCombinedBytes[offset + 1] = *(pafScanlineGreen + ((nYSize - a) * nXBlock + j));
1648
		       pCombinedBytes[offset + 2] = *(pafScanlineRed + ((nYSize - a) * nXBlock + j));
1649
		    }
1650
		 }
1651
 
1652
		 fillBMPHeader (&bmpH, &bmpI, nXBlock, nYSize, nRasterCount);
1653
		 memcpy (pCombinedBytes+2, &bmpH, sizeof(BMP_HEADER));
1654
		 memcpy (pCombinedBytes + sizeof(BMP_HEADER) + 2, &bmpI, sizeof(BMP_INFO));
1655
		 *pCombinedBytes = 'B';
1656
		 *(pCombinedBytes+1) = 'M';
1657
/* QFile qf(QString("/tmp/testbild.bmp"));
1658
qf.open(IO_ReadWrite | IO_Truncate);
1659
write(qf.handle(), pCombinedBytes, (tTypeLen * nXSize * nYSize * nRasterCount) + bmpSize);
1660
qf.close(); */
1661
		 if (!bild.loadFromData (pCombinedBytes, (tTypeLen * nXBlock * nYSize * nRasterCount) + bmpSize, "BMP"))
1662
		    KMessageBox::error(this, i18n("Error reading the binary data!"));
1663
		 else
1664
		    paint.drawPixmap (0, 0, bild);
1665
 
1666
		 delete pafScanlineRed;
1667
		 delete pafScanlineGreen;
1668
		 delete pafScanlineBlue;
1669
		 delete pCombinedBytes;
1670
	      }
1671
	      else
1672
		 KMessageBox::error(this, i18n("Error opening WMS file!"));
1673
 
1674
	      GDALClose (poDataset);
1675
	      poDataset = 0;
1676
	   }
146 andreas 1677
	}
151 andreas 1678
#endif
100 andreas 1679
	// Colors and fonts
1680
	QColor background(220, 220, 220);
104 andreas 1681
	QColor red(255, 0, 0);
100 andreas 1682
	QColor black(0, 0, 0);
1683
	QColor yellow(255, 255, 0);
1684
	QFont fntNormal("Helvetica");
1685
	fntNormal.setPixelSize(10);
1686
	fntNormal.setStyleHint(QFont::Helvetica);
104 andreas 1687
	QPen dot(red, 4, QPen::SolidLine);
100 andreas 1688
	QPen line(black, 1, QPen::SolidLine);
1689
	QPen yline(yellow, 3, QPen::SolidLine);
1690
	// Fill background with background colors
151 andreas 1691
#ifndef GDAL
100 andreas 1692
	paint.fillRect(0, 0, width+2, height+2, background);
151 andreas 1693
#endif
109 andreas 1694
	paint.setPen(line);
1695
	paint.drawLine(10, height - 9, 10, height - 4);
1696
	paint.drawLine(10, height - 4, 10 + (1000 / dist), height - 4);
1697
	paint.drawLine(10 + (1000 / dist), height - 9, 10 + (1000 / dist), height - 4);
1698
	paint.setFont(fntNormal);
1699
	paint.drawText(10, height - 10, QString("1000 m"));
1700
 
100 andreas 1701
	// Draw track
132 andreas 1702
	if (mapLap)
1703
	   i = mapLap->start_time;
1704
	else
1705
	   i = 0;
1706
 
100 andreas 1707
	x1 = y1 = 0.0;
104 andreas 1708
 
100 andreas 1709
	while ((point = ds.getPoint(i)) != 0)
1710
	{
132 andreas 1711
	   if (mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
1712
	      break;
1713
 
100 andreas 1714
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1715
	   {
132 andreas 1716
	      i = point->time + 1;
100 andreas 1717
	      continue;
1718
	   }
1719
 
132 andreas 1720
	   x2 = (left + ((posNW.lon - SEMI2DEG(point->posn.lon)) * tick * -1)) + oldTransX;
1721
	   y2 = (top + ((posNW.lat - SEMI2DEG(point->posn.lat)) * tick)) + oldTransY;
100 andreas 1722
 
1723
	   if (x1 == 0.0 && y1 == 0.0)
1724
	   {
1725
	      x1 = x2;
1726
	      y1 = y2;
1727
	   }
104 andreas 1728
 
100 andreas 1729
	   paint.setPen(yline);
104 andreas 1730
	   paint.drawLine(x1, y1, x2, y2);
1731
 
1732
	   if ((point->distance - dist) >= 1000.0)	// a dot at every 1000 meters
1733
	   {
1734
	      paint.setPen(dot);
1735
	      paint.drawEllipse(x2-1, y2-1, 2, 2);
1736
	      dist = (int)(point->distance / 1000) * 1000.0;
1737
	   }
1738
 
100 andreas 1739
	   paint.setPen(line);
1740
	   paint.drawLine(x1, y1, x2, y2);
1741
	   x1 = x2;
1742
	   y1 = y2;
132 andreas 1743
	   i = point->time + 1;
100 andreas 1744
	}
1745
 
1746
	paint.end();
1747
	imgMap->setPixmap(pmMap);
1748
}
1749
 
88 andreas 1750
void sportwatcherWidget::showCurves()
1751
{
148 andreas 1752
	showCurves (mapLap);
1753
}
1754
 
1755
void sportwatcherWidget::showCurves(LAP *lap)
1756
{
88 andreas 1757
QPainter paint;
1758
int width, height;
148 andreas 1759
int i, secs;
88 andreas 1760
int lineHeight, margin_left, margin_right, margin_bottom;
1761
int x1, y1, x2, y2;		// Coordinates
1762
bool meter;
1763
double maxHeight, minHeight;
1764
int maxHr, minHr, rh;
1765
POINT *point;
148 andreas 1766
RUN_NODE *rn;
1767
LAP *lp;
88 andreas 1768
double w_tick, h_tick;		// Number of pixels one "tick" has;
1769
				// This depends on the width and height
1770
				// of the image.
1771
	// First we draw a grid based on the min and max
1772
	// values detected in the function showLap(). In case
1773
	// all values are 0, we exit here.
1774
	if (min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
1775
	   return;
1776
 
148 andreas 1777
	width = imgProfile->width() - 2;
1778
	height = imgProfile->height();
1779
	pmProfile.resize(width, height);
88 andreas 1780
	paint.begin(&pmProfile);
1781
 
1782
	// we need a somewhat bigger area to draw our curves than
1783
	// we have with the real min and max values.
1784
	if (max_height > 0.0)
1785
	{
148 andreas 1786
	double add = (max_height - min_height) / 100.0 * 5.0;	// Percent
88 andreas 1787
 
1788
	   maxHeight = max_height + add;
1789
	   minHeight = min_height - add;
1790
 
1791
	   if (minHeight < 0.0)		// make sure, we are not too deep
1792
	      minHeight = 0.0;
1793
	}
1794
 
1795
	if (max_hr > 0)
1796
	{
1797
	   maxHr = max_hr + 10;
1798
	   minHr = min_hr - 10;
1799
 
1800
	   if (minHr < 0)
1801
	      minHr = 0;
1802
	}
1803
 
1804
	// Define colors
148 andreas 1805
	QColor background(220, 220, 220);	// Background of graphic
1806
	QColor mark(255, 255, 255);		// Lines inside curve area
1807
	QColor hlight(180, 180, 180);		// area of current lap
1808
//	hlight.setAlpha(128);			// 50% transparent
1809
	QColor frame(0, 0, 0);			// Text and borders
1810
	QColor barcol(151, 190, 13);		// heart rate
1811
	QColor barcol2(190, 151, 13);		// height over NN
88 andreas 1812
	QColor red(220, 128, 128);
1813
	QColor blue(0, 0, 240);
1814
	QFont fntNormal("Helvetica");
1815
//	QFont fntBold("Helvetica", 10, QFont::Bold);
1816
	fntNormal.setPixelSize(10);
1817
	fntNormal.setStyleHint(QFont::Helvetica);
1818
//	fntBold.setPixelSize(10);
1819
//	fntBold.setStyleHint(QFont::Helvetica);
1820
	// Calculate ticks
1821
	margin_left = 52;
1822
	margin_right = 40;
1823
	margin_bottom = 12;
1824
	lineHeight = 10;
1825
	rh = height - margin_bottom - 1;
1826
 
1827
	w_tick = (double)(width - (margin_left + margin_right)) / max_time;	// 1 tick = 1 second
1828
 
1829
	if ((maxHeight - minHeight) > (double)(maxHr - minHr))
1830
	{
1831
	   h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
1832
	   meter = true;
1833
	}
1834
	else
1835
	{
1836
	   h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
1837
	   meter = false;
1838
	}
1839
 
1840
	// Fill background with background colors
1841
	paint.fillRect(0, 0, width + 4, height + 4, background);
1842
	// Draw a grid with markers at every 10 minutes
1843
	paint.setPen(QPen(frame, 1, QPen::SolidLine));
1844
	// Bottom border line
1845
	x1 = margin_left;
1846
	y1 = height - margin_bottom;
1847
	x2 = width - margin_right;
1848
	y2 = y1;
1849
	paint.drawLine(x1, y1, x2, y2);
1850
	// Left border line
1851
	x1 = x2 = margin_left;
1852
	y1 = 2;
1853
	y2 = height - margin_bottom;
1854
	paint.drawLine(x1, y1, x2, y2);
1855
	// right border line
1856
	x1 = x2 = width - margin_right;
1857
	paint.drawLine(x1, y1, x2, y2);
148 andreas 1858
 
1859
	// Draw some darker lines to show the laps, if we have one
1860
	// and, in case we have a given lap, we fill the area.
1861
	QDateTime *qt;
1862
	QTime zeit = StartTime.time();
1863
	rn = ds.getRunNode();
1864
	paint.setPen(QPen(hlight, 1, QPen::SolidLine));
1865
 
1866
	for (i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
1867
	{
1868
	   if ((lp = ds.getLap(i)) == NULL)
1869
	      continue;
1870
 
1871
	   qt = garmin_dtime(lp->start_time);
1872
	   secs = zeit.secsTo(qt->time());
1873
	   delete qt;
1874
	   x1 = secs * w_tick + margin_left + 1;
1875
 
1876
	   if (lap && lp->start_time == lap->start_time)
1877
	      paint.fillRect(x1, 2, (int)((double)lap->total_time / 100.0 * w_tick), height - margin_bottom - 2, hlight);
1878
	   else
1879
	      paint.drawLine(x1, 2, x1, height - margin_bottom);
1880
	}
1881
 
88 andreas 1882
	// Grid vertical
1883
	paint.setPen(QPen(frame, 1, QPen::SolidLine));
1884
	paint.setFont(fntNormal);
1885
	paint.drawText(margin_left - 20, height - lineHeight, 40, lineHeight, Qt::AlignCenter, QString("00:00"));
1886
	paint.save();
1887
	paint.rotate(270);
1888
	paint.setPen(QPen(barcol, 1, QPen::SolidLine));
149 andreas 1889
	paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Elevation (ft)" : "Elevation (m)"));
88 andreas 1890
	paint.setPen(QPen(blue, 1, QPen::SolidLine));
1891
	paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
1892
	paint.restore();
1893
	paint.setPen(QPen(mark, 1, QPen::SolidLine));
1894
	// Draw the time scale
1895
	for (i = 0; (unsigned int)i < max_time; i++)
1896
	{
1897
	   if (i > 0 && !(i % 600))	// every 10 minutes
1898
	   {
1899
	      x1 = x2 = margin_left + w_tick * i;
1900
 
1901
	      if (x1 == (width - margin_right))
1902
		 continue;
1903
 
1904
	      y1 = 2;
1905
	      y2 = height - margin_bottom;
1906
	      paint.drawLine(x1, y1, x2, y2);
1907
	      QTime tm(0, 0, 0);
1908
	      tm = tm.addSecs(i);
1909
	      paint.setPen(QPen(frame, 1, QPen::SolidLine));
1910
	      paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((i >= 3600) ? "hh:mm:ss" : "mm:ss"));
1911
	      paint.setPen(QPen(mark, 1, QPen::SolidLine));
1912
	   }
1913
	}
1914
 
1915
	QTime tm(0, 0, 0);
1916
	QString qs;
1917
	tm = tm.addSecs(max_time);
1918
	paint.setPen(QPen(frame, 1, QPen::SolidLine));
1919
	paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((max_time >= 3600) ? "hh:mm:ss" : "mm:ss"));
1920
 
1921
	if (max_height > 0.0)
1922
	{
1923
	   paint.setPen(QPen(barcol, 1, QPen::SolidLine));
149 andreas 1924
	   paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? minHeight / 0.304 : minHeight));
88 andreas 1925
	}
1926
 
1927
	if (max_hr > 0)
1928
	{
1929
	   paint.setPen(QPen(blue, 1, QPen::SolidLine));
1930
	   paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
1931
	}
1932
 
1933
	paint.setPen(QPen(mark, 1, QPen::SolidLine));
1934
 
1935
	// Grid horizontal
1936
	int factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxHr - minHr) / (rh / 12);
1937
	int target = (meter) ? (int)(maxHeight - minHeight) : (maxHr - minHr);
1938
	int oldy = height;
1939
 
1940
	for (i = 0; i < target; i++)
1941
	{
1942
	   if (i > 0 && !(i % factor))
1943
	   {
1944
	      x1 = margin_left + 1;
1945
	      x2 = width - margin_right - 1;
1946
	      y1 = y2 = rh - h_tick * i;
1947
 
1948
	      if (y1 < 12)
1949
		 break;
1950
 
1951
	      paint.drawLine(x1, y1, x2, y2);
1952
 
1953
	      if (y1 < (oldy - lineHeight))
1954
	      {
1955
		 if (meter)
1956
		 {
1957
		    paint.setPen(QPen(barcol, 1, QPen::SolidLine));
149 andreas 1958
		    paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));
88 andreas 1959
 
1960
		    if (maxHr > 0)
1961
		    {
1962
		       double hrscale = (double)(maxHr - minHr) / (double)target;
1963
		       paint.setPen(QPen(blue, 1, QPen::SolidLine));
1964
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", (int)((double)minHr + hrscale * (double)i)));
1965
		    }
1966
		 }
1967
		 else
1968
		 {
1969
		    paint.setPen(QPen(blue, 1, QPen::SolidLine));
1970
		    paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
1971
 
1972
		    if (max_height > 0)
1973
		    {
1974
		       double hrscale = (maxHeight - minHeight) / (double)target;
1975
		       paint.setPen(QPen(barcol, 1, QPen::SolidLine));
1976
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minHeight + hrscale * (double)i));
1977
		    }
1978
		}
1979
 
1980
		 paint.setPen(QPen(mark, 1, QPen::SolidLine));
1981
		 oldy = y1;
1982
	      }
1983
	   }
1984
	}
1985
 
148 andreas 1986
	// To make out graphics more beautiful, we draw lines for the
88 andreas 1987
	// heart rate limits and the average heart rate.
1988
	if (max_hr > 0)
1989
	{
1990
	int ay1, ay2, ay3, ay4, ay5;
1991
 
1992
	   x1 = margin_left + 1;
1993
	   x2 = width - margin_right - 1;
1994
 
1995
	   if (meter)
1996
	   {
1997
	      double hrscale = rh / (double)(maxHr - minHr);
1998
	      ay1 = (double)rh - (double)(lower1 - minHr) * hrscale;
1999
	      ay2 = (double)rh - (double)(lower2 - minHr) * hrscale;
2000
	      ay3 = (double)rh - (double)(lower3 - minHr) * hrscale;
2001
	      ay4 = (double)rh - (double)(upper3 - minHr) * hrscale;
2002
	      ay5 = (double)rh - (double)(avg_hr - minHr) * hrscale;
2003
	   }
2004
	   else
2005
	   {
2006
	      ay1 = (double)rh - (double)(lower1 - minHr) * h_tick;
2007
	      ay2 = (double)rh - (double)(lower2 - minHr) * h_tick;
2008
	      ay3 = (double)rh - (double)(lower3 - minHr) * h_tick;
2009
	      ay4 = (double)rh - (double)(upper3 - minHr) * h_tick;
2010
	      ay5 = (double)rh - (double)(avg_hr - minHr) * h_tick;
2011
	   }
2012
 
2013
	   paint.setPen(QPen(barcol2, 1, QPen::DashLine));	// color for limits
2014
 
2015
	   if (lower1 > minHr && lower1 < maxHr)
2016
	      paint.drawLine(x1, ay1, x2, ay1);
2017
 
2018
	   if (lower2 > minHr && lower2 < maxHr)
2019
	      paint.drawLine(x1, ay2, x2, ay2);
2020
 
2021
	   if (lower3 > minHr && lower3 < maxHr)
2022
	      paint.drawLine(x1, ay3, x2, ay3);
2023
 
2024
	   if (upper3 > minHr && upper3 < maxHr)
2025
	      paint.drawLine(x1, ay4, x2, ay4);
2026
 
2027
	   paint.setPen(QPen(red, 1, QPen::DashDotLine));	// color for average heart rate
2028
 
2029
	   if (avg_hr > minHr && avg_hr < maxHr)
2030
	      paint.drawLine(x1, ay5, x2, ay5);
2031
	}
2032
 
2033
	// Now we have a grid and we've done the scaling.
2034
	// This is the point where we draw the curves itself.
2035
	// We use different colors to draw the lines.
2036
	i = 0;
2037
	x1 = x2 = y1 = y2 = 0;
148 andreas 2038
	int hy1, hy2, hx1, hx2;
88 andreas 2039
	hy1 = hy2 = hx1 = hx2 = 0;
2040
 
2041
	while ((point = ds.getPoint(i)) != 0)
2042
	{
2043
	   // calculate the y position based on the time
2044
	   qt = garmin_dtime(point->time);
2045
	   secs = zeit.secsTo(qt->time());
2046
	   delete qt;
2047
	   x2 = secs * w_tick + margin_left + 1;
2048
	   hx2 = x2;
2049
 
2050
	   if (x1 == 0)
2051
	      x1 = x2;
2052
 
2053
	   if (hx1 == 0)
2054
	      hx1 = hx2;
2055
 
2056
	   if (point->alt < 20000 && point->alt > 0.0)
2057
	   {
2058
	      if (meter)
2059
		 y2 = (double)rh - (point->alt - minHeight) * h_tick;
2060
	      else
2061
	      {
2062
		 double hrscale = rh / (maxHeight - minHeight);
2063
		 y2 = (double)rh - (point->alt - minHeight) * hrscale;
2064
	      }
2065
 
2066
	      if (y1 == 0)
2067
		 y1 = y2;
2068
 
2069
	      paint.setPen(QPen(barcol, 1, QPen::SolidLine));
2070
	      paint.drawLine(x1, y1, x2, y2);
2071
	      y1 = y2;
2072
	      x1 = x2;
2073
	   }
2074
 
2075
	   if (point->heart_rate > 0)
2076
	   {
2077
	      if (meter)
2078
	      {
2079
		 double hrscale = rh / (double)(maxHr - minHr);
2080
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * hrscale;
2081
	      }
2082
	      else
2083
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * h_tick;
2084
 
2085
	      if (hy1 == 0)
2086
		 hy1 = hy2;
2087
 
2088
	      paint.setPen(QPen(blue, 1, QPen::SolidLine));
2089
	      paint.drawLine(hx1, hy1, hx2, hy2);
2090
	      hy1 = hy2;
2091
	      hx1 = hx2;
2092
	   }
2093
 
2094
	   i++;
2095
	}
2096
 
2097
	paint.end();
2098
	imgProfile->setPixmap(pmProfile);
2099
 
2100
//	if (bProfile)
2101
//	   bitBlt(imgProfile, 0, 0, &pmProfile);
2102
}
2103
 
2104
void sportwatcherWidget::resizeEvent(QResizeEvent */* *e */)
2105
{
132 andreas 2106
	showTrack(zfactor);
88 andreas 2107
	showCurves();
2108
}
2109
 
2110
void sportwatcherWidget::paintEvent(QPaintEvent */* *e */)
2111
{
132 andreas 2112
	showTrack(zfactor);
88 andreas 2113
	showCurves();
2114
}
2115
 
132 andreas 2116
void sportwatcherWidget::mouseMoveEvent(QMouseEvent *e)
2117
{
2118
QPoint pos(0, 0);
2119
QPoint ev = imgMap->mapFrom(this, e->pos());
2120
static QRect coord;
88 andreas 2121
 
132 andreas 2122
	if (!stateHand)
2123
	   return;
2124
 
2125
	if (ev.x() >= pos.x() &&
2126
	    ev.y() >= pos.y() &&
2127
	    ev.x() <= (pos.x() + imgMap->geometry().width()) &&
2128
	    ev.y() <= (pos.y() + imgMap->geometry().height()))
2129
	{
2130
	   if (lmbPressed == 1)
2131
	   {
2132
	      coord.setCoords(ev.x(), ev.y(), 0, 0);
2133
	      lmbPressed = 0;
2134
	   }
2135
	   else
2136
	   {
2137
	      coord.setRight(ev.x());
2138
	      coord.setBottom(ev.y());
2139
	   }
2140
 
2141
	   if (lmbPressed == 2)
2142
	   {
2143
	      showTrack(zfactor, coord, mapLap);
2144
	      lmbPressed = 0;
2145
	   }
2146
	}
2147
}
2148
 
2149
void sportwatcherWidget::mousePressEvent(QMouseEvent *e)
2150
{
2151
	if (stateHand && e->button() == QMouseEvent::LeftButton)
2152
	   lmbPressed = 1;	// Left Mouse Button is pressed
2153
	else if (stateHand)
2154
	   lmbPressed = 0;	// Wrong button is pressed
2155
 
2156
	if (stateGlas)
2157
	{
2158
	   if (e->button() == QMouseEvent::LeftButton)
2159
	      btGlasPlusSlot();
2160
	   else if (e->button() == QMouseEvent::RightButton)
2161
	      btGlasMinusSlot();
2162
	}
2163
}
2164
 
2165
void sportwatcherWidget::mouseReleaseEvent(QMouseEvent *e)
2166
{
2167
	if (stateHand && e->button() == QMouseEvent::LeftButton)
2168
	{
2169
	   lmbPressed = 2;	// Left Mouse Button was released
2170
	   mouseMoveEvent(e);
2171
	}
2172
}
2173
 
88 andreas 2174
/*
2175
 * Private functions to help decode the data
2176
 */
2177
QDateTime *sportwatcherWidget::garmin_dtime (uint32 t)
2178
{
2179
time_t     tval;
2180
struct tm  tmval;
2181
QTime ti;
2182
QDate dt;
2183
QDateTime *qt;
2184
 
2185
	if (t == 0)
2186
	   return new QDateTime(QDate(1900, 1, 1), QTime(0, 0, 0, 0));
2187
 
2188
	tval = t + TIME_OFFSET;
2189
	localtime_r (&tval, &tmval);
2190
	qt = new QDateTime();
2191
	qt->setDate(QDate(tmval.tm_year+1900, tmval.tm_mon+1, tmval.tm_mday));
2192
	qt->setTime(QTime(tmval.tm_hour, tmval.tm_min, tmval.tm_sec, 0));
2193
	/* OK.  Done. */
2194
	return qt;
2195
}
2196
 
104 andreas 2197
bool sportwatcherWidget::writeTag(const QFile &fn, const QString &str, int indent)
2198
{
2199
QString qs;
2200
char *p = new char[str.length()+100];
2201
QCString qcs;
2202
int i;
88 andreas 2203
 
104 andreas 2204
	qs.fill(' ', indent * 3);
2205
	qs.append(str);
2206
	qcs = qs.utf8();
2207
	qstrcpy(p, qcs);
2208
	i = strlen(p);
2209
 
2210
	if (write(fn.handle(), p, i) != i)
2211
	{
2212
	   delete p;
2213
	   return false;
2214
	}
2215
 
2216
	delete p;
2217
	return true;
2218
}
2219
 
151 andreas 2220
#ifdef GDAL
2221
bool sportwatcherWidget::writeWMSTag(double llat, double llon, double rlat, double rlon, int width, int height)
2222
{
2223
QFile fl(MAP);
2224
QString xml, s;
2225
 
2226
	if (!fl.open(IO_ReadWrite | IO_Truncate))
2227
	{
2228
	   KMessageBox::error (this, i18n("Error opening or creating the WMS tag file!\nPlease check file name and/or permissions."));
2229
	   return false;
2230
	}
2231
 
2232
	xml = "<GDAL_WMS>\n";
2233
	xml += "   <Service name=\"WMS\">\n";
2234
	xml += "      <Version>1.1.1</Version>\n";
2235
	xml += "      <ServerURL>http://openaerialmap.org/wms/?</serverURL>\n";
2236
	xml += "      <SRS>EPSG:4326</SRS>\n";
2237
	xml += "      <CRS>CRS:83</CRS>\n";
2238
	xml += "      <ImageFormat>image/png</ImageFormat>\n";
2239
	xml += "      <Layers>world</Layers>\n";
2240
//	xml += "      <Styles></Styles>\n";
2241
	xml += "      <BBoxOrder>xyXY</BBoxOrder>\n";
2242
	xml += "   </Service>\n";
2243
	xml += "   <DataWindow>\n";
2244
	s.sprintf ("%f", llat);
2245
	xml += "      <UpperLeftX>" + s + "</UpperLeftX>\n";
2246
	s.sprintf ("%f", llon);
2247
	xml += "      <UpperLeftY>" + s + "</UpperLeftY>\n";
2248
	s.sprintf ("%f", rlat);
2249
	xml += "      <LowerRightX>" + s + "</LowerRightX>\n";
2250
	s.sprintf ("%f", rlon);
2251
	xml += "      <LowerRightY>" + s + "</LowerRightY>\n";
2252
	s.sprintf ("%d", width);
2253
	xml += "      <SizeX>" + s + "</SizeX>\n";
2254
	s.sprintf ("%d", height);
2255
	xml += "      <SizeY>" + s + "</SizeY>\n";
2256
	xml += "   </DataWindow>\n";
2257
	xml += "   <Projection>EPSG:4326</Projection>\n";
2258
	xml += "   <BandsCount>3</BandsCount>\n";
2259
	xml += "   <BlockSizeX>1024</BlockSizeX>\n";
2260
	xml += "   <BlockSizeY>1024</BlockSizeY>\n";
2261
	xml += "   <OverviewCount>10</OverviewCount>\n";
2262
	xml += "   <Cache>\n";
2263
	xml += "      <Path>./gdalwmscache</Path>\n";
2264
	xml += "      <Depth>2</Depth>\n";
2265
	xml += "      <Extension>.png</Extension>\n";
2266
	xml += "   </Cache>\n";
2267
	xml += "   <OfflineMode>false</OfflineMode>\n";
2268
	xml += "   <AdviseRead>false</AdviseRead>\n";
2269
	xml += "   <VerifyAdviseRead>true</VerifyAdviseRead>\n";
2270
	xml += "</GDAL_WMS>\n";
2271
 
2272
	write (fl.handle(), xml.ascii(), strlen (xml.ascii()));
2273
	fl.close();
2274
	return true;
2275
}
2276
 
2277
void sportwatcherWidget::fillBMPHeader (BMP_HEADER *bmpH, BMP_INFO *bmpI, int nXSize, int nYSize, int nRasterCount)
2278
{
2279
//	bmpH->bfType = 19778;
2280
	bmpH->bfSize = sizeof(BMP_HEADER) + sizeof(BMP_INFO) + (nXSize * nYSize * nRasterCount);
2281
	bmpH->bfReserved = 0;
2282
	bmpH->bfOffBits = (sizeof(BMP_HEADER) + sizeof(BMP_INFO)) * 8;
2283
//fprintf(stderr, "Size: %d, Res: %d, Off: %d\n",
2284
//		bmpH->bfSize, bmpH->bfReserved, bmpH->bfOffBits);
2285
	bmpI->biSize = sizeof(BMP_INFO);
2286
	bmpI->biWidth = nXSize;
2287
	bmpI->biHeight = nYSize;
2288
	bmpI->biPlanes = 1;
2289
	bmpI->biBitCount = 24;
2290
	bmpI->biCompression = 0;
2291
	bmpI->biSizeImage = nXSize * nYSize * nRasterCount;
2292
	bmpI->biXPelsPerMeter = 0;
2293
	bmpI->biYPelsPerMeter = 0;
2294
	bmpI->biClrUsed = 0;
2295
	bmpI->biClrImportant = 0;
2296
}
2297
 
2298
#endif
2299
 
88 andreas 2300
#include "sportwatcherwidget.moc"
2301