Subversion Repositories public

Rev

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