Subversion Repositories public

Rev

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