Subversion Repositories public

Rev

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

Rev Author Line No. Line
88 andreas 1
/***************************************************************************
314 andreas 2
 *   Copyright (C) 2007 - 2013 by Andreas Theofilu                         *
119 andreas 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"
158 andreas 26
#include "coordinateswidget.h"
274 andreas 27
#include "shapewidget.h"
151 andreas 28
#include <string.h>
96 andreas 29
 
137 andreas 30
#include <iostream>
88 andreas 31
#include <kfiledialog.h>
32
#include <kmessagebox.h>
232 andreas 33
#include <KConfig>
88 andreas 34
#include <klocale.h>
232 andreas 35
#include <k3listview.h>
100 andreas 36
#include <kaboutdata.h>
232 andreas 37
#include <kaboutapplicationdialog.h>
218 andreas 38
#include <kinputdialog.h>
128 andreas 39
#include <kglobalsettings.h>
218 andreas 40
#include <kcombobox.h>
154 andreas 41
#include <qapplication.h>
88 andreas 42
#include <qstring.h>
43
#include <qdatetime.h>
109 andreas 44
#include <qtoolbutton.h>
132 andreas 45
#include <qcursor.h>
172 andreas 46
#include <qregexp.h>
232 andreas 47
#include <QMouseEvent>
246 andreas 48
#include <QRect>
49
#include <QRegion>
245 andreas 50
#include <KIcon>
280 andreas 51
#include <QPrintDialog>
52
#include <QPrinter>
151 andreas 53
 
232 andreas 54
#if defined HAVE_GDAL
314 andreas 55
#include <gdal/ogr_spatialref.h>
56
#include <gdal/ogrsf_frmts.h>
57
#include <gdal/gdalwarper.h>
58
#include <gdal/ogrsf_frmts.h>
59
#include "GDALError.h"
157 andreas 60
#endif
61
 
218 andreas 62
#include "garmin.h"
158 andreas 63
#include "transform.h"
88 andreas 64
 
280 andreas 65
#if defined HAVE_MAPNIK
314 andreas 66
#include "render.h"
280 andreas 67
#endif
151 andreas 68
 
137 andreas 69
using std::cout;
158 andreas 70
using std::cerr;
71
using std::clog;
137 andreas 72
using std::endl;
73
 
74
 
104 andreas 75
typedef struct
76
{
77
	double lon;
78
	double lat;
79
} posn_type;
80
 
283 andreas 81
#if defined HAVE_GDAL
82
typedef struct ERRMSG
83
{
84
	char msg[4096];
85
	ERRMSG *next;
314 andreas 86
} ERRMSG;
283 andreas 87
 
88
ERRMSG *firstError;
89
#endif
90
 
245 andreas 91
sportwatcherWidget::sportwatcherWidget(QWidget *parent)
88 andreas 92
{
245 andreas 93
	ui_sportwatcherWidgetBase.setupUi(this);
232 andreas 94
 
95
#if defined HAVE_GDAL
157 andreas 96
	mFactor = 10;		// Factor to calculate square pixels
283 andreas 97
	firstError = 0;
157 andreas 98
#endif
88 andreas 99
	mama = parent;
100
	gmn = 0;
101
	min_hr = max_hr = avg_hr = 0;
102
	min_height = max_height = 0.0;
103
	max_time = 0;
104 andreas 104
	zfactor = 0;
132 andreas 105
	mapLap = 0;
106
	mapPan = QRect(0, 0, 0, 0);
107
	stateHand = stateFlag = stateGlas = false;
108
	oldTransX = oldTransY = 0.0;
109
	lmbPressed = 0;
246 andreas 110
	DIRTY = true;
248 andreas 111
	curTab = ui_sportwatcherWidgetBase.tabView->currentIndex();
112
	tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
280 andreas 113
	ActivePrint = false;	// true if we are printing on paper
230 andreas 114
	kl = new KLocale(QString("kdesktop"), 0);
132 andreas 115
 
88 andreas 116
	// Load the config parameters
314 andreas 117
	KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
118
	KConfigGroup ic(&cfg, "SportWatcher");
232 andreas 119
	lower1 = ic.readEntry("lower1", 0);
120
	lower2 = ic.readEntry("lower2", 0);
121
	lower3 = ic.readEntry("lower3", 0);
122
	upper1 = ic.readEntry("upper1", 0);
123
	upper2 = ic.readEntry("upper2", 0);
124
	upper3 = ic.readEntry("upper3", 0);
125
	MaxHr = ic.readEntry("maxHr", 180);
126
	restHr = ic.readEntry("restHr", 60);
127
	vo2max = ic.readEntry("vo2max", 50);
128
	weight = ic.readEntry("weight", 70);
129
	sampleTime = ic.readEntry("seconds", 15);
130
	Serial = ic.readEntry("Serial", false);
131
	Forerunner = ic.readEntry("Forerunner", false);
132
	Contour = ic.readEntry("Contour", false);
133
	Device = ic.readEntry("Device", "/dev/ttyUSB0");
134
	Data = ic.readEntry("Data", QDir::home().absolutePath() + "/.sportwatcher");
135
	HRM = ic.readEntry("HRM", QDir::home().absolutePath() + "/polar");
136
	MAP = ic.readEntry("MAP", QDir::home().absolutePath() + "/.sportwatcher/track.wms");
137
	Units = ic.readEntry("Units", 0);
138
	MapType = ic.readEntry("MapType", 7);
283 andreas 139
#ifdef HAVE_GDAL
140
	// set our own error handler here
141
	CPLSetErrorHandler((CPLErrorHandler)spwErrorHandler);
142
#endif
143
 
88 andreas 144
}
145
 
146
sportwatcherWidget::~sportwatcherWidget()
147
{
104 andreas 148
	destroy();
230 andreas 149
	delete kl;
283 andreas 150
#ifdef HAVE_GDAL
151
	// destroy the error handler here
152
	CPLSetErrorHandler(NULL);
153
#endif
88 andreas 154
}
155
 
100 andreas 156
void sportwatcherWidget::destroy()
157
{
314 andreas 158
	if(gmn)
159
		garmin_free_data(gmn);
100 andreas 160
 
161
	gmn = 0;
132 andreas 162
	oldTransX = oldTransY = 0.0;
100 andreas 163
}
164
 
245 andreas 165
void sportwatcherWidget::Initialize()
166
{
167
	// Set some widget settings
168
	ui_sportwatcherWidgetBase.btHand->setIcon(KIcon("hand"));
169
	ui_sportwatcherWidgetBase.btGlas->setIcon(KIcon("glas"));
170
	ui_sportwatcherWidgetBase.btGlasMinus->setIcon(KIcon("glas_minus"));
171
	ui_sportwatcherWidgetBase.btGlasPlus->setIcon(KIcon("glas_plus"));
172
	ui_sportwatcherWidgetBase.btFlag->setIcon(KIcon("flag"));
173
	ui_sportwatcherWidgetBase.btFullscreen->setIcon(KIcon("fullscreen"));
248 andreas 174
 
314 andreas 175
	if(curTab != 0)
248 andreas 176
	{
314 andreas 177
		ui_sportwatcherWidgetBase.tabView->setCurrentIndex(0);
178
		curTab = ui_sportwatcherWidgetBase.tabView->currentIndex();
248 andreas 179
	}
180
 
245 andreas 181
//	btHand->setToggleButton(true);
182
//	btGlas->setToggleButton(true);
183
	// Fill the activities
184
	getActivities();
185
#if defined HAVE_GDAL
186
	// Initialize the GDAL
187
	GDALAllRegister();
188
	poDataset = 0;
189
#endif
190
}
191
 
247 andreas 192
QTreeWidgetItem *sportwatcherWidget::findElement(QTreeWidget *wdg, const QString &val)
132 andreas 193
{
314 andreas 194
	QTreeWidgetItem *item, *child, *subchild;
132 andreas 195
 
314 andreas 196
	if(!wdg)
197
		return 0;
246 andreas 198
 
314 andreas 199
	for(int a = 0; a < wdg->topLevelItemCount(); a++)
132 andreas 200
	{
314 andreas 201
		if(!(item = wdg->topLevelItem(a)))
202
			continue;
132 andreas 203
 
314 andreas 204
		for(int j = 0; j < item->childCount(); j++)
205
		{
206
			if(!(child = item->child(j)))
207
				continue;
246 andreas 208
 
314 andreas 209
			if(child->data(0, Qt::UserRole).toString() == val)
210
				return child;
247 andreas 211
 
314 andreas 212
			for(int i = 0; i < child->childCount(); i++)
213
			{
214
				if(!(subchild = child->child(i)))
215
					continue;
247 andreas 216
 
314 andreas 217
				if(subchild->data(0, Qt::UserRole).toString() == val)
218
					return subchild;
219
			}
220
		}
132 andreas 221
	}
222
 
247 andreas 223
	return 0;
132 andreas 224
}
225
 
88 andreas 226
/*
227
 * Search for a directory named .sportwatcher in the home directory of
228
 * the user and search for *.gmn files. Open the files and read the header
229
 * to find the basic data of activities. Then add the information into
230
 * the activities KListView.
231
 */
232
void sportwatcherWidget::getActivities()
233
{
314 andreas 234
	QString path, txt;
235
	QDir mdir, dir = QDir::home();
236
	QStringList years, months;
237
	QTreeWidgetItem *running, *biking, *other, *year_run, *year_bike, *year_other;
238
	QTreeWidgetItem *el;
239
	QList<QTreeWidgetItem *> item;
240
	int i, j;
241
	int y_run, y_bike, y_other;
242
	RUN_NODE *rn;
243
	LAP *lap;
88 andreas 244
 
314 andreas 245
	if(Data.isEmpty())
88 andreas 246
	{
314 andreas 247
		path = dir.homePath();
248
		path.append("/.sportwatcher");
88 andreas 249
	}
250
	else
314 andreas 251
		path = Data;
88 andreas 252
 
253
	dir.setPath(path);
132 andreas 254
	dir.refresh();
88 andreas 255
 
314 andreas 256
	if(!dir.exists())
88 andreas 257
	{
314 andreas 258
		dir.mkdir(path);
259
		return;
88 andreas 260
	}
261
 
132 andreas 262
	destroy();
128 andreas 263
 
314 andreas 264
	if(!ui_sportwatcherWidgetBase.liActivities)
245 andreas 265
	{
314 andreas 266
		KMessageBox::error(this, i18n("Error initializing some widgets of main window!"));
267
		return;
245 andreas 268
	}
269
 
270
	ui_sportwatcherWidgetBase.liActivities->clear();
246 andreas 271
	ui_sportwatcherWidgetBase.liActivities->setSortingEnabled(false);
272
	ui_sportwatcherWidgetBase.liActivities->setColumnCount(1);
245 andreas 273
 
246 andreas 274
	running = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
275
	biking = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
276
	other = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
277
 
314 andreas 278
	if(!other || !biking || !running)
245 andreas 279
	{
314 andreas 280
		KMessageBox::error(this, i18n("Not enough memory to initilize application!"));
281
		return;
245 andreas 282
	}
283
 
246 andreas 284
	running->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
285
	biking->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
286
	other->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
128 andreas 287
 
246 andreas 288
	running->setText(0, i18n("Running"));
289
	biking->setText(0, i18n("Biking"));
290
	other->setText(0, i18n("Others"));
88 andreas 291
 
246 andreas 292
	KIcon fld(QString("history"));
293
	running->setIcon(0, fld);
294
	biking->setIcon(0, fld);
295
	other->setIcon(0, fld);
296
 
297
	running->setStatusTip(0, i18n("\"Running\" activities."));
298
	biking->setStatusTip(0, i18n("\"Biking\" activities."));
299
	other->setStatusTip(0, i18n("\"Other\" and \"Multisport\" activities."));
300
 
88 andreas 301
	dir.cd(path);
302
	dir.setFilter(QDir::Dirs | QDir::NoSymLinks);
303
	dir.setSorting(QDir::Name);
132 andreas 304
	dir.refresh();
232 andreas 305
	QFileInfoList list = dir.entryInfoList();
88 andreas 306
 
314 andreas 307
	if(!list.size())
308
		return;
88 andreas 309
 
314 andreas 310
	for(i = 0; i < list.size(); i++)		// Years
232 andreas 311
	{
314 andreas 312
		QFileInfo fileInfo = list.at(i);
88 andreas 313
 
314 andreas 314
		if(fileInfo.fileName() == QString(".") || fileInfo.fileName() == QString(".."))
315
			continue;
88 andreas 316
 
314 andreas 317
		years += fileInfo.absoluteFilePath();
88 andreas 318
	}
319
 
314 andreas 320
	for(i = 0; i < years.size(); ++i)
88 andreas 321
	{
314 andreas 322
		if(months.size() > 0)
323
			months.clear();
88 andreas 324
 
314 andreas 325
		dir.setPath(years.at(i));
326
		dir.refresh();
327
		list = dir.entryInfoList();
88 andreas 328
 
314 andreas 329
		if(!list.size())
330
			continue;
88 andreas 331
 
314 andreas 332
		for(j = 0; j < list.size(); j++)		// Months
333
		{
334
			QFileInfo fileInfo = list.at(j);
88 andreas 335
 
314 andreas 336
			if(fileInfo.fileName() == QString(".") || fileInfo.fileName() == QString(".."))
337
				continue;
88 andreas 338
 
314 andreas 339
			months += fileInfo.absoluteFilePath();
340
		}
88 andreas 341
 
314 andreas 342
		for(j = 0; j < months.size(); ++j)
343
		{
344
			mdir.setPath(months.at(j));
345
			mdir.cd(months.at(j));
346
			mdir.setFilter(QDir::Files | QDir::NoSymLinks);
347
			mdir.setSorting(QDir::Name);
348
			mdir.setNameFilters(QStringList("*.gmn"));
349
			mdir.refresh();
350
			list = mdir.entryInfoList();
88 andreas 351
 
314 andreas 352
			if(!list.size())
353
				continue;
88 andreas 354
 
314 andreas 355
			for(int a = 0; a < list.size(); a++)		// Files
356
			{
357
				QFileInfo fileInfo = list.at(a);
88 andreas 358
 
314 andreas 359
				files += fileInfo.absoluteFilePath();
360
			}
361
		}
88 andreas 362
	}
363
 
247 andreas 364
	y_run = y_bike = y_other = 0;
365
	year_run = year_bike = year_other = 0;
314 andreas 366
 
88 andreas 367
	// Open every file and read its head
314 andreas 368
	for(i = 0; i < files.size(); ++i)
88 andreas 369
	{
314 andreas 370
		QTreeWidgetItem *yr, *yb, *yo;
132 andreas 371
 
314 andreas 372
		if(findElement(ui_sportwatcherWidgetBase.liActivities, files.at(i)))
373
			continue;
246 andreas 374
 
314 andreas 375
		spw.destroy();
88 andreas 376
 
314 andreas 377
		if(spw.setFileName(files.at(i).toAscii().constData()) == -1)
378
			return;
88 andreas 379
 
314 andreas 380
		if(gmn)
381
		{
382
			garmin_free_data(gmn);
383
			gmn = 0;
384
		}
88 andreas 385
 
314 andreas 386
		if(!(gmn = spw.readFile()))
387
			continue;
246 andreas 388
 
314 andreas 389
		ds.destroy();
390
		ds.garmin_print_data(gmn);
391
		rn = ds.getRunNode();
88 andreas 392
 
314 andreas 393
		if(!rn)
394
			return;
245 andreas 395
 
314 andreas 396
		lap = ds.getLap(rn->run->first_lap_index);
245 andreas 397
 
314 andreas 398
		if(!lap)
399
			return;
245 andreas 400
 
314 andreas 401
		const QDateTime *qt = garmin_dtime(lap->start_time);
402
		// By default set the name of the session to the date and time
403
		// it was recorded.
404
		QString idx = kl->formatDateTime(*qt, KLocale::ShortDate, true);
405
		QString stTip = kl->formatDateTime(*qt, KLocale::LongDate, true);
88 andreas 406
 
314 andreas 407
		// If we have a custom name for this session, set it.
408
		if(strlen(rn->run->workout.name) > 1 && strlen(rn->run->workout.name) < 16 && isalpha(rn->run->workout.name[0]))
409
			idx = QString(rn->run->workout.name);
217 andreas 410
 
314 andreas 411
		switch(rn->run->sport_type)
412
		{
413
			case D1000_running:
414
				yr = findElement(ui_sportwatcherWidgetBase.liActivities, QString("run_%1").arg(qt->date().year()));
247 andreas 415
 
314 andreas 416
				if(!yr && qt->date().year() != y_run)
417
				{
418
					year_run = new QTreeWidgetItem(running, running, QTreeWidgetItem::Type);
419
					y_run = qt->date().year();
420
					year_run->setText(0, QString("%1").arg(y_run));
421
					year_run->setData(0, Qt::UserRole, QString("run_%1").arg(y_run));
422
					year_run->setIcon(0, KIcon(QString("today")));
423
					year_run->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
424
				}
425
				else
426
					year_run = yr;
247 andreas 427
 
314 andreas 428
				el = new QTreeWidgetItem(year_run, year_run, QTreeWidgetItem::Type);
429
				el->setText(0, idx);
430
				el->setData(0, Qt::UserRole, files.at(i));
431
				el->setIcon(0, KIcon(QString("spw-running")));
432
				el->setStatusTip(0, stTip);
433
				el->setToolTip(0, stTip);
434
				el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
435
				break;
88 andreas 436
 
314 andreas 437
			case D1000_biking:
438
				yb = findElement(ui_sportwatcherWidgetBase.liActivities, QString("bike_%1").arg(qt->date().year()));
247 andreas 439
 
314 andreas 440
				if(!yb && qt->date().year() != y_bike)
441
				{
442
					year_bike = new QTreeWidgetItem(biking, biking, QTreeWidgetItem::Type);
443
					y_bike = qt->date().year();
444
					year_bike->setText(0, QString("%1").arg(y_bike));
445
					year_bike->setData(0, Qt::UserRole, QString("bike_%1").arg(y_bike));
446
					year_bike->setIcon(0, KIcon(QString("today")));
447
					year_bike->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
448
				}
449
				else
450
					year_bike = yb;
247 andreas 451
 
314 andreas 452
				el = new QTreeWidgetItem(year_bike, year_bike, QTreeWidgetItem::Type);
453
				el->setText(0, idx);
454
				el->setData(0, Qt::UserRole, files.at(i));
455
				el->setStatusTip(0, stTip);
456
				el->setToolTip(0, stTip);
457
				el->setIcon(0, KIcon(QString("bike")));
458
				el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
459
				break;
88 andreas 460
 
314 andreas 461
			case D1000_other:
462
			default:
463
				yo = findElement(ui_sportwatcherWidgetBase.liActivities, QString("other_%1").arg(qt->date().year()));
88 andreas 464
 
314 andreas 465
				if(!yo && qt->date().year() != y_other)
466
				{
467
					year_other = new QTreeWidgetItem(other, other, QTreeWidgetItem::Type);
468
					y_other = qt->date().year();
469
					year_other->setText(0, QString("%1").arg(y_other));
470
					year_other->setData(0, Qt::UserRole, QString("other_%1").arg(y_other));
471
					year_other->setIcon(0, KIcon(QString("today")));
472
					year_other->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
473
				}
474
				else
475
					year_other = yo;
247 andreas 476
 
314 andreas 477
				el = new QTreeWidgetItem(year_other, year_other, QTreeWidgetItem::Type);
478
				el->setText(0, idx);
479
				el->setData(0, Qt::UserRole, files.at(i));
480
				el->setStatusTip(0, stTip);
481
				el->setToolTip(0, stTip);
482
				el->setIcon(0, KIcon(QString("other")));
483
				el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
484
		}
88 andreas 485
 
314 andreas 486
		delete qt;
88 andreas 487
	}
488
 
246 andreas 489
	ui_sportwatcherWidgetBase.liActivities->setItemExpanded(running, true);
88 andreas 490
 
314 andreas 491
	if(year_run)
492
		ui_sportwatcherWidgetBase.liActivities->setItemExpanded(year_run, true);
247 andreas 493
 
314 andreas 494
	if(gmn)
495
		garmin_free_data(gmn);
88 andreas 496
 
497
	gmn = 0;
498
}
499
 
500
/*$SPECIALIZATION$*/
501
void sportwatcherWidget::btFullscreenSlot()
502
{
132 andreas 503
	oldTransX = oldTransY = 0.0;
504
	mapPan.setCoords(0, 0, 0, 0);
246 andreas 505
	DIRTY = true;
104 andreas 506
	showTrack(0);
246 andreas 507
	DIRTY = false;
88 andreas 508
}
509
 
510
void sportwatcherWidget::btGlasMinusSlot()
511
{
314 andreas 512
	bool sh = stateHand;
132 andreas 513
 
514
	stateHand = false;
246 andreas 515
	DIRTY = true;
104 andreas 516
	showTrack(zfactor - 1000);
246 andreas 517
	DIRTY = false;
132 andreas 518
	stateHand = sh;
88 andreas 519
}
520
 
521
void sportwatcherWidget::btGlasPlusSlot()
522
{
314 andreas 523
	bool sh = stateHand;
132 andreas 524
 
525
	stateHand = false;
246 andreas 526
	DIRTY = true;
104 andreas 527
	showTrack(zfactor + 1000);
246 andreas 528
	DIRTY = false;
132 andreas 529
	stateHand = sh;
88 andreas 530
}
531
 
532
void sportwatcherWidget::btHandSlot()
533
{
314 andreas 534
	QCursor cs;
132 andreas 535
 
314 andreas 536
	if(stateGlas)
132 andreas 537
	{
314 andreas 538
		stateGlas = false;
539
		ui_sportwatcherWidgetBase.btGlas->toggle();
132 andreas 540
	}
314 andreas 541
 
132 andreas 542
	stateHand = (stateHand) ? false : true;
543
 
314 andreas 544
	if(stateHand)
545
		cs.setShape(Qt::PointingHandCursor);
132 andreas 546
	else
314 andreas 547
		cs.setShape(Qt::ArrowCursor);
132 andreas 548
 
245 andreas 549
	ui_sportwatcherWidgetBase.imgMap->setCursor(cs);
88 andreas 550
}
551
 
552
void sportwatcherWidget::btGlasSlot()
553
{
314 andreas 554
	QCursor cs;
132 andreas 555
 
314 andreas 556
	if(stateHand)
132 andreas 557
	{
314 andreas 558
		stateHand = false;
559
		ui_sportwatcherWidgetBase.btHand->toggle();
132 andreas 560
	}
561
 
562
	stateGlas = (stateGlas) ? false : true;
563
 
314 andreas 564
	if(stateGlas)
565
		cs.setShape(Qt::ForbiddenCursor);
132 andreas 566
	else
314 andreas 567
		cs.setShape(Qt::ArrowCursor);
132 andreas 568
 
245 andreas 569
	ui_sportwatcherWidgetBase.imgMap->setCursor(cs);
88 andreas 570
}
571
 
572
void sportwatcherWidget::btFlagSlot()
573
{
574
}
575
 
232 andreas 576
void sportwatcherWidget::liLapsSlot(Q3ListViewItem *item)
88 andreas 577
{
314 andreas 578
	QString sl;
579
	int l;
580
	int idx;
581
	RUN_NODE *rn;
582
	LAP *lap;
132 andreas 583
 
314 andreas 584
	if(!item)
585
		return;
132 andreas 586
 
246 andreas 587
	DIRTY = true;
132 andreas 588
	sl = item->text(0).mid(4, 3);
589
	l = sl.toInt();
590
 
314 andreas 591
	if(l <= 0)
132 andreas 592
	{
314 andreas 593
		// Show the whole map and track
594
		showTrack(zfactor, mapPan, 0);
595
		// Don't mark any lap. Just display normal.
596
		showCurves(0);
597
		return;
132 andreas 598
	}
599
 
600
	rn = ds.getRunNode();
601
	idx = rn->run->first_lap_index;
602
	lap = ds.getLap(idx + l - 1);
245 andreas 603
	// Show the part of the track, corresponding to the selected lap
132 andreas 604
	showTrack(zfactor, mapPan, lap);
245 andreas 605
	// Mark the selected lap
148 andreas 606
	showCurves(lap);
246 andreas 607
	DIRTY = false;
88 andreas 608
}
609
 
246 andreas 610
void sportwatcherWidget::liActivitiesSlot(QTreeWidgetItem *item, int)
88 andreas 611
{
314 andreas 612
	if(!item)
613
		return;
88 andreas 614
 
245 andreas 615
	spw.destroy();
88 andreas 616
 
314 andreas 617
	if(spw.setFileName(item->data(0, Qt::UserRole).toString().toAscii().constData()) == -1)
618
		return;
88 andreas 619
 
314 andreas 620
	if(gmn)
621
		garmin_free_data(gmn);
88 andreas 622
 
245 andreas 623
	gmn = spw.readFile();
624
	zfactor = 0;
248 andreas 625
 
626
	// Make sure, the currently not visible tabs will be redrawn as soon
627
	// as they are visible.
314 andreas 628
	switch(curTab)
248 andreas 629
	{
314 andreas 630
		case 0: tabDirt1 = tabDirt2 = tabDirt3 = true; break;
631
		case 1: tabDirt0 = tabDirt2 = tabDirt3 = true; break;
632
		case 2: tabDirt0 = tabDirt1 = tabDirt3 = true; break;
633
		case 3: tabDirt0 = tabDirt1 = tabDirt2 = true; break;
248 andreas 634
	}
635
 
245 andreas 636
	// Display the just loaded sport session
246 andreas 637
	DIRTY = true;
245 andreas 638
	showLaps();
639
	showTrack();
640
	showCurves();
250 andreas 641
 
314 andreas 642
	if(curTab == 2)
250 andreas 643
	{
314 andreas 644
		showThreeCurve();
645
		tabDirt2 = false;
250 andreas 646
	}
647
 
246 andreas 648
	DIRTY = false;
88 andreas 649
}
650
 
280 andreas 651
/*
652
 * The following function is called, when the user clicks the print button.
653
 * It then prints the currently loaded activity. First the laps and on a
654
 * seperate page the map, heart rate, elevation and speed.
655
 *
656
 * The function uses the already existing function showTrack() to draw an
657
 * optional map and the track on it. It uses the function showThreeCurve()
658
 * to draw the heart rate, elevation and speed. Only the laps are drawn
659
 * directly in this function.
660
 */
88 andreas 661
void sportwatcherWidget::filePrint()
662
{
314 andreas 663
	QPrinter printer(QPrinter::HighResolution);
664
	QDateTime dt;
665
	QTime t, st;
666
	QDateTime *qt;
667
	QRectF rect;
668
	QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
669
	QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
670
	QString qs_totdist, hv0;
671
	LAP *lap;
672
	POINT *point;
673
	RUN_NODE *rakt, *rn;
674
	int laps, i, anz, cad, page, firstPage, lastPage;
675
	qreal extMil[4];
676
	double sum_dsc, old_asc, old_dsc;
677
	double totdist, lineH, aktLine;
678
	bool printed = false;
280 andreas 679
 
314 andreas 680
	if(!gmn)
280 andreas 681
	{
314 andreas 682
		KMessageBox::error(this, i18n("You must select an activity first!"));
683
		return;
280 andreas 684
	}
685
 
686
	printer.setCreator(QString("SportWatcher"));
687
	printer.setDocName(QString("SportWatcher_%1").arg(QString(VERSION)));
688
	QPrintDialog printDialog(&printer, this);
689
 
314 andreas 690
	if(!printDialog.exec() == QDialog::Accepted)
691
		return;
280 andreas 692
 
314 andreas 693
	if(!(rn = ds.getRunNode()))
694
		return;
280 andreas 695
 
696
	// We dont care about page margins of a printer. Instead we assume
697
	// a frame from about 20mm arround the page. European paper size is
698
	// A4 (210x297mm) and the output is optimized for this.
283 andreas 699
	totdist = 0;
280 andreas 700
	extMil[0] = 20.0;
701
	extMil[1] = 20.0;
702
	extMil[2] = 210.0 - 20.0;
703
	extMil[3] = 279.0 - 20.0;
704
	lineH = 4.5;	// The height of a line with 10pt letters
705
	page = 1;	// The page number
706
	firstPage = printer.fromPage();
707
	lastPage = printer.toPage();
708
 
314 andreas 709
	if(!printArea.begin(&printer))
280 andreas 710
	{
314 andreas 711
		KMessageBox::error(this, i18n("Error initializing printer! Printing is currently not available!"));
712
		return;
280 andreas 713
	}
714
 
715
	ActivePrint = true;
716
	rakt = rn;
314 andreas 717
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
280 andreas 718
 
314 andreas 719
	while(rakt)
280 andreas 720
	{
314 andreas 721
		// Check for a supported run type
722
		if(rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
723
		                  rakt->run->type == data_D1010)
724
		{
725
			int ahr;
726
			double distance, speed, mspeed;
727
			QDate dat;
280 andreas 728
 
314 andreas 729
			printArea.setFont(QFont(QString("Helvetica"), 12, QFont::Bold, false));
730
			rect.setCoords(milToPixel(extMil[0], printer),
731
			               milToPixel(extMil[1], printer, true),
732
			               milToPixel(extMil[0] + 170, printer),
733
			               milToPixel(extMil[1] + 7.0, printer, true));
734
			printArea.setPen(QPen(QBrush(QColor("black")), (qreal)milToPixel(0.5, printer, false)));
280 andreas 735
 
314 andreas 736
			if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
737
			                  (lastPage == 0 && firstPage == 0))
738
			{
739
				printArea.drawRect(rect);
740
				printed = true;
741
			}
280 andreas 742
 
314 andreas 743
			if(!(lap = ds.getLap(rakt->run->first_lap_index)))
744
			{
745
				ActivePrint = false;
746
				QApplication::restoreOverrideCursor();
747
				return;
748
			}
280 andreas 749
 
314 andreas 750
			if(strlen(rn->run->workout.name) > 1 && strlen(rn->run->workout.name) < 16 && isalpha(rn->run->workout.name[0]))
751
				hv0 = QString(rakt->run->workout.name);
752
			else
753
			{
754
				qt = garmin_dtime(lap->start_time);
755
				hv0 = kl->formatDate(qt->date(), KLocale::ShortDate) + " ";
756
				hv0.append(qt->toString("hh:mm:ss"));
757
				delete qt;
758
			}
280 andreas 759
 
314 andreas 760
			// Set the name depending on the sport type
761
			// This is used on the tab "Summary"
762
			switch(rakt->run->sport_type)
763
			{
764
				case D1000_running: qs_name = i18n("Running: "); break;
765
				case D1000_biking:  qs_name = i18n("Biking: "); break;
766
				case D1000_other:   qs_name = i18n("Other: "); break;
767
				default:
768
					qs_name = i18n("Unknown: ");
769
			}
280 andreas 770
 
314 andreas 771
			// Print the headline inside the frame
772
			if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
773
			                  (lastPage == 0 && firstPage == 0))
774
			{
775
				printArea.drawText(rect, Qt::AlignHCenter, QString("%1%2").arg(qs_name).arg(hv0));
776
				// Print the headline of the table
777
				printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Bold, false));
778
				rect.setCoords(milToPixel(extMil[0], printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
779
				printArea.drawText(rect, Qt::AlignHCenter, i18n("Lap"));
780
				rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
781
				printArea.drawText(rect, Qt::AlignHCenter, i18n("Distance"));
782
				rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
783
				printArea.drawText(rect, Qt::AlignHCenter, i18n("Time"));
784
				rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
785
				printArea.drawText(rect, Qt::AlignHCenter, i18n("Speed"));
786
				rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
787
				printArea.drawText(rect, Qt::AlignHCenter, i18n("Heart rate"));
788
				rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
789
				printArea.drawText(rect, Qt::AlignHCenter, i18n("Cadence"));
790
				aktLine = extMil[1] + 10.0 + lineH;
791
				printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
792
				aktLine += 1.0;
793
				printed = true;
794
			}
795
			else
796
			{
797
				aktLine = extMil[1] + 10.0 + lineH;
798
				aktLine += 1.0;
799
			}
280 andreas 800
 
314 andreas 801
			// Prepare to print the first line
802
			qt = garmin_dtime(lap->start_time);
803
			StartTime = *qt;
804
			st = qt->time();
805
			dat = qt->date();
806
			delete qt;
807
			qt = 0;
280 andreas 808
 
314 andreas 809
			// Find the last track
810
			if(!(point = ds.getLastPoint()))
811
			{
812
				QApplication::restoreOverrideCursor();
813
				KMessageBox::error(this, i18n("Error getting the last messure point!"));
814
				ActivePrint = false;
815
				return;
816
			}
280 andreas 817
 
314 andreas 818
			qt = garmin_dtime(point->time);
819
			t = qt->time();
820
			t.setHMS(0, 0, 0);
821
			t = t.addSecs(ds.getTotalTime());
822
			qt->setDate(dat);
823
			qt->setTime(t);
824
			qs_name = kl->formatDate(dat, KLocale::ShortDate);
825
			qs_name.append(" ");
826
			qs_name.append(kl->formatTime(st, true));
827
			max_time = ds.getTotalTime();
828
			qs_etime = QString(qt->toString("hh:mm:ss.zzz"));
280 andreas 829
 
314 andreas 830
			distance = 0.0;
831
			mspeed = 0;
832
			ahr = 0;
833
			anz = 0;
834
			cad = 0;
835
			sum_dsc = old_asc = old_dsc = 0;
280 andreas 836
 
314 andreas 837
			// Find out the total distance, calories, maximum speed,
838
			// maximum heart rate and the average heart rate. Get this
839
			// values from the lap summary the watch made.
840
			for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
841
			{
842
				if((lap = ds.getLap(i)) == NULL)
843
					continue;
280 andreas 844
 
314 andreas 845
				distance += lap->total_distance;
280 andreas 846
 
314 andreas 847
				if(lap->avg_cadence != 0xff)
848
					cad += lap->avg_cadence;
280 andreas 849
 
314 andreas 850
				ahr += lap->avg_heart_rate;
851
				anz++;
280 andreas 852
 
314 andreas 853
				if(lap->max_speed > mspeed)
854
					mspeed = lap->max_speed;
855
			}
280 andreas 856
 
314 andreas 857
			total_distance = distance = ds.getTotalDistance();
280 andreas 858
 
314 andreas 859
			if(Units == 1)		// Statute?
860
				qs_distance.sprintf("%.2f ft", distance / 0.304);
861
			else
862
				qs_distance.sprintf("%.2f m", distance);
280 andreas 863
 
314 andreas 864
			if(distance > 0)
865
			{
866
				QTime tt = qt->time();
867
				long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;
280 andreas 868
 
314 andreas 869
				if(Units == 0)
870
					secs = secs * (1000.0 / distance * 100.0);
871
				else
872
					secs = secs * (1609.344 / distance * 100.0);
280 andreas 873
 
314 andreas 874
				int h = secs / 3600;
875
				int m = (secs - (h * 3600)) / 60;
876
				int s = secs - ((h * 3600) + (m * 60));
877
				t = QTime(h, m, s, 0);
878
				qs_avgpace = QString("  ") + kl->formatTime(t, true);
280 andreas 879
 
314 andreas 880
				if(Units == 0)
881
					qs_avgpace.append(QString(" /km"));
882
				else
883
					qs_avgpace.append(QString(" /mi"));
884
			}
280 andreas 885
 
314 andreas 886
			if(Units == 1)		// Statute?
887
				speed = distance / ds.getTotalTime() * 3.6 / 1.609344;
888
			else
889
				speed = distance / ds.getTotalTime() * 3.6;
280 andreas 890
 
314 andreas 891
			qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
892
			qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
893
			qs_avghr.sprintf("%d bpm", ahr / anz);
280 andreas 894
 
314 andreas 895
			if(cad > 0)
896
				qs_avgcadence.sprintf("%d", cad / anz);
280 andreas 897
 
314 andreas 898
			// Print out the summary line and draw twi thin lines underneath
899
			if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
900
			                  (lastPage == 0 && firstPage == 0))
901
			{
902
				printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Normal, false));
903
				rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(aktLine + lineH, printer, true));
904
				printArea.drawText(rect, Qt::AlignLeft, qs_name);
905
				rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(aktLine + lineH, printer, true));
906
				printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_distance, false));
907
				rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(aktLine + lineH, printer, true));
908
				printArea.drawText(rect, Qt::AlignRight, qs_etime);
909
				rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(aktLine + lineH, printer, true));
910
				printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_avgspeed, false));
911
				rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(aktLine + lineH, printer, true));
912
				printArea.drawText(rect, Qt::AlignRight, qs_avghr);
913
				rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
914
				printArea.drawText(rect, Qt::AlignRight, qs_avgcadence);
915
				aktLine += (lineH + (lineH / 3.0));
916
				printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.1, printer, false)));
917
				printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
918
				printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine + 0.5, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + 0.5, printer, true));
919
				aktLine += (lineH / 3.0);
920
				printed = true;
921
			}
922
			else
923
			{
924
				aktLine += (lineH + (lineH / 3.0));
925
				aktLine += (lineH / 3.0);
926
			}
280 andreas 927
 
314 andreas 928
			delete qt;
929
			/* Get the laps. */
930
			laps = 1;
280 andreas 931
 
314 andreas 932
			for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
933
			{
934
				double spd;
935
				char *un;
280 andreas 936
 
314 andreas 937
				if((lap = ds.getLap(i)) == NULL)
938
					continue;
280 andreas 939
 
314 andreas 940
				qt = garmin_dtime(lap->start_time);
941
				qs_name.sprintf("Lap %03d - ", laps);
942
				qs_name.append(kl->formatTime(qt->time(), true));
943
				qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
944
				totdist += (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance;
945
				qs_totdist.sprintf("%2.f %s", totdist, (Units == 1) ? "ft" : "m");
946
				t = QTime(0, 0, 0, 0);
947
				t = t.addMSecs(lap->total_time * 10);
948
				qs_etime = t.toString("hh:mm:ss.zzz");
949
				spd = lap->total_distance / (lap->total_time / 100.0);
950
				delete qt;
951
				qt = 0;
280 andreas 952
 
314 andreas 953
				if(Units == 0)
954
				{
955
					un = (char *)"km/h";
956
					spd *= 3.6;
957
				}
958
				else
959
				{
960
					spd *= 3.6 / 1.609344;
961
					un = (char *)"mph";
962
				}
280 andreas 963
 
314 andreas 964
				qs_avgspeed.sprintf("%.2f %s", spd, un);
280 andreas 965
 
314 andreas 966
				if(lap->total_distance > 0 && lap->total_time != 0)
967
				{
968
					double fact;
280 andreas 969
 
314 andreas 970
					if(Units == 0)
971
						fact = 1000.0;		// 1 km
972
					else
973
						fact = 1609.344;		// 1 mile in meters
280 andreas 974
 
314 andreas 975
					long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
976
					int h = secs / 3600;
977
					int m = (secs - (h * 3600)) / 60;
978
					int s = secs - ((h * 3600) + (m * 60));
979
					t = QTime(h, m, s, 0);
980
					qs_avgpace = kl->formatTime(t, true);
280 andreas 981
 
314 andreas 982
					if(Units == 0)
983
						qs_avgpace.append(QString(" /km"));
984
					else
985
						qs_avgpace.append(QString(" /mi"));
986
				}
280 andreas 987
 
314 andreas 988
				qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
280 andreas 989
 
314 andreas 990
				if(lap->avg_cadence != 0xff)
991
					qs_avgcadence.sprintf("%d", lap->avg_cadence);
280 andreas 992
 
314 andreas 993
				// Draw a new detail line
994
				if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
995
				                  (lastPage == 0 && firstPage == 0))
996
				{
997
					rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(aktLine + lineH, printer, true));
998
					printArea.drawText(rect, Qt::AlignLeft, qs_name);
999
					rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(aktLine + lineH, printer, true));
1000
					printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_distance, false));
1001
					rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(aktLine + lineH, printer, true));
1002
					printArea.drawText(rect, Qt::AlignRight, qs_etime);
1003
					rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(aktLine + lineH, printer, true));
1004
					printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_avgspeed, false));
1005
					rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(aktLine + lineH, printer, true));
1006
					printArea.drawText(rect, Qt::AlignRight, qs_avghr);
1007
					rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
1008
					printArea.drawText(rect, Qt::AlignRight, qs_avgcadence);
1009
					printed = true;
1010
				}
280 andreas 1011
 
314 andreas 1012
				aktLine += lineH;
280 andreas 1013
 
314 andreas 1014
				if(aktLine >= extMil[3])	// Print on the next page
1015
				{
1016
					aktLine = extMil[3] + 10.0;
280 andreas 1017
 
314 andreas 1018
					if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
1019
					                  (lastPage == 0 && firstPage == 0))
1020
					{
1021
						printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
1022
						rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
1023
						printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
1024
						aktLine = extMil[1];
1025
						printed = true;
1026
					}
1027
					else
1028
						aktLine = extMil[1];
280 andreas 1029
 
314 andreas 1030
					if(printed)
1031
						printer.newPage();
280 andreas 1032
 
314 andreas 1033
					page++;
280 andreas 1034
 
314 andreas 1035
					// Print the headline of the table
1036
					if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
1037
					                  (lastPage == 0 && firstPage == 0))
1038
					{
1039
						printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Bold, false));
1040
						rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(aktLine + lineH, printer, true));
1041
						printArea.drawText(rect, Qt::AlignHCenter, i18n("Lap"));
1042
						rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(aktLine + lineH, printer, true));
1043
						printArea.drawText(rect, Qt::AlignHCenter, i18n("Distance"));
1044
						rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(aktLine + lineH, printer, true));
1045
						printArea.drawText(rect, Qt::AlignHCenter, i18n("Time"));
1046
						rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(aktLine + lineH, printer, true));
1047
						printArea.drawText(rect, Qt::AlignHCenter, i18n("Speed"));
1048
						rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(aktLine + lineH, printer, true));
1049
						printArea.drawText(rect, Qt::AlignHCenter, i18n("Heart rate"));
1050
						rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
1051
						printArea.drawText(rect, Qt::AlignHCenter, i18n("Cadence"));
1052
						aktLine += lineH;
1053
						printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.5, printer, false)));
1054
						printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
1055
						aktLine += 1.0;
1056
						printed = true;
1057
					}
1058
					else
1059
					{
1060
						aktLine += lineH;
1061
						aktLine += 1.0;
1062
					}
280 andreas 1063
 
314 andreas 1064
					printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Normal, false));
1065
				}
280 andreas 1066
 
314 andreas 1067
				delete qt;
1068
				laps++;
1069
			}
280 andreas 1070
 
314 andreas 1071
			aktLine = extMil[3] + 10.0;
280 andreas 1072
 
314 andreas 1073
			if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
1074
			                  (lastPage == 0 && firstPage == 0))
1075
			{
1076
				printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
1077
				rect.setCoords(milToPixel(extMil[0], printer),
1078
				               milToPixel(aktLine, printer, true),
1079
				               milToPixel(extMil[0] + 170, printer),
1080
				               milToPixel(aktLine + lineH, printer, true));
1081
				printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
1082
				printed = true;
1083
			}
280 andreas 1084
 
314 andreas 1085
			aktLine = extMil[1];
1086
			page++;
280 andreas 1087
 
314 andreas 1088
			if(printed && (page <= lastPage || lastPage == 0))
1089
				printer.newPage();
280 andreas 1090
 
314 andreas 1091
			if((lastPage > 0 && (page < firstPage || page > lastPage)))
1092
				break;
280 andreas 1093
 
314 andreas 1094
			// Draw the map on top of a new page
1095
			// Use 1/3 of the available height for the map
1096
			qreal resFact = 8;	// The factor to calculate the resolution for pixmaps
1097
			int width = (int)(milToPixel(170, printer) / resFact);
1098
			int height = (int)(milToPixel(extMil[3] - extMil[1], printer, true) / resFact);
1099
			pmPrMap = QPixmap(width, height / 3);	// 1/3 of page height
1100
			DIRTY = true;
1101
			int ct = curTab;
1102
			curTab = 1;
1103
			QApplication::restoreOverrideCursor();
1104
			showTrack();
1105
			QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1106
			DIRTY = false;
1107
			curTab = ct;
1108
			printArea.drawPixmap(milToPixel(extMil[0], printer),
1109
			                     milToPixel(extMil[1], printer),
1110
			                     pmPrMap.scaled((int)milToPixel(170, printer),
1111
			                                    (int)milToPixel(extMil[3] - extMil[1], printer, true) / 3,
1112
			                                    Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1113
			// Put a frame around the map
1114
			rect.setCoords(milToPixel(extMil[0], printer), milToPixel(extMil[1], printer, true),
1115
			               milToPixel(extMil[0] + 170, printer),
1116
			               milToPixel(extMil[1], printer, true) + (milToPixel(extMil[3] - extMil[1], printer, true) / 3));
1117
			printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.2, printer)));
1118
			printArea.drawRect(rect);
1119
			aktLine = (extMil[3] - extMil[1]) / 3.0 + extMil[1] + lineH;
280 andreas 1120
 
314 andreas 1121
			// Draw the heart rate diagram
1122
			rect.setCoords(milToPixel(extMil[0], printer),
1123
			               milToPixel(aktLine, printer, true),
1124
			               milToPixel(extMil[2], printer),
1125
			               milToPixel(aktLine + lineH, printer, true));
1126
			printArea.drawText(rect, Qt::AlignLeft, i18n("Heart rate:"));
1127
			aktLine += lineH;
1128
			qreal pixHeight = (extMil[3] - aktLine) / 3.0 - lineH * 2.0;
1129
			int realH = (int)milToPixel(pixHeight, printer, true);
1130
			height = realH / (int)resFact;
1131
			showThreeCurve(width, height);	// Calculate the curves
1132
			printArea.drawPixmap(milToPixel(extMil[0], printer),
1133
			                     milToPixel(aktLine, printer, true),
1134
			                     prHR.scaled((int)milToPixel(170, printer),
1135
			                                 realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1136
			rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
1137
			               milToPixel(extMil[0] + 170, printer),
1138
			               milToPixel(aktLine + pixHeight, printer, true));
1139
			printArea.drawRect(rect);
1140
			aktLine += pixHeight + lineH;
1141
 
1142
			// Draw the elevation diagram
1143
			rect.setCoords(milToPixel(extMil[0], printer),
1144
			               milToPixel(aktLine, printer, true),
1145
			               milToPixel(extMil[2], printer),
1146
			               milToPixel(aktLine + lineH, printer, true));
1147
			printArea.drawText(rect, Qt::AlignLeft, i18n("Elevation:"));
1148
			aktLine += lineH;
1149
			printArea.drawPixmap(milToPixel(extMil[0], printer),
1150
			                     milToPixel(aktLine, printer, true),
1151
			                     prElevation.scaled((int)milToPixel(170, printer),
1152
			                                        realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1153
			rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
1154
			               milToPixel(extMil[0] + 170, printer),
1155
			               milToPixel(aktLine + pixHeight, printer, true));
1156
			printArea.drawRect(rect);
1157
			aktLine += pixHeight + lineH;
1158
 
1159
			// Draw the speed diagram
1160
			rect.setCoords(milToPixel(extMil[0], printer),
1161
			               milToPixel(aktLine, printer, true),
1162
			               milToPixel(extMil[2], printer),
1163
			               milToPixel(aktLine + lineH, printer, true));
1164
			printArea.drawText(rect, Qt::AlignLeft, i18n("Speed:"));
1165
			aktLine += lineH;
1166
			printArea.drawPixmap(milToPixel(extMil[0], printer),
1167
			                     milToPixel(aktLine, printer, true),
1168
			                     prSpeed.scaled((int)milToPixel(170, printer),
1169
			                                    realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1170
			rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
1171
			               milToPixel(extMil[0] + 170, printer),
1172
			               milToPixel(aktLine + pixHeight, printer, true));
1173
			printArea.drawRect(rect);
1174
 
1175
			// Print the page number at the right bottom of the page
1176
			aktLine = extMil[3] + 10.0;
1177
			printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
1178
			rect.setCoords(milToPixel(extMil[0], printer),
1179
			               milToPixel(aktLine, printer, true),
1180
			               milToPixel(extMil[0] + 170, printer),
1181
			               milToPixel(aktLine + lineH, printer, true));
1182
			printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
1183
		}
1184
 
1185
		rakt = rakt->next;
280 andreas 1186
	}
1187
 
1188
	printArea.end();
1189
	// Mark printing as done
1190
	ActivePrint = false;
1191
	QApplication::restoreOverrideCursor();
88 andreas 1192
}
1193
 
280 andreas 1194
qreal sportwatcherWidget::milToPixel(qreal dist, QPrinter &pr, bool dir)
1195
{
1196
	QSizeF r = pr.paperSize(QPrinter::DevicePixel);
1197
	QSizeF m = pr.paperSize(QPrinter::Millimeter);
1198
 
314 andreas 1199
	if(!dir)	// width
1200
		return r.width() / m.width() * dist;
280 andreas 1201
	else
314 andreas 1202
		return r.height() / m.height() * dist;
280 andreas 1203
}
1204
 
104 andreas 1205
/*
1206
 * This function allows the user to choose a file name, where we save the
1207
 * actual lap in Garmins own TCX format. This format is simply a XML-file.
1208
 * For details about the schema of this file look at
1209
 * http://developer.garmin.com/schemas/tcx/v2/
1210
 */
88 andreas 1211
void sportwatcherWidget::fileSaveAs()
1212
{
314 andreas 1213
	QString fname;
1214
	QFile fn;
1215
	QString buffer;
1216
	RUN_NODE *rn, *rakt;
1217
	LAP *lap;
1218
	POINT *point;
1219
	int indent, i;
1220
	QDateTime *qt;
1221
	KUrl sDir("~/");
1222
	QRegExp rx("(\\.tcx|\\.gpx|\\.osm)$");
104 andreas 1223
 
314 andreas 1224
	if(!gmn)
104 andreas 1225
	{
314 andreas 1226
		KMessageBox::error(this, i18n("Currently no activity is selected!"));
1227
		return;
104 andreas 1228
	}
1229
 
246 andreas 1230
	rx.setPatternSyntax(QRegExp::RegExp);
232 andreas 1231
	fname = KFileDialog::getSaveFileName(sDir, QString("*.tcx|Garmin Training Center (*.tcx)\n*.gpx|GPS Excange Format (*.gpx)\n*.osm|OpenStreetMap (*.osm)"), this, QString("SportWatcher"));
104 andreas 1232
 
314 andreas 1233
	if(fname.isEmpty())
1234
		return;
104 andreas 1235
 
314 andreas 1236
	if(rx.indexIn(fname) < 0)
172 andreas 1237
	{
314 andreas 1238
		KMessageBox::error(this, i18n("The file %1 has no valid file extension!").arg(fname));
1239
		return;
172 andreas 1240
	}
1241
 
232 andreas 1242
	fn.setFileName(fname);
104 andreas 1243
 
314 andreas 1244
	if(fn.exists())
104 andreas 1245
	{
314 andreas 1246
		if(KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
1247
			return;
104 andreas 1248
	}
1249
 
246 andreas 1250
	rx.setPattern("*.gpx");
1251
	rx.setPatternSyntax(QRegExp::Wildcard);
172 andreas 1252
 
314 andreas 1253
	if(rx.exactMatch(fname))	// Should we create a *.gpx file?
172 andreas 1254
	{
314 andreas 1255
		sportwatcherWidget::saveGPX(fname);
1256
		return;
172 andreas 1257
	}
1258
 
246 andreas 1259
	rx.setPattern("*.osm");
1260
	rx.setPatternSyntax(QRegExp::Wildcard);
172 andreas 1261
 
314 andreas 1262
	if(rx.exactMatch(fname))	// Should we create a *.osm file?
172 andreas 1263
	{
314 andreas 1264
		sportwatcherWidget::saveOSM(fname);
1265
		return;
172 andreas 1266
	}
1267
 
1268
	// No, we create a *.tcx file!
171 andreas 1269
	indent = 0;
104 andreas 1270
	rn = ds.getRunNode();
1271
	lap = ds.getLap(rn->run->first_lap_index);
1272
 
314 andreas 1273
	if((point = ds.getPoint(lap->start_time)) == 0)
104 andreas 1274
	{
314 andreas 1275
		KMessageBox::error(this, i18n("No data to save!"));
1276
		return;
104 andreas 1277
	}
1278
 
314 andreas 1279
	if(!fn.open(QIODevice::ReadWrite | QIODevice::Truncate))
104 andreas 1280
	{
314 andreas 1281
		KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fname));
1282
		return;
104 andreas 1283
	}
1284
 
1285
	buffer = QString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
1286
	buffer.append("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\" ");
1287
	buffer.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
1288
	buffer.append("xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 ");
1289
	buffer.append("http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd\">\n\n");
314 andreas 1290
	writeTag(fn, buffer, indent);
104 andreas 1291
	buffer = QString("<folders/>\n\n");
314 andreas 1292
	writeTag(fn, buffer, indent);
104 andreas 1293
 
1294
	// Open a course
1295
	QFileInfo finfo(fname);
232 andreas 1296
	buffer = QString("<Courses>\n   <Course>\n      <name>%1</name>\n").arg(QFileInfo(finfo).baseName());
314 andreas 1297
	writeTag(fn, buffer, indent);
104 andreas 1298
	indent = 2;
1299
 
1300
	rakt = rn;
1301
 
314 andreas 1302
	while(rakt)
104 andreas 1303
	{
314 andreas 1304
		if(rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1305
		                  rakt->run->type != data_D1010)
1306
		{
1307
			rakt = rakt->next;
1308
			continue;
1309
		}
104 andreas 1310
 
314 andreas 1311
		for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
1312
		{
1313
			if((lap = ds.getLap(i)) == NULL)
1314
				continue;
104 andreas 1315
 
314 andreas 1316
			// Write the information of the lap
1317
			writeTag(fn, QString("<Lap>\n"), indent);
1318
			indent++;
1319
			buffer.sprintf("<TotalTimeSeconds>%f</TotalTimeSeconds>\n", (double)lap->total_time / 100.0);
1320
			writeTag(fn, buffer, indent);
1321
			qt = garmin_dtime(lap->start_time);
1322
			buffer = QString("<StartTime>%1</StartTime>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
1323
			writeTag(fn, buffer, indent);
1324
			buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", lap->total_distance);
1325
			writeTag(fn, buffer, indent);
104 andreas 1326
 
314 andreas 1327
			writeTag(fn, QString("<BeginPosition>\n"), indent);
1328
			indent++;
1329
			buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->begin.lat));
1330
			writeTag(fn, buffer, indent);
1331
			buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->begin.lon));
1332
			writeTag(fn, buffer, indent);
1333
			indent--;
1334
			writeTag(fn, QString("</BeginPosition>\n"), indent);
104 andreas 1335
 
314 andreas 1336
			writeTag(fn, QString("<EndPosition>\n"), indent);
1337
			indent++;
1338
			buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->end.lat));
1339
			writeTag(fn, buffer, indent);
1340
			buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->end.lon));
1341
			writeTag(fn, buffer, indent);
1342
			indent--;
1343
			writeTag(fn, QString("</EndPosition>\n"), indent);
104 andreas 1344
 
314 andreas 1345
			writeTag(fn, QString("<AverageHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
1346
			indent++;
1347
			buffer.sprintf("<Value>%d</Value>\n", lap->avg_heart_rate);
1348
			writeTag(fn, buffer, indent);
1349
			indent--;
1350
			writeTag(fn, QString("</AverageHeartRateBpm>\n"), indent);
104 andreas 1351
 
314 andreas 1352
			writeTag(fn, QString("<MaximumHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
1353
			indent++;
1354
			buffer.sprintf("<Value>%d</Value>\n", lap->max_heart_rate);
1355
			writeTag(fn, buffer, indent);
1356
			indent--;
1357
			writeTag(fn, QString("</MaximumHeartRateBpm>\n"), indent);
104 andreas 1358
 
314 andreas 1359
			if(lap->avg_cadence < 255)
1360
			{
1361
				buffer.sprintf("<AverageCadence>%d</AverageCadence>\n", lap->avg_cadence);
1362
				writeTag(fn, buffer, indent);
1363
				buffer.sprintf("<Cadence>%d</Cadence>\n", lap->avg_cadence);
1364
				writeTag(fn, buffer, indent);
1365
			}
172 andreas 1366
 
314 andreas 1367
			buffer = QString("<Intensity>%1</Intensity>\n").arg((!lap->intensity) ? "Active" : "Resting");
1368
			writeTag(fn, buffer, indent);
217 andreas 1369
 
314 andreas 1370
			buffer.sprintf("<Calories>%d</Calories>\n", lap->calories);
1371
			writeTag(fn, buffer, indent);
217 andreas 1372
 
314 andreas 1373
			buffer.sprintf("<MaximumSpeed>%f</MaximumSpeed>\n", lap->max_speed);
1374
			writeTag(fn, buffer, indent);
1375
			indent--;
1376
			writeTag(fn, QString("</Lap>\n"), indent);
104 andreas 1377
 
314 andreas 1378
			point = ds.getPoint(lap->start_time);
1379
			writeTag(fn, QString("<Track>\n"), indent);
1380
			indent++;
104 andreas 1381
 
314 andreas 1382
			while(point)
1383
			{
1384
				if(point->time > (lap->start_time + (lap->total_time / 100)))
1385
					break;
104 andreas 1386
 
314 andreas 1387
				writeTag(fn, QString("<Trackpoint>\n"), indent);
1388
				indent++;
1389
				qt = garmin_dtime(point->time);
1390
				buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
1391
				writeTag(fn, buffer, indent);
1392
				delete qt;
1393
				writeTag(fn, QString("<Position>\n"), indent);
1394
				indent++;
1395
				buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(point->posn.lat));
1396
				writeTag(fn, buffer, indent);
1397
				buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(point->posn.lon));
1398
				writeTag(fn, buffer, indent);
1399
				indent--;
1400
				writeTag(fn, QString("</Position>\n"), indent);
104 andreas 1401
 
314 andreas 1402
				if(point->alt < 20000.0)
1403
				{
1404
					buffer.sprintf("<AltitudeMeters>%f</AltitudeMeters>\n", point->alt);
1405
					writeTag(fn, buffer, indent);
1406
				}
104 andreas 1407
 
314 andreas 1408
				buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", point->distance);
1409
				writeTag(fn, buffer, indent);
104 andreas 1410
 
314 andreas 1411
				if(point->heart_rate > 0 && point->heart_rate < 250)
1412
				{
1413
					writeTag(fn, QString("<HeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
1414
					indent++;
1415
					buffer.sprintf("<Value>%d</Value>\n", point->heart_rate);
1416
					writeTag(fn, buffer, indent);
1417
					indent--;
1418
					writeTag(fn, QString("</HeartRateBpm>\n"), indent);
1419
				}
104 andreas 1420
 
314 andreas 1421
				if(point->cadence < 0xff)
1422
				{
1423
					buffer.sprintf("<Cadence>%d</Cadence>\n", point->cadence);
1424
					writeTag(fn, buffer, indent);
1425
				}
215 andreas 1426
 
314 andreas 1427
				buffer.sprintf("<SensorState>%s</SensorState>\n", (!point->sensor) ? "Absent" : "Present");
1428
				writeTag(fn, buffer, indent);
1429
				indent--;
1430
				writeTag(fn, QString("</Trackpoint>\n"), indent);
1431
				point = ds.getPoint(point->time + 1);
1432
			}
104 andreas 1433
 
314 andreas 1434
			indent--;
1435
			writeTag(fn, QString("</Track>\n"), indent);
1436
		}
104 andreas 1437
 
314 andreas 1438
		indent--;
1439
		writeTag(fn, QString("</Course>\n"), indent);
1440
		indent--;
1441
		writeTag(fn, QString("</Courses>\n"), indent);
1442
		rakt = rakt->next;
104 andreas 1443
	}
1444
 
1445
	// Write information about device
1446
	// Here my personal signature is written :-)
314 andreas 1447
	writeTag(fn, QString("<Author xsi:type=\"Application_t\">\n"), indent);
104 andreas 1448
	indent++;
314 andreas 1449
	writeTag(fn, QString("<Name>SportWatcher</Name>\n"), indent);
1450
	writeTag(fn, QString("<Build>\n"), indent);
104 andreas 1451
	indent++;
314 andreas 1452
	writeTag(fn, QString("<Version>\n"), indent);
104 andreas 1453
	indent++;
314 andreas 1454
	writeTag(fn, QString("<VersionMajor>0</VersionMajor>\n"), indent);
1455
	writeTag(fn, QString("<VersionMinor>1</VersionMinor>\n"), indent);
1456
	writeTag(fn, QString("<BuildMajor>0</BuildMajor>\n"), indent);
1457
	writeTag(fn, QString("<BuildMinor>0</BuildMinor>\n"), indent);
104 andreas 1458
	indent--;
314 andreas 1459
	writeTag(fn, QString("</Version>\n"), indent);
1460
	writeTag(fn, QString("<Type>Beta</Type>\n"), indent);
1461
	writeTag(fn, QString("<Time>Jan 31 2008, 00:00:00</Time>\n"), indent);
1462
	writeTag(fn, QString("<Builder>theosys</Builder>\n"), indent);
104 andreas 1463
	indent--;
314 andreas 1464
	writeTag(fn, QString("</Build>\n"), indent);
1465
	writeTag(fn, QString("<LangID>EN</LangID>\n"), indent);
1466
	writeTag(fn, QString("<PartNumber>000-00000-00</PartNumber>\n"), indent);
104 andreas 1467
	indent--;
314 andreas 1468
	writeTag(fn, QString("</Author>\n"), indent);
1469
	writeTag(fn, QString("</TrainingCenterDatabase>\n"), indent);
104 andreas 1470
 
1471
	fn.close();
1472
	KMessageBox::information(this, i18n("File ") + fname + i18n(" was written successfully."));
88 andreas 1473
}
1474
 
1475
void sportwatcherWidget::fileSave()
1476
{
172 andreas 1477
	KMessageBox::information(this, i18n("This function is currently not implemented!"));
88 andreas 1478
}
1479
 
172 andreas 1480
void sportwatcherWidget::saveGPX(const QString &fn)
1481
{
314 andreas 1482
	QFile qf;
1483
	QString buffer;
1484
	RUN_NODE *rn, *rakt;
1485
	LAP *lap;
1486
	POINT *point;
1487
	int indent;
1488
	unsigned int i;
1489
	QDateTime *qt;
1490
	double minLat, minLon, maxLat, maxLon;
172 andreas 1491
 
1492
	indent = 0;
1493
	rn = ds.getRunNode();
1494
	lap = ds.getLap(rn->run->first_lap_index);
1495
 
314 andreas 1496
	if((point = ds.getPoint(lap->start_time)) == 0)
172 andreas 1497
	{
314 andreas 1498
		KMessageBox::error(this, i18n("No data to save!"));
1499
		return;
172 andreas 1500
	}
1501
 
232 andreas 1502
	qf.setFileName(fn);
172 andreas 1503
 
314 andreas 1504
	if(!qf.open(QIODevice::ReadWrite | QIODevice::Truncate))
172 andreas 1505
	{
314 andreas 1506
		KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fn));
1507
		return;
172 andreas 1508
	}
1509
 
1510
	buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
1511
	buffer.append("<gpx version=\"1.1\" creator=\"TheoSys SportWatcher\" xmlns=\"http://www.topografix.com/GPX/1/1\">\n");
1512
	buffer.append("   <metadata>\n");
1513
	indent = 0;
314 andreas 1514
	writeTag(qf, buffer, indent);
172 andreas 1515
 
1516
	// Find the edges of our coordinates
1517
	// We need this information in the header (metadata)
1518
	rakt = rn;
1519
	minLat = -90.0;
1520
	minLon = -180.0;
1521
	maxLat = 90.0;
1522
	maxLon = 180.0;
1523
 
314 andreas 1524
	while(rakt)
172 andreas 1525
	{
314 andreas 1526
		if(rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1527
		                  rakt->run->type != data_D1010)
1528
		{
1529
			rakt = rakt->next;
1530
			continue;
1531
		}
172 andreas 1532
 
314 andreas 1533
		i = rakt->run->first_lap_index;
172 andreas 1534
 
314 andreas 1535
		// get the first lap
1536
		if((lap = ds.getLap(i)) == NULL)
1537
			continue;
172 andreas 1538
 
314 andreas 1539
		i = 0;
172 andreas 1540
 
314 andreas 1541
		// iterate the points associated with the laps
1542
		while((point = ds.getPoint(i)) != 0)
1543
		{
1544
			if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1545
			{
1546
				i = point->time + 1;
1547
				continue;
1548
			}
172 andreas 1549
 
314 andreas 1550
			if(SEMI2DEG(point->posn.lat) > minLat)
1551
				minLat = SEMI2DEG(point->posn.lat);
172 andreas 1552
 
314 andreas 1553
			if(SEMI2DEG(point->posn.lat) < maxLat)
1554
				maxLat = SEMI2DEG(point->posn.lat);
172 andreas 1555
 
314 andreas 1556
			if(SEMI2DEG(point->posn.lon) > minLon)
1557
				minLon = SEMI2DEG(point->posn.lon);
172 andreas 1558
 
314 andreas 1559
			if(SEMI2DEG(point->posn.lon) < maxLon)
1560
				maxLon = SEMI2DEG(point->posn.lon);
1561
 
1562
			i = point->time + 1;
1563
		}
1564
 
1565
		rakt = rakt->next;
172 andreas 1566
	}
314 andreas 1567
 
172 andreas 1568
	buffer.sprintf("      <bounds minlat=\"%f\" minlon=\"%f\" maxlat=\"%f\" maxlon=\"%f\" />\n",
314 andreas 1569
	               maxLat, minLon, minLat, maxLon);
172 andreas 1570
	buffer.append("   </metadata>\n");
1571
	buffer.append("   <trk>\n");
1572
	buffer.append("      <trkseg>\n");
314 andreas 1573
	writeTag(qf, buffer, indent);
172 andreas 1574
	indent = 3;
1575
	rn = ds.getRunNode();
1576
	lap = ds.getLap(rn->run->first_lap_index);
1577
	i = 0;
1578
 
314 andreas 1579
	while((point = ds.getPoint(i)) != 0)
172 andreas 1580
	{
314 andreas 1581
		if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1582
		{
1583
			i = point->time + 1;
1584
			continue;
1585
		}
172 andreas 1586
 
314 andreas 1587
		buffer.sprintf("<trkpt lat=\"%f\" lon=\"%f\">\n",
1588
		               SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
1589
		writeTag(qf, buffer, indent);
1590
		indent++;
1591
		buffer.sprintf("<ele>%f</ele>\n", point->alt);
1592
		writeTag(qf, buffer, indent);
1593
		qt = garmin_dtime(point->time);
1594
		buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
1595
		writeTag(qf, buffer, indent);
1596
		indent--;
1597
		writeTag(qf, QString("</trkpt>\n"), indent);
1598
		i = point->time + 1;
172 andreas 1599
	}
1600
 
1601
	indent = 0;
1602
	buffer = QString("      </trkseg>\n");
1603
	buffer.append("   </trk>\n");
1604
	buffer.append("</gpx>\n");
1605
	writeTag(qf, buffer, indent);
1606
	qf.close();
1607
	KMessageBox::information(this, i18n("File ") + fn + i18n(" was written successfully."));
1608
}
1609
 
1610
void sportwatcherWidget::saveOSM(const QString &fn)
1611
{
314 andreas 1612
	QFile qf;
1613
	QString buffer;
1614
	RUN_NODE *rn, *rakt;
1615
	LAP *lap;
1616
	POINT *point;
1617
	int indent, id, j;
1618
	unsigned int i;
1619
	double minLat, minLon, maxLat, maxLon;
1620
	QDateTime *qt;
172 andreas 1621
 
1622
	indent = 0;
1623
	rn = ds.getRunNode();
1624
	lap = ds.getLap(rn->run->first_lap_index);
1625
 
314 andreas 1626
	if((point = ds.getPoint(lap->start_time)) == 0)
172 andreas 1627
	{
314 andreas 1628
		KMessageBox::error(this, i18n("No data to save!"));
1629
		return;
172 andreas 1630
	}
1631
 
232 andreas 1632
	qf.setFileName(fn);
172 andreas 1633
 
314 andreas 1634
	if(!qf.open(QIODevice::ReadWrite | QIODevice::Truncate))
172 andreas 1635
	{
314 andreas 1636
		KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fn));
1637
		return;
172 andreas 1638
	}
1639
 
1640
	buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
1641
	buffer.append("<osm version=\"0.5\" generator=\"TheoSys SportWatcher\">\n");
1642
	indent = 0;
314 andreas 1643
	writeTag(qf, buffer, indent);
172 andreas 1644
	// Find the edges of our coordinates
1645
	// We need this information in the header (metadata)
1646
	rakt = rn;
1647
	minLat = -90.0;
1648
	minLon = -180.0;
1649
	maxLat = 90.0;
1650
	maxLon = 180.0;
1651
 
314 andreas 1652
	while(rakt)
172 andreas 1653
	{
314 andreas 1654
		if(rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1655
		                  rakt->run->type != data_D1010)
1656
		{
1657
			rakt = rakt->next;
1658
			continue;
1659
		}
172 andreas 1660
 
314 andreas 1661
		i = rakt->run->first_lap_index;
172 andreas 1662
 
314 andreas 1663
		// get the first lap
1664
		if((lap = ds.getLap(i)) == NULL)
1665
			continue;
172 andreas 1666
 
314 andreas 1667
		i = 0;
172 andreas 1668
 
314 andreas 1669
		// iterate the points associated with the laps
1670
		while((point = ds.getPoint(i)) != 0)
1671
		{
1672
			if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1673
			{
1674
				i = point->time + 1;
1675
				continue;
1676
			}
172 andreas 1677
 
314 andreas 1678
			if(SEMI2DEG(point->posn.lat) > minLat)
1679
				minLat = SEMI2DEG(point->posn.lat);
172 andreas 1680
 
314 andreas 1681
			if(SEMI2DEG(point->posn.lat) < maxLat)
1682
				maxLat = SEMI2DEG(point->posn.lat);
172 andreas 1683
 
314 andreas 1684
			if(SEMI2DEG(point->posn.lon) > minLon)
1685
				minLon = SEMI2DEG(point->posn.lon);
172 andreas 1686
 
314 andreas 1687
			if(SEMI2DEG(point->posn.lon) < maxLon)
1688
				maxLon = SEMI2DEG(point->posn.lon);
1689
 
1690
			i = point->time + 1;
1691
		}
1692
 
1693
		rakt = rakt->next;
172 andreas 1694
	}
314 andreas 1695
 
172 andreas 1696
	buffer.sprintf("   <bound box='%f,%f,%f,%f' origin='http://www.openstreetmap.org/api/0.5' />\n",
314 andreas 1697
	               maxLat, minLon, minLat, maxLon);
1698
	writeTag(qf, buffer, indent);
172 andreas 1699
	indent = 1;
1700
	rn = ds.getRunNode();
1701
	lap = ds.getLap(rn->run->first_lap_index);
1702
	i = 0;
1703
	id = -1;
1704
 
314 andreas 1705
	while((point = ds.getPoint(i)) != 0)
172 andreas 1706
	{
314 andreas 1707
		if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1708
		{
1709
			i = point->time + 1;
1710
			continue;
1711
		}
172 andreas 1712
 
314 andreas 1713
		buffer.sprintf("<node id='%d' action='modify' visible='true' lat=\"%f\" lon=\"%f\">\n",
1714
		               id, SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
1715
		writeTag(qf, buffer, indent);
1716
		indent++;
1717
		buffer = QString("<tag k='created_by' v='TheoSys Sportwatcher' />\n");
1718
		writeTag(qf, buffer, indent);
1719
		buffer = QString("<tag k='highway' v='tertiary' />\n");
1720
		writeTag(qf, buffer, indent);
1721
		indent--;
1722
		writeTag(qf, QString("</node>\n"), indent);
1723
		id--;
1724
		i = point->time + 1;
172 andreas 1725
	}
1726
 
1727
	qt = garmin_dtime(lap->start_time);
1728
	buffer.sprintf("<way id='%d' action='modify' visible='true' timestamp='%s'>\n",
314 andreas 1729
	               id, QString(qt->toString("yyyy-MM-ddThh:mm:ssZ")).toAscii().data());
172 andreas 1730
	writeTag(qf, buffer, indent);
1731
	indent++;
1732
 
314 andreas 1733
	for(j = -1; j > id; j--)
172 andreas 1734
	{
314 andreas 1735
		buffer.sprintf("<nd ref='%d' />\n", j);
1736
		writeTag(qf, buffer, indent);
172 andreas 1737
	}
1738
 
1739
	indent--;
1740
	writeTag(qf, QString("</way>\n"), indent);
1741
	indent = 0;
1742
	writeTag(qf, QString("</osm>\n"), indent);
1743
	qf.close();
232 andreas 1744
	KMessageBox::information(this, i18n("File %1 was written successfully.").arg(fn));
172 andreas 1745
}
1746
 
88 andreas 1747
void sportwatcherWidget::fileOpen()
1748
{
314 andreas 1749
	QString fname = KFileDialog::getOpenFileName(Data, QString("*.gmn"), this, QString("SportWatcher"));
1750
	int m;
88 andreas 1751
 
314 andreas 1752
	if(fname.isEmpty())
1753
		return;
88 andreas 1754
 
1755
	spw.destroy();
1756
 
314 andreas 1757
	if(spw.setFileName(fname.toAscii().data()) == -1)
1758
		return;
88 andreas 1759
 
314 andreas 1760
	if(gmn)
1761
		garmin_free_data(gmn);
88 andreas 1762
 
1763
	gmn = spw.readFile();
104 andreas 1764
	zfactor = 0;
137 andreas 1765
 
314 andreas 1766
	if((m = garmin_count_error()) > 0)
137 andreas 1767
	{
314 andreas 1768
		int i, key = -1;
137 andreas 1769
 
314 andreas 1770
		for(i = 0; i < m; i++)
1771
			KMessageBox::error(this, QString(garmin_get_next_error(&key)));
137 andreas 1772
 
314 andreas 1773
		garmin_clear_errors();
1774
		return;
137 andreas 1775
	}
1776
 
246 andreas 1777
	DIRTY = true;
250 andreas 1778
	tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
88 andreas 1779
	showLaps();
100 andreas 1780
	showTrack();
88 andreas 1781
	showCurves();
250 andreas 1782
 
314 andreas 1783
	if(curTab == 2)
250 andreas 1784
	{
314 andreas 1785
		showThreeCurve();
1786
		tabDirt2 = false;
250 andreas 1787
	}
1788
 
1789
	tabDirt0 = tabDirt3 = false;
246 andreas 1790
	DIRTY = false;
88 andreas 1791
}
1792
 
314 andreas 1793
/**
1794
 * This function is called from the XML parser in "gmn_import"
1795
 * whenever an activity is complete.
1796
 * Necessary because there may be more than one activity in a history
1797
 * file.
1798
 */
1799
void sportwatcherWidget::saveImported(void *gd)
1800
{
1801
gmn_import import;
1802
QString tgfile, fld, px;
1803
RUN_NODE *rn;
1804
LAP *lap;
1805
garmin_data *g = (garmin_data *)gd;
1806
QFileInfo datei;
1807
QPixmap qpx;
1808
QList<QTreeWidgetItem *>item;
1809
QTreeWidgetItem *el, *it;
1810
 
1811
	if(!g)
1812
	{
1813
		std::cerr << "sportwatcherWidget::saveImported: Empty data! Nothing was saved!" << std::endl;
1814
		return;
1815
	}
1816
 
1817
	// Find the filename;
1818
	// It consists of the date and the time.
1819
	// We need this information to set the correct path to store the file.
1820
	tgfile = Data;		// The base path
1821
	rn = ds.getRunNode();
1822
	lap = ds.getLap(rn->run->first_lap_index);
1823
	QDateTime *qt = garmin_dtime(lap->start_time);
1824
	tgfile.append(qt->toString("/yyyy"));   // year is a folder
1825
	tgfile.append(qt->toString("/MM"));	// month is a folder
1826
	tgfile.append(qt->toString("/yyyyMMddThhmmss"));	// The file name
1827
	tgfile.append(".gmn");		// Extension of file name
1828
	datei.setFile(tgfile);
1829
std:cerr << "sportwatcherWidget::saveImported:Saving to file " << datei.absoluteFilePath().toAscii().data() << std::endl;
1830
	// save the data to a real file, but only if it doesn't exist allready.
1831
	garmin_save_all(g, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 0);
1832
 
1833
	// in case the item is already in the list on the left side, we
1834
	// only highlight the item.
1835
	item = ui_sportwatcherWidgetBase.liActivities->findItems(tgfile, Qt::MatchExactly);
1836
 
1837
	if(item.size() > 0)
1838
	{
1839
		ui_sportwatcherWidgetBase.liActivities->setItemSelected(item.at(0), true);
1840
		ui_sportwatcherWidgetBase.liActivities->setCurrentItem(item.at(0));
1841
		return;
1842
	}
1843
 
1844
	// insert everything into the list on the left side
1845
	switch(rn->run->sport_type)
1846
	{
1847
		case D1000_running:
1848
			fld = i18n("Running");
1849
			px = QString("spw-running");
1850
		break;
1851
 
1852
		case D1000_biking:
1853
			fld = i18n("Biking");
1854
			px = QString("bike");
1855
		break;
1856
 
1857
		default:
1858
			fld = i18n("Others");
1859
			px = QString("other");
1860
	}
1861
 
1862
	// Do we have allready so items in the list?
1863
	item = ui_sportwatcherWidgetBase.liActivities->findItems(fld, Qt::MatchExactly);
1864
 
1865
	if(item.size() > 0)
1866
	{
1867
		el = new QTreeWidgetItem(item.at(0));
1868
		el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
1869
		el->setData(0, Qt::UserRole, tgfile);
1870
		el->setIcon(0, KIcon(px));
1871
	}
1872
	else	// no, this is the first item. (shouldn't be!)
1873
	{
1874
		it = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
1875
		it->setText(0, fld);
1876
		it->setIcon(0, KIcon(QString("history")));
1877
 
1878
		el = new QTreeWidgetItem(item.at(0));
1879
		el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
1880
		el->setData(0, Qt::UserRole, tgfile);
1881
		el->setIcon(0, KIcon(px));
1882
	}
1883
}
1884
 
217 andreas 1885
void sportwatcherWidget::fileImport()
1886
{
1887
QString fname = KFileDialog::getOpenFileName(QString("~/"), QString("*.tcx"), this, QString("SportWatcher"));
1888
gmn_import import;
1889
int m;
225 andreas 1890
QString tgfile, fld, px;
232 andreas 1891
QPixmap qpx;
225 andreas 1892
QFileInfo datei;
246 andreas 1893
QList<QTreeWidgetItem *>item;
1894
QTreeWidgetItem *el, *it;
225 andreas 1895
LAP *lap;
1896
RUN_NODE *rn;
217 andreas 1897
 
314 andreas 1898
	if(fname.isEmpty())
1899
		return;
217 andreas 1900
 
314 andreas 1901
	import.connectCallback(this);
1902
	import.setFile(fname);
217 andreas 1903
 
314 andreas 1904
	if((m = import.import()) != 0)
217 andreas 1905
	{
314 andreas 1906
		KMessageBox::error(this, QString(import.getError(m)));
1907
		return;
217 andreas 1908
	}
1909
 
314 andreas 1910
	if(gmn)
246 andreas 1911
	{
314 andreas 1912
		garmin_free_data(gmn);
1913
		gmn = 0;
246 andreas 1914
	}
217 andreas 1915
 
314 andreas 1916
	if(!(gmn = import.getGarminData()))
1917
		return;
217 andreas 1918
 
246 andreas 1919
	DIRTY = true;
250 andreas 1920
	tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
217 andreas 1921
	showLaps();
1922
	showTrack();
1923
	showCurves();
250 andreas 1924
 
314 andreas 1925
	if(curTab == 2)
250 andreas 1926
	{
314 andreas 1927
		showThreeCurve();
1928
		tabDirt2 = false;
250 andreas 1929
	}
1930
 
1931
	tabDirt0 = tabDirt3 = false;
246 andreas 1932
	DIRTY = false;
225 andreas 1933
 
1934
	// Find the filename;
1935
	// It consists of the date and the time.
1936
	// We need this information to set the correct path to store the file.
1937
	tgfile = Data;		// The base path
1938
	rn = ds.getRunNode();
1939
	lap = ds.getLap(rn->run->first_lap_index);
314 andreas 1940
	QDateTime *qt = garmin_dtime(lap->start_time);
1941
	tgfile.append(qt->toString("/yyyy"));   // year is a folder
1942
	tgfile.append(qt->toString("/MM"));	// month is a folder
1943
	tgfile.append(qt->toString("/yyyyMMddThhmmss"));	// The file name
1944
	tgfile.append(".gmn");		// Extension of file name
1945
	datei.setFile(tgfile);
1946
	std:cerr << "sportwatcherWidget::fileImport:Saving to file " << datei.absoluteFilePath().toAscii().data() << std::endl;
225 andreas 1947
	// save the data to a real file, but only if it doesn't exist allready.
314 andreas 1948
	garmin_save_all(gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 0);
225 andreas 1949
 
1950
	// in case the item is already in the list on the left side, we
1951
	// only highlight the item.
314 andreas 1952
	item = ui_sportwatcherWidgetBase.liActivities->findItems(tgfile, Qt::MatchExactly);
246 andreas 1953
 
314 andreas 1954
	if(item.size() > 0)
225 andreas 1955
	{
314 andreas 1956
		ui_sportwatcherWidgetBase.liActivities->setItemSelected(item.at(0), true);
1957
		ui_sportwatcherWidgetBase.liActivities->setCurrentItem(item.at(0));
1958
		return;
225 andreas 1959
	}
1960
 
1961
	// insert everything into the list on the left side
314 andreas 1962
	switch(rn->run->sport_type)
225 andreas 1963
	{
314 andreas 1964
		case D1000_running:
1965
			fld = i18n("Running");
1966
			px = QString("spw-running");
1967
		break;
225 andreas 1968
 
314 andreas 1969
		case D1000_biking:
1970
			fld = i18n("Biking");
1971
			px = QString("bike");
1972
		break;
225 andreas 1973
 
314 andreas 1974
		default:
1975
			fld = i18n("Others");
1976
			px = QString("other");
225 andreas 1977
	}
1978
 
1979
	// Do we have allready so items in the list?
314 andreas 1980
	item = ui_sportwatcherWidgetBase.liActivities->findItems(fld, Qt::MatchExactly);
246 andreas 1981
 
314 andreas 1982
	if(item.size() > 0)
225 andreas 1983
	{
314 andreas 1984
		el = new QTreeWidgetItem(item.at(0));
1985
		el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
1986
		el->setData(0, Qt::UserRole, tgfile);
1987
		el->setIcon(0, KIcon(px));
225 andreas 1988
	}
1989
	else	// no, this is the first item. (shouldn't be!)
1990
	{
314 andreas 1991
		it = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
1992
		it->setText(0, fld);
1993
		it->setIcon(0, KIcon(QString("history")));
246 andreas 1994
 
314 andreas 1995
		el = new QTreeWidgetItem(item.at(0));
1996
		el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
1997
		el->setData(0, Qt::UserRole, tgfile);
1998
		el->setIcon(0, KIcon(px));
225 andreas 1999
	}
217 andreas 2000
}
2001
 
218 andreas 2002
/*
2003
 * Display a small dialog to rename the currently loaded session.
2004
 */
2005
void sportwatcherWidget::editRename()
2006
{
314 andreas 2007
	bool ok;
2008
	QString name, inhalt;
2009
	QList<QTreeWidgetItem *> item;
2010
	QTreeWidgetItem *lvItem;
2011
	QFileInfo datei;
2012
	RUN_NODE *rn;
2013
	LAP *lap;
2014
	garmin_list *list;
2015
	D1009 *n;
218 andreas 2016
 
314 andreas 2017
	if(!gmn)
218 andreas 2018
	{
314 andreas 2019
		KMessageBox::error(this, i18n("There is no session selected!"));
2020
		return;
218 andreas 2021
	}
314 andreas 2022
 
218 andreas 2023
	rn = ds.getRunNode();
314 andreas 2024
	item = ui_sportwatcherWidgetBase.liActivities->selectedItems();
218 andreas 2025
	lvItem = item.first();
2026
 
314 andreas 2027
	if(!isdigit(rn->run->workout.name[0]))
2028
		inhalt = lvItem->text(0);
218 andreas 2029
	else
314 andreas 2030
		inhalt.clear();
218 andreas 2031
 
2032
	name = KInputDialog::getText(i18n("Rename session"), i18n("Session name"),
314 andreas 2033
	                             inhalt, &ok, this, (QValidator *)0, QString("Nxxxxxxxxxxxxxx"),
2034
	                             i18n("Enter a new name for the currently selected activity."));
218 andreas 2035
 
314 andreas 2036
	if(!ok)
2037
		return;
218 andreas 2038
 
314 andreas 2039
	if(name.length() <= 1)
218 andreas 2040
	{
314 andreas 2041
		lap = ds.getLap(rn->run->first_lap_index);
2042
		const QDateTime *qt = garmin_dtime(lap->start_time);
2043
		QString idx = kl->formatDateTime(*qt, KLocale::ShortDate, true);
2044
		lvItem->setText(0, idx);
2045
		datei.setFile(lvItem->data(0, Qt::UserRole).toString());
2046
		garmin_save_all(gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 1);
2047
		delete qt;
2048
		return;
218 andreas 2049
	}
2050
 
314 andreas 2051
	strncpy(rn->run->workout.name, name.toAscii().data(), 16);
218 andreas 2052
 
314 andreas 2053
	if(gmn->type != data_Dlist)
218 andreas 2054
	{
314 andreas 2055
		KMessageBox::error(this, i18n("editRename: Unexpected structure type %1 found!").arg(gmn->type));
2056
		return;
218 andreas 2057
	}
2058
 
2059
	list = (garmin_list *)gmn->data;
2060
 
314 andreas 2061
	if(list->head->data->type != data_D1009)	// This should be the run node
218 andreas 2062
	{
314 andreas 2063
		KMessageBox::error(this, i18n("editRename: The run node was not found!"));
2064
		return;
218 andreas 2065
	}
2066
 
2067
	n = (D1009 *)list->head->data->data;
314 andreas 2068
	strncpy(n->workout.name, rn->run->workout.name, 15);
2069
	lvItem->setText(0, name);
2070
	datei.setFile(lvItem->data(0, Qt::UserRole).toString());
2071
	garmin_save_all(gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 1);
218 andreas 2072
}
2073
 
88 andreas 2074
void sportwatcherWidget::fileNew()
2075
{
314 andreas 2076
	progressWidget *dlg = new progressWidget(this);
96 andreas 2077
 
100 andreas 2078
	dlg->show();
137 andreas 2079
 
314 andreas 2080
	if(!dlg->Download())
137 andreas 2081
	{
314 andreas 2082
		int m, key;
137 andreas 2083
 
314 andreas 2084
		key = -1;
137 andreas 2085
 
314 andreas 2086
		for(m = 0; m < garmin_count_error(); m++)
2087
			KMessageBox::error(this, QString(garmin_get_next_error(&key)));
137 andreas 2088
	}
2089
	else
314 andreas 2090
		getActivities();
137 andreas 2091
 
2092
	garmin_clear_errors();
96 andreas 2093
	delete dlg;
88 andreas 2094
}
2095
 
2096
/*
2097
 * This function is called, when the user clicks at the menu point
2098
 * "Save Heart Rate".
2099
 * First, a file dialog box is displayed, where the user can choose a
2100
 * directory and a file name to save the heart rate.
2101
 * If the file could successfully be created, the heart rate is saved
137 andreas 2102
 * in the "HRM"-format. This is the native format Polar uses to store
88 andreas 2103
 * heart rate data. I've choosen this format, because it's popular and
2104
 * used by many other software too.
2105
 */
2106
void sportwatcherWidget::extrasSaveHR()
2107
{
314 andreas 2108
	QString fname, str1, str2;
2109
	QFile fdfile;
2110
	QDateTime *qt, *oldqt;
2111
	QDate dat;
2112
	QTime t;
2113
	QDir dir = QDir::home();
2114
	char hv0[256];
2115
	RUN_NODE *rn;
2116
	LAP *lap, *alap;
2117
	POINT *point;
2118
	int samples, smp, seconds, anz, nsec, samsec;
2119
	int avgHeart, minHeart, maxHeart, aktHeart;
2120
	int secRange1, secRange2, secRange3, secAbove, secBeyond;
88 andreas 2121
 
314 andreas 2122
	if(!gmn)
88 andreas 2123
	{
314 andreas 2124
		KMessageBox::information(this, i18n("There is no activity open"));
2125
		return;
88 andreas 2126
	}
2127
 
314 andreas 2128
	if(HRM.isEmpty())
2129
		str1 = dir.path();
88 andreas 2130
	else
314 andreas 2131
		str1 = HRM;
88 andreas 2132
 
2133
	str1 +=  "/" + StartTime.toString("yyyyMMddThhmmss.zzz.hrm");
2134
	fname = KFileDialog::getSaveFileName(str1, QString("*.hrm"), this, QString("SportWatcher"));
2135
 
314 andreas 2136
	if(fname.isEmpty())
2137
		return;
88 andreas 2138
 
232 andreas 2139
	fdfile.setFileName(fname);
88 andreas 2140
 
314 andreas 2141
	if(fdfile.exists())
88 andreas 2142
	{
314 andreas 2143
		if(KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
2144
			return;
88 andreas 2145
	}
2146
 
314 andreas 2147
	if(!fdfile.open(QIODevice::ReadWrite | QIODevice::Truncate))
88 andreas 2148
	{
314 andreas 2149
		KMessageBox::error(this, i18n("Error creating a file!\nPlease check permissions."));
2150
		return;
88 andreas 2151
	}
2152
 
2153
	rn = ds.getRunNode();
2154
	lap = ds.getLap(rn->run->first_lap_index);
2155
	t = StartTime.time();
2156
	dat = StartTime.date();
2157
 
314 andreas 2158
	if((point = ds.getPoint(lap->start_time)) == 0)
88 andreas 2159
	{
314 andreas 2160
		fdfile.close();
2161
		return;
88 andreas 2162
	}
2163
 
314 andreas 2164
	strcpy(hv0, "[Params]\n");
88 andreas 2165
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2166
	str1 = dat.toString("yyyyMMdd");
2167
	str2 = t.toString("hh:mm:ss.z");
2168
	sprintf(hv0, "Version=106\nMonitor=11\nSMode=000000000\nDate=%s\nStartTime=%s\n",
314 andreas 2169
	        str1.toAscii().data(), str2.toAscii().data());
88 andreas 2170
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2171
	t.setHMS(0, 0, 0);
2172
	t = t.addSecs(max_time);
2173
	str2 = t.toString("hh:mm:ss.z");
2174
 
314 andreas 2175
	switch(sampleTime)
88 andreas 2176
	{
314 andreas 2177
		case 0: samsec = 5; break;
2178
		case 1: samsec = 15; break;
2179
		case 2: samsec = 30; break;
2180
		case 3: samsec = 60; break;
2181
		default:
2182
			samsec = 15;
88 andreas 2183
	}
2184
 
2185
	sprintf(hv0, "Length=%s\nInterval=%d\nUpper1=%d\nLower1=%d\nUpper2=%d\n",
314 andreas 2186
	        str2.toAscii().data(), samsec, upper1, lower1, upper2);
88 andreas 2187
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2188
	sprintf(hv0, "Lower2=%d\nUpper3=%d\nLower3=%d\nTimer1=00:00:00.0\n",
314 andreas 2189
	        lower2, upper3, lower3);
88 andreas 2190
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2191
	strcpy(hv0, "Timer2=00:00:00.0\nTimer3=00:00:00.0\nActiveLimit=0\n");
2192
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2193
	sprintf(hv0, "MaxHR=%d\nRestHR=%d\nStartDelay=0\nVO2max=%d\nWeight=%d\n\n",
314 andreas 2194
	        MaxHr, restHr, vo2max, weight);
88 andreas 2195
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2196
 
2197
	// Write the intervall times. One block for every lap
2198
	secRange1 = secRange2 = secRange3 = secAbove = secBeyond = 0;
2199
	strcpy(hv0, "[IntTimes]\n");
2200
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2201
	t.setHMS(0, 0, 0);
2202
 
314 andreas 2203
	for(unsigned int i = rn->run->first_lap_index; i < rn->run->last_lap_index; i++)
88 andreas 2204
	{
314 andreas 2205
		alap = ds.getLap(i);
2206
		point = ds.getPoint(alap->start_time);
2207
		oldqt = garmin_dtime(point->time);
2208
		avgHeart = minHeart = maxHeart = aktHeart = 0;
2209
		anz = 0;
2210
		unsigned long lastTime = point->time;
2211
		int totSec = 0;
88 andreas 2212
 
314 andreas 2213
		while(point)
2214
		{
2215
			if(point->time > (alap->start_time + (alap->total_time / 100)))
2216
				break;
88 andreas 2217
 
314 andreas 2218
			if(point->heart_rate > 0)
2219
			{
2220
				avgHeart += point->heart_rate;
2221
				nsec = point->time - lastTime;
2222
				totSec += nsec;
88 andreas 2223
 
314 andreas 2224
				if(minHeart == 0 || minHeart > point->heart_rate)
2225
					minHeart = point->heart_rate;
88 andreas 2226
 
314 andreas 2227
				if(maxHeart < point->heart_rate)
2228
					maxHeart = point->heart_rate;
88 andreas 2229
 
314 andreas 2230
				if(aktHeart == 0 && totSec >= samsec)
2231
					aktHeart = avgHeart / (anz + 1);
88 andreas 2232
 
314 andreas 2233
				if(point->heart_rate < lower1)
2234
					secBeyond += nsec;
2235
				else if(point->heart_rate < lower2)
2236
					secRange1 += nsec;
2237
				else if(point->heart_rate < lower3)
2238
					secRange2 += nsec;
2239
				else if(point->heart_rate < upper3)
2240
					secRange3 += nsec;
2241
				else
2242
					secAbove += nsec;
88 andreas 2243
 
314 andreas 2244
				lastTime = point->time;
2245
				anz++;
2246
			}
88 andreas 2247
 
314 andreas 2248
			point = ds.getPoint(point->time + 1);
2249
		}
88 andreas 2250
 
314 andreas 2251
		t = t.addSecs(alap->total_time / 100);
2252
		str1 = t.toString("hh:mm:ss.z");
166 andreas 2253
 
314 andreas 2254
		if(anz > 0)
2255
			avgHeart = avgHeart / anz;
2256
		else
2257
			avgHeart = 0;
166 andreas 2258
 
314 andreas 2259
		sprintf(hv0, "%s\t %d\t %d\t %d\t %d\n",
2260
		        str1.toAscii().data(), aktHeart, minHeart, avgHeart, maxHeart);
2261
		write(fdfile.handle(), &hv0[0], strlen(hv0));
2262
		strcpy(hv0, "32\t 0\t 0\t 0\t 0\t 0\n");
2263
		write(fdfile.handle(), &hv0[0], strlen(hv0));
2264
		strcpy(hv0, "0\t 0\t 0\t 0\t 0\n");
2265
		write(fdfile.handle(), &hv0[0], strlen(hv0));
2266
		sprintf(hv0, "0\t %d\t 0\t 0\t 0\t 0\n", (int)alap->total_distance);
2267
		write(fdfile.handle(), &hv0[0], strlen(hv0));
2268
		strcpy(hv0, "0\t 0\t 0\t 0\t 0\t 0\n");
2269
		write(fdfile.handle(), &hv0[0], strlen(hv0));
88 andreas 2270
	}
2271
 
2272
	strcpy(hv0, "\n[IntNotes]\n\n[ExtraData]\n\n");
2273
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2274
 
2275
	strcpy(hv0, "[Summary-123]\n");
2276
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
2277
	smp = max_time - secBeyond - secRange1 - secRange2 - secRange3 - secAbove;
245 andreas 2278
	sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
314 andreas 2279
	        max_time, secRange1, secRange2 + secRange3,
2280
	        secAbove + secBeyond, smp);
88 andreas 2281
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 1
2282
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
314 andreas 2283
	        MaxHr, upper1, lower1, restHr);
88 andreas 2284
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
245 andreas 2285
	sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
314 andreas 2286
	        max_time, secRange2, secRange1 + secRange3,
2287
	        secAbove + secBeyond, smp);
88 andreas 2288
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 2
2289
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
314 andreas 2290
	        MaxHr, upper2, lower2, restHr);
88 andreas 2291
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 2
245 andreas 2292
	sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
314 andreas 2293
	        max_time, secRange3, secRange1 + secRange2,
2294
	        secAbove + secBeyond, smp);
88 andreas 2295
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 3
2296
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
314 andreas 2297
	        MaxHr, upper3, lower3, restHr);
88 andreas 2298
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 3
2299
	samples = max_time / samsec;
2300
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
2301
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2302
 
2303
	strcpy(hv0, "[Summary-TH]\n");
2304
	write(fdfile.handle(), &hv0[0], strlen(hv0));
245 andreas 2305
	sprintf(hv0, "%lu\t 0\t %lu\t %d\t %d\t 0\n", max_time, max_time - max_hr - restHr, max_hr, restHr);
88 andreas 2306
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2307
	sprintf(hv0, "%d\t %d\t %d\t %d\n", MaxHr, upper3, lower1, restHr);
2308
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2309
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
2310
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2311
 
2312
	sprintf(hv0, "[HRZones]\n%d\n%d\n%d\n%d\n%d\n%d\n0\n0\n0\n0\n0\n\n",
314 andreas 2313
	        MaxHr, upper3, upper2, upper1, lower1, restHr);
88 andreas 2314
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2315
 
2316
	strcpy(hv0, "[HRData]\n");
2317
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2318
 
2319
	smp = 0;		// average heart rate of 15 seconds
2320
	seconds = 0;
2321
	anz = 0;
2322
	nsec = samsec;
2323
	oldqt = garmin_dtime(lap->start_time);
2324
	qt = 0;
2325
	point = ds.getPoint(lap->start_time);
2326
 
314 andreas 2327
	while(point)
88 andreas 2328
	{
314 andreas 2329
		if(seconds >= nsec)
2330
		{
2331
			if(anz > 0)
2332
			{
2333
				sprintf(hv0, "%d\n", smp / anz);
2334
				write(fdfile.handle(), &hv0[0], strlen(hv0));
2335
			}
88 andreas 2336
 
314 andreas 2337
			if(smp > 0 && seconds >= (nsec + samsec))
2338
			{
2339
				if(anz <= 0)
2340
					anz = 0;
88 andreas 2341
 
314 andreas 2342
				for(int x = nsec; x < seconds; x += samsec)
2343
				{
2344
					sprintf(hv0, "%d\n", smp / anz);
2345
					write(fdfile.handle(), &hv0[0], strlen(hv0));
2346
					nsec += samsec;
2347
				}
2348
			}
88 andreas 2349
 
314 andreas 2350
			anz = 0;
2351
			smp = 0;
2352
			nsec += samsec;
2353
		}
88 andreas 2354
 
314 andreas 2355
		qt = garmin_dtime(point->time);
2356
		seconds += oldqt->secsTo(*qt);
88 andreas 2357
 
314 andreas 2358
		if(point->heart_rate > 0)
2359
		{
2360
			smp += point->heart_rate;
2361
			anz++;
2362
		}
2363
 
2364
		delete oldqt;
2365
		oldqt = qt;
2366
		point = ds.getPoint(point->time + 1);
88 andreas 2367
	}
2368
 
2369
	fdfile.close();
2370
	KMessageBox::information(this, i18n("File successfully written."));
2371
}
2372
 
2373
void sportwatcherWidget::extrasSettings()
2374
{
314 andreas 2375
	settingsWidget *dlg = new settingsWidget(this);
88 andreas 2376
 
314 andreas 2377
	if(dlg->exec() == QDialog::Accepted)
88 andreas 2378
	{
314 andreas 2379
		KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
2380
		KConfigGroup ic(&cfg, "SportWatcher");
2381
		lower1 = ic.readEntry("lower1", 0);
2382
		lower2 = ic.readEntry("lower2", 0);
2383
		lower3 = ic.readEntry("lower3", 0);
2384
		upper1 = ic.readEntry("upper1", 0);
2385
		upper2 = ic.readEntry("upper2", 0);
2386
		upper3 = ic.readEntry("upper3", 0);
2387
		MaxHr = ic.readEntry("maxHr", 0);
2388
		restHr = ic.readEntry("restHr", 0);
2389
		vo2max = ic.readEntry("vo2max", 0);
2390
		weight = ic.readEntry("weight", 0);
2391
		sampleTime = ic.readEntry("seconds", 1);
2392
		Serial = ic.readEntry("Serial", false);
2393
		Contour = ic.readEntry("Contour", false);
2394
		Device = ic.readEntry("Device", QString("/dev/ttyUSB0"));
2395
		Forerunner = ic.readEntry("Forerunner", false);
2396
		Data = ic.readEntry("Data", QString("/"));
2397
		HRM = ic.readEntry("HRM", QString("/"));
2398
		MAP = ic.readEntry("MAP", QString("/"));
2399
		Units = ic.readEntry("Units", 0);
2400
		MapType = ic.readEntry("MapType", 0);
88 andreas 2401
	}
2402
 
2403
	delete dlg;
152 andreas 2404
}
151 andreas 2405
 
152 andreas 2406
void sportwatcherWidget::extrasWMSSettings()
2407
{
232 andreas 2408
#if defined HAVE_GDAL
314 andreas 2409
 
2410
	if(MapType == MPT_BMP || MapType == MPT_GIF || MapType == MPT_PNG ||
2411
	                  MapType == MPT_TIF)
158 andreas 2412
	{
314 andreas 2413
		coordinatesWidget *idlg = new coordinatesWidget(this);
2414
		idlg->exec();
2415
		delete idlg;
2416
		return;
158 andreas 2417
	}
274 andreas 2418
 
314 andreas 2419
	if(MapType == MPT_WMS)
158 andreas 2420
	{
314 andreas 2421
		wmsbase *dlg = new wmsbase(this);
2422
		dlg->exec();
2423
		delete dlg;
274 andreas 2424
	}
314 andreas 2425
 
280 andreas 2426
#if defined HAVE_MAPNIK
314 andreas 2427
 
2428
	if(MapType == MPT_SHP || MapType == MPT_OSM)
274 andreas 2429
	{
314 andreas 2430
		shapeWidget *dlg = new shapeWidget(this);
276 andreas 2431
 
314 andreas 2432
		if(MapType == MPT_SHP)
2433
			dlg->setMapType(shapeWidget::MAP_SHAPE);
2434
		else
2435
			dlg->setMapType(shapeWidget::MAP_OSM);
276 andreas 2436
 
314 andreas 2437
		dlg->exec();
2438
		delete dlg;
274 andreas 2439
	}
314 andreas 2440
 
280 andreas 2441
#else
2442
	KMessageBox::detailedSorry(this,
314 andreas 2443
	                           i18n("This function was disabled at compile time because of missing Mapnik!"),
2444
	                           i18n("SportWatcher needs Mapnik 0.6 or newer, to enable this function.\n") +
2445
	                           i18n("If you like this to be working, install Mapnik and recompile the source."));
280 andreas 2446
#endif
314 andreas 2447
 
2448
	if(MapType != MPT_WMS && MapType != MPT_SHP && MapType != MPT_OSM)
274 andreas 2449
	{
314 andreas 2450
		KMessageBox::detailedSorry(this,
2451
		                           i18n("You have not choosen a WMS tag file or shape file directory!"),
2452
		                           i18n("This dialog is especialy to set map specific parameters. ") +
2453
		                           i18n("Therefore this dialog is temporary disabled. It will be ") +
2454
		                           i18n("available again, as soon as you choose \"WMS server\" or ") +
2455
		                           i18n("Shape file as your map type."));
2456
		return;
158 andreas 2457
	}
314 andreas 2458
 
156 andreas 2459
#else
2460
	KMessageBox::detailedSorry(this,
314 andreas 2461
	                           i18n("This function was disabled at compile time because of missing GDAL v1.x.x!"),
2462
	                           i18n("Sportwatcher needs GDAL v1.5.x or newer, to enable this function.\n") +
2463
	                           i18n("If you like this to be working, install GDAL and recompile the source!"));
156 andreas 2464
#endif
88 andreas 2465
}
2466
 
2467
/*
2468
 * Functions to fill in the boxes of the main mask.
2469
 */
2470
void sportwatcherWidget::showLaps()
2471
{
314 andreas 2472
	QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
2473
	QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
2474
	QString qs_totdist;
2475
	QDateTime dt;
2476
	QTime t, st;
2477
	QDateTime *qt;
2478
	LAP *lap;
2479
	POINT *point;
2480
	RUN_NODE *rakt, *rn;
2481
	int laps, i, anz, men, cad;
2482
	double alt_asc, alt_dsc, sum_asc, sum_dsc, old_asc, old_dsc;
2483
	double totdist;
2484
	bool pause;
88 andreas 2485
 
314 andreas 2486
	if(!DIRTY)
2487
		return;
246 andreas 2488
 
314 andreas 2489
	if(!gmn)
2490
		return;
88 andreas 2491
 
314 andreas 2492
	if(gmn->type == data_Dnil)
88 andreas 2493
	{
314 andreas 2494
		KMessageBox::error(this, i18n("No data found!"));
2495
		return;
88 andreas 2496
	}
2497
 
314 andreas 2498
	if(gmn->type != data_Dlist)      /* List of data */
88 andreas 2499
	{
314 andreas 2500
		KMessageBox::error(this, i18n("Found unexpected data type %1!").arg(gmn->type));
2501
		return;
88 andreas 2502
	}
2503
 
2504
	ds.destroy();
221 andreas 2505
	min_hr = max_hr = avg_hr = 0;
88 andreas 2506
	min_height = max_height = 0.0;
218 andreas 2507
	min_speed = max_speed = 0.0;
248 andreas 2508
	totdist = 0.0;
2509
	// Tab Summary
245 andreas 2510
	ui_sportwatcherWidgetBase.liLaps->clear();
2511
	ui_sportwatcherWidgetBase.liLaps->setAllColumnsShowFocus(true);
248 andreas 2512
	// Tab Laps
2513
	ui_sportwatcherWidgetBase.twLaps->clear();
88 andreas 2514
	ds.garmin_print_data(gmn);
245 andreas 2515
 
314 andreas 2516
	if(!(rn = ds.getRunNode()))
2517
		return;
245 andreas 2518
 
88 andreas 2519
	rakt = rn;
248 andreas 2520
	// Tab Summary
245 andreas 2521
	ui_sportwatcherWidgetBase.liLaps->setRootIsDecorated(true);
88 andreas 2522
 
314 andreas 2523
	for(i = 1; i < 12; i++)
2524
		ui_sportwatcherWidgetBase.liLaps->setColumnAlignment(i, Qt::AlignRight);
2525
 
248 andreas 2526
	// Tab Laps
2527
	ui_sportwatcherWidgetBase.edTotalDistance->clear();
2528
	ui_sportwatcherWidgetBase.edTotalTime->clear();
2529
	ui_sportwatcherWidgetBase.edAvgSpeed->clear();
2530
	ui_sportwatcherWidgetBase.edTotalHeight->clear();
2531
	ui_sportwatcherWidgetBase.edAvgHR->clear();
2532
	ui_sportwatcherWidgetBase.edLapNumber->clear();
2533
 
88 andreas 2534
	qs_name = qs_distance = qs_etime = qs_avgpace = qs_avgspeed = qs_maxspeed = QString("");
2535
	qs_calories = qs_avghr = qs_maxhr = qs_avgcadence = qs_ascent = qs_descent = QString("");
2536
	men = 0;
149 andreas 2537
	cad = 0;
88 andreas 2538
 
249 andreas 2539
	// The main loop.
2540
	// If a supported run type is detected, it will be processed.
314 andreas 2541
	while(rakt)
88 andreas 2542
	{
314 andreas 2543
		// Check for a supported run type
2544
		if(rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
2545
		                  rakt->run->type == data_D1010)
2546
		{
2547
			int cal, ahr, mhr;
2548
			double distance, speed, mspeed;
2549
			QDate dat;
88 andreas 2550
 
314 andreas 2551
			// Set the name depending on the sport type
2552
			// This is used on the tab "Summary"
2553
			switch(rakt->run->sport_type)
2554
			{
2555
				case D1000_running: qs_name = i18n("Running: "); break;
2556
				case D1000_biking:  qs_name = i18n("Biking: "); break;
2557
				case D1000_other:   qs_name = i18n("Other: "); break;
2558
				default:
2559
					qs_name = i18n("Unknown: ");
2560
			}
88 andreas 2561
 
314 andreas 2562
			if(!(lap = ds.getLap(rakt->run->first_lap_index)))
2563
				return;
245 andreas 2564
 
314 andreas 2565
			qt = garmin_dtime(lap->start_time);
2566
			StartTime = *qt;
2567
			st = qt->time();
2568
			dat = qt->date();
2569
			delete qt;
2570
			qt = 0;
215 andreas 2571
 
314 andreas 2572
			// Find the last track;
2573
			//    It is possible to delete laps directly on the watch,
2574
			//    so we can't be sure the last lap is really the last one.
2575
			//    Tracks are not deleted and the last track contains the
2576
			//    summuraries we need.
2577
			if(!(point = ds.getLastPoint()))
2578
			{
2579
				KMessageBox::error(this, i18n("Error getting the last messure point!"));
2580
				return;
2581
			}
88 andreas 2582
 
314 andreas 2583
			qt = garmin_dtime(point->time);
2584
			t = qt->time();
2585
			t.setHMS(0, 0, 0);
2586
			t = t.addSecs(ds.getTotalTime());
2587
			qt->setDate(dat);
2588
			qt->setTime(t);
2589
			qs_name.append(kl->formatDate(dat, KLocale::ShortDate));
2590
			qs_name.append(" ");
2591
			qs_name.append(kl->formatTime(st, true));
2592
			max_time = ds.getTotalTime();
2593
			qs_etime = QString(qt->toString("hh:mm:ss.zzz"));
88 andreas 2594
 
314 andreas 2595
			distance = 0.0;
2596
			cal = 0;
2597
			mspeed = 0;
2598
			ahr = mhr = 0;
2599
			anz = 0;
2600
			cad = 0;
2601
			sum_asc = sum_dsc = old_asc = old_dsc = 0;
88 andreas 2602
 
314 andreas 2603
			// Find out the total distance, calories, maximum speed,
2604
			// maximum heart rate and the average heart rate. Get this
2605
			// values from the lap summary the watch made.
2606
			for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
2607
			{
2608
				if((lap = ds.getLap(i)) == NULL)
2609
					continue;
149 andreas 2610
 
314 andreas 2611
				distance += lap->total_distance;
2612
				cal += lap->calories;
149 andreas 2613
 
314 andreas 2614
				if(lap->avg_cadence != 0xff)
2615
					cad += lap->avg_cadence;
88 andreas 2616
 
314 andreas 2617
				ahr += lap->avg_heart_rate;
2618
				anz++;
88 andreas 2619
 
314 andreas 2620
				if(lap->max_speed > mspeed)
2621
					mspeed = lap->max_speed;
88 andreas 2622
 
314 andreas 2623
				if(lap->max_heart_rate > mhr)
2624
					mhr = lap->max_heart_rate;
2625
			}
213 andreas 2626
 
314 andreas 2627
			total_distance = distance = ds.getTotalDistance();
149 andreas 2628
 
314 andreas 2629
			if(Units == 1)		// Statute?
2630
				qs_distance.sprintf("%.2f ft", distance / 0.304);
2631
			else
2632
				qs_distance.sprintf("%.2f m", distance);
156 andreas 2633
 
314 andreas 2634
			if(distance > 0)
2635
			{
2636
				QTime tt = qt->time();
2637
				long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;
156 andreas 2638
 
314 andreas 2639
				if(Units == 0)
2640
					secs = secs * (1000.0 / distance * 100.0);
2641
				else
2642
					secs = secs * (1609.344 / distance * 100.0);
156 andreas 2643
 
314 andreas 2644
				int h = secs / 3600;
2645
				int m = (secs - (h * 3600)) / 60;
2646
				int s = secs - ((h * 3600) + (m * 60));
2647
				t = QTime(h, m, s, 0);
2648
				qs_avgpace = QString("  ") + kl->formatTime(t, true);
88 andreas 2649
 
314 andreas 2650
				if(Units == 0)
2651
					qs_avgpace.append(QString(" /km"));
2652
				else
2653
					qs_avgpace.append(QString(" /mi"));
2654
			}
149 andreas 2655
 
314 andreas 2656
			if(Units == 1)		// Statute?
2657
				speed = distance / ds.getTotalTime() * 3.6 / 1.609344;
2658
			else
2659
				speed = distance / ds.getTotalTime() * 3.6;
88 andreas 2660
 
314 andreas 2661
			qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
2662
			qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
2663
			qs_calories.sprintf("%d", cal);
2664
			qs_avghr.sprintf("%d bpm", ahr / anz);
2665
			qs_maxhr.sprintf("%d bpm", mhr);
149 andreas 2666
 
314 andreas 2667
			if(cad > 0)
2668
				qs_avgcadence.sprintf("%d", cad / anz);
88 andreas 2669
 
314 andreas 2670
			// Add the summary line columns to the tab "Summary"
2671
			K3ListViewItem *element = new K3ListViewItem(ui_sportwatcherWidgetBase.liLaps,
2672
			                  qs_name, kl->formatNumber(qs_distance, false),
2673
			                  qs_etime, qs_avgpace, kl->formatNumber(qs_avgspeed, false),
2674
			                  kl->formatNumber(qs_maxspeed, false), qs_calories, qs_avghr);
2675
			element->setText(8, qs_maxhr);
2676
			element->setText(9, qs_avgcadence);
2677
			element->setText(10, kl->formatNumber(qs_ascent, false));
2678
			element->setText(11, kl->formatNumber(qs_descent, false));
2679
			element->sortChildItems(0, false);
2680
			element->setOpen(true);
2681
			element->setPixmap(0, KIcon(QString("activity")).pixmap(16));
2682
			ui_sportwatcherWidgetBase.liLaps->insertItem(element);
2683
			// Add some of the summaries to the fields on the tab "Lap details"
2684
			ui_sportwatcherWidgetBase.edTotalDistance->setAlignment(Qt::AlignRight);
2685
			ui_sportwatcherWidgetBase.edTotalDistance->insert(kl->formatNumber(qs_distance, false));
2686
			ui_sportwatcherWidgetBase.edTotalTime->setAlignment(Qt::AlignRight);
2687
			ui_sportwatcherWidgetBase.edTotalTime->insert(qs_etime);
2688
			ui_sportwatcherWidgetBase.edAvgSpeed->setAlignment(Qt::AlignRight);
2689
			ui_sportwatcherWidgetBase.edAvgSpeed->insert(kl->formatNumber(qs_avgspeed, false));
2690
			ui_sportwatcherWidgetBase.edTotalHeight->setAlignment(Qt::AlignRight);
2691
			ui_sportwatcherWidgetBase.edTotalHeight->insert(kl->formatNumber(qs_ascent, false));
2692
			ui_sportwatcherWidgetBase.edAvgHR->setAlignment(Qt::AlignRight);
2693
			ui_sportwatcherWidgetBase.edAvgHR->insert(qs_avghr);
2694
			delete qt;
2695
			/* Get the laps. */
2696
			laps = 1;
149 andreas 2697
 
314 andreas 2698
			for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
2699
			{
2700
				double spd;
2701
				char *un;
88 andreas 2702
 
314 andreas 2703
				if((lap = ds.getLap(i)) == NULL)
2704
					continue;
149 andreas 2705
 
314 andreas 2706
				qt = garmin_dtime(lap->start_time);
2707
				qs_name.sprintf("Lap %03d - ", laps);
2708
				qs_name.append(kl->formatTime(qt->time(), true));
2709
				qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
2710
				totdist += (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance;
2711
				qs_totdist.sprintf("%2.f %s", totdist, (Units == 1) ? "ft" : "m");
2712
				t = QTime(0, 0, 0, 0);
2713
				t = t.addMSecs(lap->total_time * 10);
2714
				qs_etime = t.toString("hh:mm:ss.zzz");
2715
				spd = lap->total_distance / (lap->total_time / 100.0);
2716
				delete qt;
2717
				qt = 0;
149 andreas 2718
 
314 andreas 2719
				if(Units == 0)
2720
				{
2721
					un = (char *)"km/h";
2722
					spd *= 3.6;
2723
				}
2724
				else
2725
				{
2726
					spd *= 3.6 / 1.609344;
2727
					un = (char *)"mph";
2728
				}
88 andreas 2729
 
314 andreas 2730
				qs_avgspeed.sprintf("%.2f %s", spd, un);
2731
				qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? lap->max_speed * 3.6 / 1.609344 : lap->max_speed * 3.6, un);
2732
				qs_calories.sprintf("%d", lap->calories);
156 andreas 2733
 
314 andreas 2734
				if(lap->total_distance > 0 && lap->total_time != 0)
2735
				{
2736
					double fact;
156 andreas 2737
 
314 andreas 2738
					if(Units == 0)
2739
						fact = 1000.0;		// 1 km
2740
					else
2741
						fact = 1609.344;		// 1 mile in meters
156 andreas 2742
 
314 andreas 2743
					long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
2744
					int h = secs / 3600;
2745
					int m = (secs - (h * 3600)) / 60;
2746
					int s = secs - ((h * 3600) + (m * 60));
2747
					t = QTime(h, m, s, 0);
2748
					qs_avgpace = kl->formatTime(t, true);
88 andreas 2749
 
314 andreas 2750
					if(Units == 0)
2751
						qs_avgpace.append(QString(" /km"));
2752
					else
2753
						qs_avgpace.append(QString(" /mi"));
2754
				}
88 andreas 2755
 
314 andreas 2756
				qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
2757
				qs_maxhr.sprintf("%d bpm", lap->max_heart_rate);
88 andreas 2758
 
314 andreas 2759
				anz = 0;
2760
				alt_asc = alt_dsc = 0;
2761
				// Add a new detail line to the tab "Lap details"
2762
				QTreeWidgetItem * trdetail = new QTreeWidgetItem(ui_sportwatcherWidgetBase.twLaps);
149 andreas 2763
 
314 andreas 2764
				if((point = ds.getPoint(lap->start_time)) != 0)
2765
				{
2766
					if(point->alt < 20000)
2767
					{
2768
						alt_dsc = alt_asc = point->alt;
149 andreas 2769
 
314 andreas 2770
						if(old_asc == 0)
2771
							old_asc = alt_asc;
88 andreas 2772
 
314 andreas 2773
						if(old_dsc == 0)
2774
							old_dsc = alt_dsc;
2775
					}
2776
					else
2777
						alt_dsc = alt_asc = 0;
218 andreas 2778
 
314 andreas 2779
					POINT *oldPoint = 0;
2780
					double sc, dist, speed;
2781
					unsigned long t1, t2;
2782
					t1 = t2 = 0;
2783
					pause = false;
2784
					bool ignore = false;
88 andreas 2785
 
314 andreas 2786
					while(point)
2787
					{
2788
						if(point->time > (lap->start_time + (lap->total_time / 100)))
2789
							break;
249 andreas 2790
 
314 andreas 2791
						QTreeWidgetItem *child = new QTreeWidgetItem(trdetail);
2792
						qt = garmin_dtime(point->time);
2793
						child->setText(0, kl->formatTime(qt->time(), true));
2794
						child->setTextAlignment(0, Qt::AlignRight);
2795
						child->setText(8, QString("%1 %2").arg(kl->formatNumber((double)point->heart_rate, 0)).arg(" bpm"));
2796
						child->setTextAlignment(8, Qt::AlignRight);
249 andreas 2797
 
314 andreas 2798
						if(point->cadence < 0xff)
2799
						{
2800
							child->setText(10, kl->formatNumber((double)point->cadence, 0));
2801
							child->setTextAlignment(10, Qt::AlignRight);
2802
						}
249 andreas 2803
 
314 andreas 2804
						if(point->alt < 20000)
2805
						{
2806
							double alt = (Units == 0) ? (double)point->alt : (double)point->alt / 0.304;
249 andreas 2807
 
314 andreas 2808
							child->setText(11, QString("%1 %2").arg(kl->formatNumber(alt, 2)).arg((Units == 0) ? QString(" m") : QString(" ft")));
2809
							child->setTextAlignment(11, Qt::AlignRight);
2810
						}
218 andreas 2811
 
314 andreas 2812
						if(!oldPoint)
2813
							oldPoint = point;
88 andreas 2814
 
314 andreas 2815
						if(point->alt > alt_asc && point->alt < 20000)
2816
						{
2817
							alt_asc = point->alt;
88 andreas 2818
 
314 andreas 2819
							if(alt_dsc == 0)
2820
								alt_dsc = point->alt;
2821
						}
88 andreas 2822
 
314 andreas 2823
						if(point->alt < alt_dsc)
2824
							alt_dsc = point->alt;
88 andreas 2825
 
314 andreas 2826
						// save the min and max values. We need this information to
2827
						// build the graphics.
2828
						if(point->heart_rate > max_hr && point->heart_rate < 250)
2829
							max_hr = point->heart_rate;
88 andreas 2830
 
314 andreas 2831
						if((min_hr == 0 && point->heart_rate > 0 && point->heart_rate < 250)
2832
						                  || (point->heart_rate > 0 && point->heart_rate < min_hr))
2833
							min_hr = point->heart_rate;
88 andreas 2834
 
314 andreas 2835
						if(point->alt < 20000 && max_height < point->alt)
2836
							max_height = point->alt;
88 andreas 2837
 
314 andreas 2838
						if(point->alt < 20000 && (min_height == 0.0 || min_height > point->alt))
2839
							min_height = point->alt;
218 andreas 2840
 
314 andreas 2841
						// Calculate speed of current track
2842
						if(!pause && point->distance > 1.0e10)
2843
						{
2844
							t1 = point->time;
2845
							pause = true;
2846
							ignore = true;
2847
						}
2848
						else if(pause)
2849
						{
2850
							t2 = point->time;
2851
							pause = false;
2852
							point = ds.getPoint(point->time + 1);
2853
							continue;
2854
						}
218 andreas 2855
 
314 andreas 2856
						if(!ignore && !pause)
2857
						{
2858
							sc = point->time - oldPoint->time;
2859
							dist = point->distance - oldPoint->distance;
249 andreas 2860
 
314 andreas 2861
							child->setText(1, QString("%1 %2").arg(kl->formatNumber((Units == 0) ? (double)dist : (double)dist / 0.304, 2)).arg((Units == 0) ? QString(" m") : QString(" ft")));
2862
							child->setTextAlignment(1, Qt::AlignRight);
218 andreas 2863
 
314 andreas 2864
							if(t2 > t1)
2865
								sc -= t2 - t1;
223 andreas 2866
 
314 andreas 2867
							if(sc > 0.0)
2868
							{
2869
								speed = (dist / sc) * 3.6;
218 andreas 2870
 
314 andreas 2871
								if(speed > lap->max_speed * 3.6)
2872
									speed = lap->max_speed * 3.6;
2873
							}
2874
							else
2875
								speed = 0.0;
218 andreas 2876
 
314 andreas 2877
							if(Units == 1)
2878
								speed /= 1.609344;
249 andreas 2879
 
314 andreas 2880
							child->setText(5, QString("%1 %2").arg(kl->formatNumber(speed, 2)).arg((Units == 0) ? QString(" Km/h") : QString(" mi/h")));
2881
							child->setTextAlignment(5, Qt::AlignRight);
222 andreas 2882
 
314 andreas 2883
							if(speed > 0.0 && speed < 400.0 && max_speed < speed)
2884
								max_speed = speed;
222 andreas 2885
 
314 andreas 2886
							if(speed > 0.0 && (min_speed == 0.0 || min_speed > speed))
2887
								min_speed = speed;
222 andreas 2888
 
314 andreas 2889
							oldPoint = point;
2890
						}
222 andreas 2891
 
314 andreas 2892
						if(!pause && ignore)
2893
							ignore = false;
88 andreas 2894
 
314 andreas 2895
						if(point->heart_rate > 0 && point->heart_rate < 250)
2896
						{
2897
							avg_hr += point->heart_rate;
2898
							men++;
2899
						}
88 andreas 2900
 
314 andreas 2901
						point = ds.getPoint(point->time + 1);
2902
					}
149 andreas 2903
 
314 andreas 2904
					if(old_asc < alt_asc)
2905
						sum_asc += (alt_asc - old_asc);
149 andreas 2906
 
314 andreas 2907
					if(old_dsc > alt_dsc)
2908
						sum_dsc += (old_dsc - alt_dsc);
88 andreas 2909
 
314 andreas 2910
					old_asc = alt_asc;
2911
					old_dsc = alt_dsc;
2912
					qs_ascent.sprintf("%.2f %s", (Units == 1) ? (alt_asc / 0.304) : alt_asc, (Units == 1) ? "ft" : "m");
2913
					qs_descent.sprintf("%.2f %s", (Units == 1) ? (alt_dsc / 0.304) : alt_dsc, (Units == 1) ? "ft" : "m");
2914
				}
232 andreas 2915
 
314 andreas 2916
				if(lap->avg_cadence != 0xff)
2917
					qs_avgcadence.sprintf("%d", lap->avg_cadence);
232 andreas 2918
 
314 andreas 2919
				// Add a new detail line to the tab "Summary"
2920
				K3ListViewItem *edetail = new K3ListViewItem(element, qs_name,
2921
				                  kl->formatNumber(qs_distance, false),
2922
				                  qs_etime, qs_avgpace, kl->formatNumber(qs_avgspeed, false),
2923
				                  kl->formatNumber(qs_maxspeed, false), qs_calories, qs_avghr);
2924
				edetail->setText(8, qs_maxhr);
2925
				edetail->setText(9, qs_avgcadence);
2926
				edetail->setText(10, kl->formatNumber(qs_ascent, false));
2927
				edetail->setText(11, kl->formatNumber(qs_descent, false));
2928
				edetail->setPixmap(0, KIcon(QString("history")).pixmap(16));
2929
				QPixmap qpx = KIcon(QString("other")).pixmap(16);
232 andreas 2930
 
314 andreas 2931
				trdetail->setText(0, qs_etime);
2932
				trdetail->setTextAlignment(0, Qt::AlignRight);
2933
				trdetail->setText(1, kl->formatNumber(qs_distance));
2934
				trdetail->setTextAlignment(1, Qt::AlignRight);
2935
				trdetail->setText(2, kl->formatNumber(qs_totdist));
2936
				trdetail->setTextAlignment(2, Qt::AlignRight);
2937
				trdetail->setText(4, qs_avgpace);
2938
				trdetail->setTextAlignment(4, Qt::AlignRight);
2939
				trdetail->setText(5, kl->formatNumber(qs_avgspeed, false));
2940
				trdetail->setTextAlignment(5, Qt::AlignRight);
2941
				trdetail->setText(6, kl->formatNumber(qs_maxspeed, false));
2942
				trdetail->setTextAlignment(6, Qt::AlignRight);
2943
				trdetail->setText(7, qs_calories);
2944
				trdetail->setTextAlignment(7, Qt::AlignRight);
2945
				trdetail->setText(8, qs_avghr);
2946
				trdetail->setTextAlignment(8, Qt::AlignRight);
2947
				trdetail->setText(9, qs_maxhr);
2948
				trdetail->setTextAlignment(9, Qt::AlignRight);
2949
				trdetail->setText(10, qs_avgcadence);
2950
				trdetail->setTextAlignment(10, Qt::AlignRight);
2951
				trdetail->setText(11, kl->formatNumber(qs_ascent, false));
2952
				trdetail->setTextAlignment(11, Qt::AlignRight);
128 andreas 2953
 
314 andreas 2954
				switch(rakt->run->sport_type)
2955
				{
2956
					case D1000_running:
2957
						edetail->setPixmap(0, KIcon(QString("spw-running")).pixmap(16));
2958
						break;
149 andreas 2959
 
314 andreas 2960
					case D1000_biking:
2961
						edetail->setPixmap(0, KIcon(QString("bike")).pixmap(16));
2962
						break;
88 andreas 2963
 
314 andreas 2964
					case D1000_other:
2965
						edetail->setPixmap(0, qpx);
2966
						break;
2967
 
2968
					default:
2969
						edetail->setPixmap(0, qpx);
2970
				}
2971
 
2972
				ui_sportwatcherWidgetBase.liLaps->clearSelection();
2973
				element->insertItem(edetail);
2974
				delete qt;
2975
				laps++;
2976
			}
2977
 
2978
			qs_ascent.sprintf("%.2f %s", (Units == 1) ? sum_asc / 0.304 : sum_asc, (Units == 1) ? "ft" : "m");
2979
			qs_descent.sprintf("%.2f %s", (Units == 1) ? sum_dsc / 0.304 : sum_dsc, (Units == 1) ? "ft" : "m");
2980
			element->setText(10, qs_ascent);
2981
			element->setText(11, qs_descent);
2982
			qs_ascent.sprintf("%s %s", (Units == 1) ? kl->formatNumber(ds.getAscend() / 0.304, 2).toAscii().data() : kl->formatNumber(ds.getAscend(), 2).toAscii().data(), (Units == 1) ? "ft" : "m");
2983
			ui_sportwatcherWidgetBase.edTotalHeight->clear();
2984
			ui_sportwatcherWidgetBase.edTotalHeight->insert(qs_ascent);
2985
			ui_sportwatcherWidgetBase.edLapNumber->setAlignment(Qt::AlignRight);
2986
			ui_sportwatcherWidgetBase.edLapNumber->insert(kl->formatNumber((double)laps, 0));
2987
		}
2988
 
2989
		rakt = rakt->next;
88 andreas 2990
	}
2991
 
314 andreas 2992
	if(men > 0)
2993
		avg_hr /= men;
221 andreas 2994
	else
314 andreas 2995
		min_hr = max_hr = avg_hr = 0;
88 andreas 2996
}
2997
 
100 andreas 2998
void sportwatcherWidget::showTrack()
2999
{
132 andreas 3000
	showTrack(0, QRect(0, 0, 0, 0), 0);
104 andreas 3001
}
3002
 
3003
void sportwatcherWidget::showTrack(int zoom)
3004
{
132 andreas 3005
	showTrack(zoom, mapPan, mapLap);
3006
}
3007
 
3008
void sportwatcherWidget::showTrack(int zoom, const QRect &pan, LAP *lap)
3009
{
314 andreas 3010
	int width, height;
3011
	double x1, y1, x2, y2;
3012
	int a, top, left, panX, panY;
3013
	uint32 i;
3014
	double coordW, coordH, tick;
3015
	double meterW, dist, fact;
3016
	QPainter paint;
3017
	posn_type posNW, posSE, posLXY, posRXY;
3018
	POINT *point;
3019
	bool Fgeo = false;
3020
	bool Data = false;
232 andreas 3021
#if defined HAVE_GDAL
314 andreas 3022
	QString fName = MAP;
158 andreas 3023
//double adfGeoTransform[6];
314 andreas 3024
	GDALDataset *poDataset = 0;
3025
	GDALRasterBand *poBand = 0;
3026
	unsigned char *pafScanline = 0;
3027
	unsigned char *pafScanlineRed = 0;
3028
	unsigned char *pafScanlineGreen = 0;
3029
	unsigned char *pafScanlineBlue = 0;
3030
	unsigned char *pafScanlineAlpha = 0;
3031
	int nXSize, nYSize;
3032
	int xOff, yOff;
3033
	double oriLeftLon, oriLeftLat, oriRightLon, oriRightLat;
151 andreas 3034
#endif
100 andreas 3035
 
314 andreas 3036
	if(!DIRTY || curTab == 2 || curTab == 3)
3037
		return;
246 andreas 3038
 
314 andreas 3039
	if(!gmn)
3040
		return;
109 andreas 3041
 
314 andreas 3042
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
154 andreas 3043
 
314 andreas 3044
	if(zoom != zfactor)
3045
		zfactor = zoom;
104 andreas 3046
 
314 andreas 3047
	if(mapLap != lap)
3048
		mapLap = lap;
132 andreas 3049
 
283 andreas 3050
	y2 = x2 = 0;
232 andreas 3051
#if defined HAVE_GDAL
283 andreas 3052
	nXSize = nYSize = 0;
314 andreas 3053
	KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
3054
	KConfigGroup wms(&cfg, "WMS");
232 andreas 3055
	bool square = wms.readEntry("Square", false);
3056
	int CorrX = wms.readEntry("CorrX", 0);
3057
	int CorrY = wms.readEntry("CorrY", 0);
314 andreas 3058
	KConfigGroup ic(&cfg, "ImageCoords");
232 andreas 3059
	oriLeftLon = ic.readEntry("LeftLon", 0.0);
3060
	oriLeftLat = ic.readEntry("LeftLat", 0.0);
3061
	oriRightLon = ic.readEntry("RightLon", 0.0);
3062
	oriRightLat = ic.readEntry("RightLat", 0.0);
3063
//	int isrs = ic.readEntry("SRS", 0);
157 andreas 3064
#endif
314 andreas 3065
 
3066
	if(curTab == 0 && !ActivePrint)
248 andreas 3067
	{
314 andreas 3068
		width = ui_sportwatcherWidgetBase.imgMap->width() - 2;
3069
		height = ui_sportwatcherWidgetBase.imgMap->height();
248 andreas 3070
	}
314 andreas 3071
	else if(ActivePrint)
280 andreas 3072
	{
314 andreas 3073
		width = pmPrMap.width();
3074
		height = pmPrMap.height();
280 andreas 3075
	}
248 andreas 3076
	else
3077
	{
314 andreas 3078
		width = ui_sportwatcherWidgetBase.grMap->width() - 2;
3079
		height = ui_sportwatcherWidgetBase.grMap->height();
248 andreas 3080
	}
314 andreas 3081
 
232 andreas 3082
#if defined HAVE_GDAL
314 andreas 3083
 
3084
	if(MapType == MPT_WMS && square)
3085
		pmMap = QPixmap(width / (int)mFactor * (int)mFactor, height / (int)mFactor * (int)mFactor);
157 andreas 3086
	else
314 andreas 3087
		pmMap = QPixmap(width, height);
3088
 
157 andreas 3089
#else
232 andreas 3090
	pmMap = QPixmap(width, height);
157 andreas 3091
#endif
245 andreas 3092
 
314 andreas 3093
	if(pmMap.isNull())
3094
		return;
3095
 
245 andreas 3096
	// Here we begin do draw something
100 andreas 3097
	paint.begin(&pmMap);
3098
 
132 andreas 3099
	panX = panY = 0;
3100
 
314 andreas 3101
	if(stateHand && mapPan != pan)
132 andreas 3102
	{
314 andreas 3103
		mapPan = pan;
3104
		panX = mapPan.right() - mapPan.left();
3105
		panY = mapPan.bottom() - mapPan.top();
3106
		oldTransX += (double)panX;
3107
		oldTransY += (double)panY;
132 andreas 3108
	}
3109
 
104 andreas 3110
	memset(&posNW, 0, sizeof(posn_type));
3111
	memset(&posSE, 0, sizeof(posn_type));
100 andreas 3112
 
156 andreas 3113
	posSE.lat = 90.0;
3114
	posSE.lon = 180.0;
3115
	posNW.lat = -90.0;
3116
	posNW.lon = -180.0;
100 andreas 3117
 
3118
	/*
3119
	 * Find out the corners of our track (NW, NE, SE, SW)
3120
	 */
314 andreas 3121
	if(mapLap)
3122
		i = mapLap->start_time;
132 andreas 3123
	else
314 andreas 3124
		i = 0;
3125
 
3126
	while((point = ds.getPoint(i)) != 0)
100 andreas 3127
	{
314 andreas 3128
		if(mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
3129
			break;
132 andreas 3130
 
314 andreas 3131
		if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
3132
		{
3133
			i = point->time + 1;
3134
			continue;
3135
		}
100 andreas 3136
 
314 andreas 3137
		if(SEMI2DEG(point->posn.lat) > posNW.lat)
3138
			posNW.lat = SEMI2DEG(point->posn.lat);
100 andreas 3139
 
314 andreas 3140
		if(SEMI2DEG(point->posn.lat) < posSE.lat)
3141
			posSE.lat = SEMI2DEG(point->posn.lat);
100 andreas 3142
 
314 andreas 3143
		if(SEMI2DEG(point->posn.lon) > posNW.lon)
3144
			posNW.lon = SEMI2DEG(point->posn.lon);
100 andreas 3145
 
314 andreas 3146
		if(SEMI2DEG(point->posn.lon) < posSE.lon)
3147
			posSE.lon = SEMI2DEG(point->posn.lon);
100 andreas 3148
 
314 andreas 3149
		i = point->time + 1;
3150
		Data = true;
100 andreas 3151
	}
104 andreas 3152
 
3153
	coordW = (posNW.lon > posSE.lon) ? posNW.lon - posSE.lon : posSE.lon - posNW.lon;
3154
	coordH = (posNW.lat > posSE.lat) ? posNW.lat - posSE.lat : posSE.lat - posNW.lat;
109 andreas 3155
	meterW = ds.earth_distance(posNW.lat, posNW.lon, posNW.lat, posSE.lon);
104 andreas 3156
 
3157
	// define the ticks to translate the GPS coordinates into pixels.
3158
	// The track should be centered and we have to calculate the
3159
	// rectangular within we draw the track.
314 andreas 3160
	if(coordW < coordH)
100 andreas 3161
	{
314 andreas 3162
		tick = (double)width / coordW + (double)zoom;
152 andreas 3163
 
314 andreas 3164
		if((tick * coordH) > height)
3165
			tick = (double)height / coordH + (double)zoom;
100 andreas 3166
	}
3167
	else
3168
	{
314 andreas 3169
		tick = (double)height / coordH + (double)zoom;
152 andreas 3170
 
314 andreas 3171
		if((tick * coordW) > width)
3172
			tick = (double)width / coordW + (double)zoom;
100 andreas 3173
	}
104 andreas 3174
 
156 andreas 3175
	left = width - (width - tick * coordW) / 2;
152 andreas 3176
	top = (height - tick * coordH) / 2;
3177
 
132 andreas 3178
	a = tick * coordW;
156 andreas 3179
 
314 andreas 3180
	if(Units == 0)
3181
		dist = meterW / a;			// Meters
156 andreas 3182
	else
314 andreas 3183
		dist = meterW * 1.609344 / a;	// 1/1000 mile (5.28 feet)
156 andreas 3184
 
232 andreas 3185
#if defined HAVE_GDAL
159 andreas 3186
	geoRect.llat = 0.0;
3187
	geoRect.llon = 0.0;
3188
	geoRect.rlat = 0.0;
3189
	geoRect.rlon = 0.0;
158 andreas 3190
	geoRect.width = width;
3191
	geoRect.height = height;
314 andreas 3192
 
146 andreas 3193
	/*
3194
	 * If we have a map file, we try to read it and if successfull,
3195
	 * we should get a map painted.
154 andreas 3196
	 *
3197
	 * Currently only WMS-Server is supported, allthough GDAL allows
3198
	 * several other formats too.
146 andreas 3199
	 */
314 andreas 3200
	if(!MAP.isEmpty() && Data)
146 andreas 3201
	{
314 andreas 3202
		bool writeTag = true;
3203
		double mtx, mty;
3204
		double vx, vy;
152 andreas 3205
 
314 andreas 3206
		xOff = yOff = 0;
3207
		posRXY.lon = posNW.lon + (width - left + oldTransX) / tick;
3208
		posLXY.lat = posNW.lat + (top + oldTransY) / tick;
3209
		posLXY.lon = posSE.lon - (left - a - oldTransX) / tick;
3210
		posRXY.lat = posSE.lat - (height - top - (tick * coordH) - oldTransY) / tick;
3211
		geoRect.llat = posLXY.lat;
3212
		geoRect.llon = posLXY.lon;
3213
		geoRect.rlat = posRXY.lat;
3214
		geoRect.rlon = posRXY.lon;
3215
		// width and height of map in meters
3216
		mtx = ds.earth_distance(posRXY.lat, posRXY.lon, posRXY.lat, posLXY.lon);
3217
		mty = ds.earth_distance(posRXY.lat, posRXY.lon, posLXY.lat, posRXY.lon);
157 andreas 3218
 
314 andreas 3219
		// factor to correct the map, in case we use a WMS server
3220
		if(MapType == MPT_WMS)
3221
		{
3222
			vx = (posRXY.lon - posLXY.lon) / mtx * CorrX;
3223
			vy = (posRXY.lat - posLXY.lat) / mty * CorrY;
3224
			posRXY.lon += vx;
3225
			posRXY.lat += vy;
3226
			posLXY.lon += vx;
3227
			posLXY.lat += vy;
3228
		}
158 andreas 3229
 
314 andreas 3230
		/*
3231
		 * Write a control file for GDAL, if we use a WMS server.
3232
		 * Warp an image if we use PNG or BMP or GIF.
3233
		 * Warp a region if we use TIFF
3234
		 */
3235
		if(MapType == MPT_WMS)
3236
			writeTag = writeWMSTag(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat, width, height);
158 andreas 3237
 
314 andreas 3238
		if(MapType == MPT_GIF || MapType == MPT_BMP || MapType == MPT_PNG ||
3239
		                  MapType == MPT_SGI || MapType == MPT_TIF)
3240
			writeTag = warpImage(MAP, &fName);
158 andreas 3241
 
314 andreas 3242
		if(writeTag)
3243
		{
3244
			if(MapType != MPT_SHP && (poDataset = (GDALDataset *)GDALOpen(fName.toAscii().constData(), GA_ReadOnly)) != NULL)
3245
			{
3246
				QPixmap bild;
3247
				int nRasterCount = poDataset->GetRasterCount();
3248
				int nXBlock, nYBlock;
3249
				GDALColorTable *pCT, *pCTb, *pCTr, *pCTg, *pCTa;
146 andreas 3250
 
314 andreas 3251
				int      bGotMin, bGotMax;
3252
				int		 tTypeLen; //, tColorEntrys;
3253
				GDALDataType tRasterType;
3254
				double   adfMinMax[2];
151 andreas 3255
 
314 andreas 3256
				pCT = pCTb = pCTr = pCTg = pCTa = 0;
3257
				tTypeLen = 0;
3258
				pafScanlineRed = pafScanlineGreen = pafScanlineBlue = pafScanlineAlpha = 0;
3259
				Fgeo = true;
246 andreas 3260
 
314 andreas 3261
				/*
3262
				 * Read every raster band.
3263
				 *
3264
				 * If we get 3 raster bands, the image is a 24 bit image.
3265
				 * If we get 4 raster bands, the image is probably a 24 bit
3266
				 * image with an alpha channel. Currently the alpha channel
3267
				 * is ignored!
3268
				 * If we have 1 raster band, the image is 8 bit monochrom.
3269
				 * Otherwise the image is undefined and the results are also.
3270
				 */
3271
				for(a = 1; a <= nRasterCount; a++)
3272
				{
3273
					if(!Fgeo)
3274
						break;
245 andreas 3275
 
314 andreas 3276
					if(!(poBand = poDataset->GetRasterBand(a)))
3277
					{
3278
						paint.end();
3279
						return;
3280
					}
151 andreas 3281
 
314 andreas 3282
					poBand->GetBlockSize(&nXBlock, &nYBlock);
3283
					nXSize = poBand->GetXSize();
3284
					nYSize = poBand->GetYSize();
3285
					tRasterType = poBand->GetRasterDataType();
3286
					tTypeLen = GDALGetDataTypeSize(tRasterType) / 8;	// We need Bytes not Bits!
3287
//					tColor = poBand->GetColorInterpretation();
151 andreas 3288
 
314 andreas 3289
					adfMinMax[0] = poBand->GetMinimum(&bGotMin);
3290
					adfMinMax[1] = poBand->GetMaximum(&bGotMax);
151 andreas 3291
 
314 andreas 3292
					if(!(bGotMin && bGotMax))
3293
						GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
151 andreas 3294
 
314 andreas 3295
//					if((pCT = poBand->GetColorTable()) != NULL)
3296
//						tColorEntrys = poBand->GetColorTable()->GetColorEntryCount();
151 andreas 3297
 
314 andreas 3298
					switch(a)
3299
					{
3300
						case 1: pafScanlineRed   = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineRed; pCTr = pCT; break;
3301
						case 2: pafScanlineGreen = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineGreen; pCTg = pCT; break;
3302
						case 3: pafScanlineBlue  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineBlue; pCTb = pCT; break;
3303
						case 4: pafScanlineAlpha  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineAlpha; pCTa = pCT; break;
3304
					}
246 andreas 3305
 
314 andreas 3306
					if(!pafScanline)
3307
					{
3308
						paint.end();
3309
						KMessageBox::error(this, i18n("Not enough memory for a raster operation!"));
3310
						return;
3311
					}
151 andreas 3312
 
314 andreas 3313
					memset(pafScanline, 0, tTypeLen * nXSize * nYSize);
151 andreas 3314
 
314 andreas 3315
					/*
3316
					 * Get the image (from the server) and put the tiles together.
3317
					 *
3318
					 * The function reads only one raster band. This is,
3319
					 * because the function is called for every raster band and
3320
					 * every raster band is stored into a separate array.
3321
					 */
3322
					if(poBand->RasterIO(GF_Read, 0, 0, nXSize, nYSize, pafScanline, nXSize, nYSize, tRasterType, 0, 0) == CE_Failure)
3323
					{
3324
						paint.end();
3325
						KMessageBox::error(this, i18n("Error reading a raster band!"));
3326
						paint.begin(&pmMap);
3327
						Fgeo = false;
3328
						break;
3329
					}
3330
					else
3331
						Fgeo = true;
3332
				}
151 andreas 3333
 
314 andreas 3334
				/*
3335
				 * Only if Fgeo is TRUE, we've read successfully all raster
3336
				 * bands. Now we have to put the bands together to get
3337
				 * an image.
3338
				 */
3339
				if(Fgeo)
3340
				{
3341
					unsigned char *pCombinedBytes = new unsigned char[(tTypeLen * nXSize * nYSize * nRasterCount)];
3342
					unsigned char *ptr_dest, *ptr_src;
3343
					int j;
245 andreas 3344
 
314 andreas 3345
					ptr_dest = ptr_src = 0;
152 andreas 3346
 
314 andreas 3347
					/*
3348
					 * We need two nested loops to set the pixels in the wanted
3349
					 * order.
3350
					 */
3351
					for(a = 0, j = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount, j++)
3352
					{
3353
						int k = a;
152 andreas 3354
 
314 andreas 3355
						for(int m = nRasterCount - 1; m >= 0; m--, k++)
3356
						{
3357
							unsigned char *pBytes = 0;
152 andreas 3358
 
314 andreas 3359
							switch(m)
3360
							{
3361
								case 3: pBytes = pafScanlineAlpha; pCT = pCTa; break;
3362
								case 2: pBytes = pafScanlineBlue; pCT = pCTb; break;
3363
								case 1: pBytes = pafScanlineGreen; pCT = pCTg; break;
3364
								default: pBytes = pafScanlineRed; pCT = pCTr;
3365
							}
152 andreas 3366
 
314 andreas 3367
							ptr_dest = pCombinedBytes + k;
3368
							unsigned char b = pBytes[j];
152 andreas 3369
 
314 andreas 3370
							/*
3371
							 * If we have a color table, the pixels are pointers
3372
							 * to the color table. We need to convert them into
3373
							 * 24 bit pixels plus an optional alpha channel.
3374
							 */
3375
							if(pCT != NULL)
3376
							{
3377
								GDALColorEntry ce;
3378
								unsigned int c = (unsigned int)b;
3379
								c = pCT->GetColorEntryAsRGB(c, &ce);
152 andreas 3380
 
314 andreas 3381
								if(m == 0) c = ce.c1;
152 andreas 3382
 
314 andreas 3383
								if(m == 1) c = ce.c2;
152 andreas 3384
 
314 andreas 3385
								if(m == 2) c = ce.c3;
152 andreas 3386
 
314 andreas 3387
								if(m == 3) c = ce.c4;
154 andreas 3388
 
314 andreas 3389
								b = (unsigned char)c;
3390
							}
158 andreas 3391
 
314 andreas 3392
							ptr_src = &b;
3393
							memcpy(ptr_dest, ptr_src, 1);
3394
						}
3395
					}
152 andreas 3396
 
314 andreas 3397
					x1 = y1 = 0;
152 andreas 3398
 
314 andreas 3399
					/*
3400
					 * The following loop is QT specific! It sets the pixels
3401
					 * of the raw image, pixel by pixel. This may be slow, but
3402
					 * everything else didn't work :-(
3403
					 *
3404
					 * FIXME: We need a more effective routine to put the
3405
					 *        raw image into QT's "painter" class.
3406
					 */
3407
					for(a = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount)
3408
					{
3409
						if(x1 < width && y1 < height)
3410
						{
3411
							if(nRasterCount == 3)
3412
								paint.setPen(QPen(QColor((int)pCombinedBytes[a + 2], (int)pCombinedBytes[a + 1], (int)pCombinedBytes[a]), Qt::SolidLine));
3413
							else if(nRasterCount > 3)
3414
								paint.setPen(QPen(QColor(qRgba((int)pCombinedBytes[a + 3], (int)pCombinedBytes[a + 2], (int)pCombinedBytes[a + 1], (int)pCombinedBytes[a])), Qt::SolidLine));
3415
							else if(nRasterCount == 2)
3416
								paint.setPen(QPen(QColor((int)pCombinedBytes[a + 1], (int)pCombinedBytes[a], (int)pCombinedBytes[a + 1]), Qt::SolidLine));
3417
							else if(nRasterCount == 1)
3418
								paint.setPen(QPen(QColor((int)pCombinedBytes[a], (int)pCombinedBytes[a], (int)pCombinedBytes[a]), Qt::SolidLine));
151 andreas 3419
 
314 andreas 3420
							paint.drawPoint(x1, y1);
3421
						}
151 andreas 3422
 
314 andreas 3423
						x1++;
152 andreas 3424
 
314 andreas 3425
						if(x1 >= nXSize)
3426
						{
3427
							x1 = 0;
3428
							y1++;
3429
						}
3430
					}
152 andreas 3431
 
314 andreas 3432
					delete pCombinedBytes;
3433
					pCombinedBytes = 0;
3434
				}
154 andreas 3435
 
314 andreas 3436
				if(pafScanlineRed)
3437
					delete pafScanlineRed;
158 andreas 3438
 
314 andreas 3439
				if(pafScanlineGreen)
3440
					delete pafScanlineGreen;
3441
 
3442
				if(pafScanlineBlue)
3443
					delete pafScanlineBlue;
3444
 
3445
				if(pafScanlineAlpha)
3446
					delete pafScanlineAlpha;
3447
 
3448
				GDALClose(poDataset);
3449
				poDataset = 0;
3450
 
3451
				if(MAP != fName)
3452
					unlink(fName.toAscii().data());
3453
			}
3454
 
280 andreas 3455
#if defined HAVE_MAPNIK
314 andreas 3456
			else if(MapType == MPT_SHP)
3457
			{
3458
				QDir shpd(MAP, QString("*.shp"));
158 andreas 3459
 
314 andreas 3460
				if(shpd.count() < 1)
3461
				{
3462
					KMessageBox::error(this, i18n("There is no shape file in directory %1").arg(MAP));
3463
					Fgeo = false;
3464
				}
3465
				else
3466
				{
3467
					SRender rd;
3468
					QColor bg(220, 220, 220);		// background color
158 andreas 3469
 
314 andreas 3470
					if(curTab == 0 && !ActivePrint)
3471
						rd.setDrawArea(ui_sportwatcherWidgetBase.imgMap->width(), ui_sportwatcherWidgetBase.imgMap->height());
3472
					else if(!ActivePrint)
3473
						rd.setDrawArea(ui_sportwatcherWidgetBase.grMap->width(), ui_sportwatcherWidgetBase.grMap->height());
3474
					else if(ActivePrint)
3475
						rd.setDrawArea(pmPrMap.width(), pmPrMap.height());
275 andreas 3476
 
314 andreas 3477
					rd.setMapType(SRender::MAP_SHAPE);
276 andreas 3478
 
314 andreas 3479
					if(rd.getMap(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat))
3480
					{
3481
						paint.fillRect(0, 0, width + 2, height + 2, bg);
3482
						paint.drawPixmap(0, 0, rd.pixmap());
3483
						Fgeo = true;
3484
					}
3485
					else
3486
						Fgeo = false;
3487
				}
3488
			}
3489
			else if(MapType == MPT_OSM)
3490
			{
3491
				QFileInfo osmf(MAP);
276 andreas 3492
 
314 andreas 3493
				if(!osmf.exists())
3494
				{
3495
					KMessageBox::error(this, i18n("The OSM file %1 does not exist!").arg(MAP));
3496
					Fgeo = false;
3497
				}
3498
				else
3499
				{
3500
					SRender rd;
3501
					QColor bg(220, 220, 220);		// background color
276 andreas 3502
 
314 andreas 3503
					if(curTab == 0 && !ActivePrint)
3504
						rd.setDrawArea(ui_sportwatcherWidgetBase.imgMap->width(), ui_sportwatcherWidgetBase.imgMap->height());
3505
					else if(!ActivePrint)
3506
						rd.setDrawArea(ui_sportwatcherWidgetBase.grMap->width(), ui_sportwatcherWidgetBase.grMap->height());
3507
					else if(ActivePrint)
3508
						rd.setDrawArea(pmPrMap.width(), pmPrMap.height());
276 andreas 3509
 
314 andreas 3510
					rd.setMapType(SRender::MAP_OSM);
276 andreas 3511
 
314 andreas 3512
					if(rd.getMap(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat))
3513
					{
3514
						paint.fillRect(0, 0, width + 2, height + 2, bg);
3515
						paint.drawPixmap(0, 0, rd.pixmap());
3516
						Fgeo = true;
3517
					}
3518
					else
3519
						Fgeo = false;
3520
				}
3521
			}
3522
 
280 andreas 3523
#endif	// HAVE_MAPNIK
314 andreas 3524
			else
3525
			{
3526
				KMessageBox::error(this, i18n("Error opening map file!"));
3527
				Fgeo = false;
3528
			}
3529
		}
146 andreas 3530
	}
314 andreas 3531
 
280 andreas 3532
#endif	// HAVE_GDAL
154 andreas 3533
	/*
3534
	 * Here we come to draw the track. It will be drawn over the previous
3535
	 * created map image.
3536
	 */
100 andreas 3537
	// Colors and fonts
154 andreas 3538
	QColor background(220, 220, 220);		// background color
3539
	QColor red(255, 0, 0);				// mile marker
3540
	QColor black(0, 0, 0);				// Text, center of track
3541
//	QColor yellow(255, 255, 0);
3542
	QColor yellow(0x00cf, 0x00ff, 0x0000);		// color of track
100 andreas 3543
	QFont fntNormal("Helvetica");
3544
	fntNormal.setPixelSize(10);
3545
	fntNormal.setStyleHint(QFont::Helvetica);
232 andreas 3546
	QPen dot(red, 4, Qt::SolidLine);
3547
	QPen line(black, 2, Qt::SolidLine);
247 andreas 3548
	QPen yline(yellow, 4, Qt::SolidLine);
314 andreas 3549
 
154 andreas 3550
	// Fill background with background colors, if there is no map.
314 andreas 3551
	if(!Fgeo)
3552
		paint.fillRect(0, 0, width + 2, height + 2, background);
152 andreas 3553
 
314 andreas 3554
	if(Units == 0)
3555
		fact = 1000.0;
156 andreas 3556
	else
314 andreas 3557
		fact = 1609.344;
156 andreas 3558
 
109 andreas 3559
	paint.setPen(line);
3560
	paint.drawLine(10, height - 9, 10, height - 4);
156 andreas 3561
	paint.drawLine(10, height - 4, 10 + (fact / dist), height - 4);
3562
	paint.drawLine(10 + (fact / dist), height - 9, 10 + (fact / dist), height - 4);
109 andreas 3563
	paint.setFont(fntNormal);
3564
 
314 andreas 3565
	if(Units == 0)
3566
		paint.drawText(10, height - 10, QString("1000 m"));
156 andreas 3567
	else
314 andreas 3568
		paint.drawText(10, height - 10, QString("5280 ft"));
156 andreas 3569
 
100 andreas 3570
	// Draw track
314 andreas 3571
	if(mapLap)
3572
		i = mapLap->start_time;
132 andreas 3573
	else
314 andreas 3574
		i = 0;
3575
 
100 andreas 3576
	x1 = y1 = 0.0;
157 andreas 3577
	bool wStart = false;
104 andreas 3578
 
314 andreas 3579
	while((point = ds.getPoint(i)) != 0)
100 andreas 3580
	{
314 andreas 3581
		if(mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
3582
			break;
132 andreas 3583
 
314 andreas 3584
		if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
3585
		{
3586
			i = point->time + 1;
3587
			continue;
3588
		}
100 andreas 3589
 
314 andreas 3590
		x2 = (left + ((posNW.lon - SEMI2DEG(point->posn.lon)) * tick * -1)) + oldTransX;
3591
		y2 = (top + ((posNW.lat - SEMI2DEG(point->posn.lat)) * tick)) + oldTransY;
100 andreas 3592
 
314 andreas 3593
		if(!wStart && x1 != 0.0 && y1 != 0.0)
3594
		{
3595
			// Load the start symbol
3596
			QPixmap qpx(KIcon(QString("wstart")).pixmap(16));
3597
			// Find the angle of the track and turn the symbol accordingly
3598
			// we use Pythagoras to calculate the triangle
3599
			double xl = (x1 < x2) ? x2 - x1 : x1 - x2;
3600
			double yl = (y1 < y2) ? y2 - y1 : y1 - y2;
3601
			double da = fmin(xl, yl);
3602
			double db = fmax(xl, yl);
3603
			double zl = sqrt(pow(da, 2) + pow(db, 2));
3604
			double angle = (asin(da / zl) / M_PIl) * 180.0;
157 andreas 3605
 
314 andreas 3606
			angle = (angle > 45.0) ? 90.0 - angle : angle;
3607
 
157 andreas 3608
// cout << "Winkel: " << angle << " ---- X: " << xl << ", Y: " << yl << ", Z: " << zl << ", Point (x1,y1,x2,y2): " << x1 << ", " << y1 << ", " << x2 << ", " << y2 << endl;
314 andreas 3609
			if(x1 < x2 && y1 < y2)		// right, down
3610
				angle = 90.0 + angle;
3611
			else if(x1 > x2 && y1 < y2)	// left, down
3612
				angle = 270.0 - angle;
3613
			else if(x1 > x2 && y1 > y2)	// left, up
3614
				angle = 270.0 + angle;
3615
			else				// right, up
3616
				angle = 90.0 - angle;
3617
 
157 andreas 3618
// cout << "Realer Winkel: " << angle << endl;
314 andreas 3619
			// Set the center of the symbol
3620
			paint.save();
3621
			paint.translate(x1, y1);
3622
			// rotate the symbol
3623
			paint.rotate(angle);
3624
			paint.drawPixmap(-8, -8, qpx);
3625
			paint.restore();
3626
			wStart = true;
3627
		}
157 andreas 3628
 
314 andreas 3629
		if(x1 == 0.0 && y1 == 0.0)
3630
		{
3631
			x1 = x2;
3632
			y1 = y2;
3633
		}
104 andreas 3634
 
314 andreas 3635
		paint.setPen(yline);
3636
		paint.drawLine(x1, y1, x2, y2);
104 andreas 3637
 
314 andreas 3638
		if((point->distance - dist) >= fact)	// a dot at every 1000 meters or at 1 mile
3639
		{
3640
			paint.setPen(dot);
3641
			paint.drawEllipse(x2 - 2, y2 - 2, 3, 3);
3642
			dist = (int)(point->distance / fact) * fact;
3643
		}
104 andreas 3644
 
314 andreas 3645
		paint.setPen(line);
3646
		paint.drawLine(x1, y1, x2, y2);
3647
		x1 = x2;
3648
		y1 = y2;
3649
		i = point->time + 1;
100 andreas 3650
	}
3651
 
157 andreas 3652
	bool lastLap = false;
3653
 
314 andreas 3654
	if(mapLap)
3655
		if(ds.getRunNode()->run->last_lap_index == mapLap->index)
3656
			lastLap = true;
157 andreas 3657
 
314 andreas 3658
	if((!mapLap || lastLap) && wStart)
157 andreas 3659
	{
314 andreas 3660
		// load the end symbol
3661
		QPixmap qpx(KIcon(QString("wtarget")).pixmap(16));
3662
		paint.drawPixmap(x2, y2 - 16, qpx);
157 andreas 3663
	}
3664
 
100 andreas 3665
	paint.end();
248 andreas 3666
 
314 andreas 3667
	if(curTab == 0 && !ActivePrint)
3668
		ui_sportwatcherWidgetBase.imgMap->setPixmap(pmMap);
3669
	else if(ActivePrint)
3670
		pmPrMap = pmMap;
248 andreas 3671
	else
314 andreas 3672
		ui_sportwatcherWidgetBase.grMap->setPixmap(pmMap);
248 andreas 3673
 
154 andreas 3674
	QApplication::restoreOverrideCursor();
100 andreas 3675
}
3676
 
245 andreas 3677
void sportwatcherWidget::kcbCurveSlot(int)
3678
{
246 andreas 3679
	DIRTY = true;
245 andreas 3680
	showCurves();
246 andreas 3681
	DIRTY = false;
245 andreas 3682
}
3683
 
248 andreas 3684
void sportwatcherWidget::tabViewSlot(int tab)
3685
{
3686
	curTab = tab;
3687
 
314 andreas 3688
	if(tab == 0 && tabDirt0)
248 andreas 3689
	{
314 andreas 3690
		DIRTY = true;
3691
		showLaps();
3692
		showTrack();
3693
		showCurves();
3694
		DIRTY = false;
3695
		tabDirt0 = false;
248 andreas 3696
	}
314 andreas 3697
	else if(tab == 1 && tabDirt1)
248 andreas 3698
	{
314 andreas 3699
		DIRTY = true;
248 andreas 3700
 
314 andreas 3701
		if(tabDirt0)
3702
			showLaps();
248 andreas 3703
 
314 andreas 3704
		showTrack();
3705
		DIRTY = false;
3706
		tabDirt1 = false;
248 andreas 3707
	}
314 andreas 3708
	else if(tab == 2 && tabDirt2)
250 andreas 3709
	{
314 andreas 3710
		DIRTY = true;
250 andreas 3711
 
314 andreas 3712
		if(tabDirt0)
3713
			showLaps();
250 andreas 3714
 
314 andreas 3715
		setMouseTracking(true);
3716
		ui_sportwatcherWidgetBase.tabView->setMouseTracking(true);
3717
		ui_sportwatcherWidgetBase.grHR->setMouseTracking(true);
3718
		ui_sportwatcherWidgetBase.grElevation->setMouseTracking(true);
3719
		ui_sportwatcherWidgetBase.grSpeed->setMouseTracking(true);
3720
		showThreeCurve();
3721
		tabDirt2 = false;
3722
		DIRTY = false;
250 andreas 3723
	}
248 andreas 3724
}
3725
 
88 andreas 3726
void sportwatcherWidget::showCurves()
3727
{
314 andreas 3728
	showCurves(mapLap);
148 andreas 3729
}
3730
 
3731
void sportwatcherWidget::showCurves(LAP *lap)
3732
{
314 andreas 3733
	QPainter paint;
3734
	int width, height;
3735
	int i, secs, cuType;
3736
	int lineHeight, margin_left, margin_right, margin_bottom;
3737
	int x1, y1, x2, y2;		// Coordinates
3738
	bool meter;
3739
	double maxHeight, minHeight, maxSpeed, minSpeed;
3740
	int maxHr, minHr, rh;
3741
	POINT *point;
3742
	RUN_NODE *rn;
3743
	LAP *lp;
3744
	double w_tick, h_tick;		// Number of pixels one "tick" has;
3745
 
3746
	// This depends on the width and height
3747
	// of the image.
88 andreas 3748
	// First we draw a grid based on the min and max
3749
	// values detected in the function showLap(). In case
3750
	// all values are 0, we exit here.
314 andreas 3751
	if(min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
3752
		return;
88 andreas 3753
 
314 andreas 3754
	if(!DIRTY || curTab != 0)
3755
		return;
246 andreas 3756
 
218 andreas 3757
	// Look up, what curves we should draw
245 andreas 3758
	cuType = ui_sportwatcherWidgetBase.kcbCurveTypes->currentIndex();
218 andreas 3759
	// Get the dimensions of the available draw area
245 andreas 3760
	width = ui_sportwatcherWidgetBase.imgProfile->width() - 2;
3761
	height = ui_sportwatcherWidgetBase.imgProfile->height();
232 andreas 3762
	pmProfile = QPixmap(width, height);
88 andreas 3763
	paint.begin(&pmProfile);
3764
 
3765
	// we need a somewhat bigger area to draw our curves than
3766
	// we have with the real min and max values.
314 andreas 3767
	if(max_height > 0.0)
88 andreas 3768
	{
314 andreas 3769
		double add = (max_height - min_height) / 100.0 * 5.0;	// Percent
88 andreas 3770
 
314 andreas 3771
		maxHeight = max_height + add;
3772
		minHeight = min_height - add;
88 andreas 3773
 
314 andreas 3774
		if(minHeight < 0.0)		// make sure, we are not too deep
3775
			minHeight = 0.0;
88 andreas 3776
	}
221 andreas 3777
	else
314 andreas 3778
		maxHeight = minHeight = 0.0;
88 andreas 3779
 
314 andreas 3780
	if(max_speed > 0.0)
218 andreas 3781
	{
314 andreas 3782
		double add = (max_speed - min_speed) / 100.0 * 5.0;	// Percent
218 andreas 3783
 
314 andreas 3784
		maxSpeed = max_speed + add;
3785
		minSpeed = min_speed - add;
218 andreas 3786
 
314 andreas 3787
		if(minSpeed < 0.0)		// make sure, we are not too deep
3788
			minSpeed = 0.0;
218 andreas 3789
	}
221 andreas 3790
	else
314 andreas 3791
		maxSpeed = minSpeed = 0.0;
218 andreas 3792
 
314 andreas 3793
	if(max_hr > 0)
88 andreas 3794
	{
314 andreas 3795
		maxHr = max_hr + 10;
3796
		minHr = min_hr - 10;
88 andreas 3797
 
314 andreas 3798
		if(minHr < 0)
3799
			minHr = 0;
88 andreas 3800
	}
221 andreas 3801
	else
314 andreas 3802
		maxHr = minHr = 0;
88 andreas 3803
 
3804
	// Define colors
148 andreas 3805
	QColor background(220, 220, 220);	// Background of graphic
3806
	QColor mark(255, 255, 255);		// Lines inside curve area
3807
	QColor hlight(180, 180, 180);		// area of current lap
3808
//	hlight.setAlpha(128);			// 50% transparent
3809
	QColor frame(0, 0, 0);			// Text and borders
3810
	QColor barcol(151, 190, 13);		// heart rate
3811
	QColor barcol2(190, 151, 13);		// height over NN
222 andreas 3812
	QColor red(220, 128, 128);		// speed
88 andreas 3813
	QColor blue(0, 0, 240);
3814
	QFont fntNormal("Helvetica");
3815
//	QFont fntBold("Helvetica", 10, QFont::Bold);
3816
	fntNormal.setPixelSize(10);
3817
	fntNormal.setStyleHint(QFont::Helvetica);
3818
//	fntBold.setPixelSize(10);
3819
//	fntBold.setStyleHint(QFont::Helvetica);
3820
	// Calculate ticks
3821
	margin_left = 52;
3822
	margin_right = 40;
3823
	margin_bottom = 12;
3824
	lineHeight = 10;
3825
	rh = height - margin_bottom - 1;
3826
 
249 andreas 3827
	w_tick = (double)(width - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
88 andreas 3828
 
314 andreas 3829
	if(cuType == 1)	// Speed and heart rate?
88 andreas 3830
	{
314 andreas 3831
		if((maxSpeed - minSpeed) > (double)(maxHr - minHr))
3832
		{
3833
			h_tick = (double)rh / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
3834
			meter = true;
3835
		}
3836
		else
3837
		{
3838
			h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
3839
			meter = false;
3840
		}
88 andreas 3841
	}
314 andreas 3842
	else if(cuType == 2)	// Elevation and speed?
88 andreas 3843
	{
314 andreas 3844
		if((maxHeight - minHeight) > (double)(maxHr - minHr))
3845
		{
3846
			h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
3847
			meter = true;
3848
		}
3849
		else
3850
		{
3851
			h_tick = (double)rh / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
3852
			meter = false;
3853
		}
222 andreas 3854
	}
3855
	else			// Elevation and heart rate
3856
	{
314 andreas 3857
		if((maxHeight - minHeight) > (double)(maxHr - minHr))
3858
		{
3859
			h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
3860
			meter = true;
3861
		}
3862
		else
3863
		{
3864
			h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
3865
			meter = false;
3866
		}
88 andreas 3867
	}
218 andreas 3868
 
88 andreas 3869
	// Fill background with background colors
3870
	paint.fillRect(0, 0, width + 4, height + 4, background);
3871
	// Draw a grid with markers at every 10 minutes
232 andreas 3872
	paint.setPen(QPen(frame, 1, Qt::SolidLine));
88 andreas 3873
	// Bottom border line
3874
	x1 = margin_left;
3875
	y1 = height - margin_bottom;
3876
	x2 = width - margin_right;
3877
	y2 = y1;
3878
	paint.drawLine(x1, y1, x2, y2);
3879
	// Left border line
3880
	x1 = x2 = margin_left;
3881
	y1 = 2;
3882
	y2 = height - margin_bottom;
3883
	paint.drawLine(x1, y1, x2, y2);
3884
	// right border line
3885
	x1 = x2 = width - margin_right;
3886
	paint.drawLine(x1, y1, x2, y2);
148 andreas 3887
 
3888
	// Draw some darker lines to show the laps, if we have one
3889
	// and, in case we have a given lap, we fill the area.
3890
	QDateTime *qt;
3891
	QTime zeit = StartTime.time();
3892
	rn = ds.getRunNode();
232 andreas 3893
	paint.setPen(QPen(hlight, 1, Qt::SolidLine));
148 andreas 3894
 
314 andreas 3895
	for(i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
148 andreas 3896
	{
314 andreas 3897
		if((lp = ds.getLap(i)) == NULL)
3898
			continue;
148 andreas 3899
 
314 andreas 3900
		qt = garmin_dtime(lp->start_time);
3901
		secs = zeit.secsTo(qt->time());
3902
		delete qt;
3903
		x1 = secs * w_tick + margin_left + 1;
148 andreas 3904
 
314 andreas 3905
		if(lap && lp->start_time == lap->start_time)
3906
			paint.fillRect(x1, 2, (int)((double)lap->total_time / 100.0 * w_tick), height - margin_bottom - 2, hlight);
3907
		else
3908
			paint.drawLine(x1, 2, x1, height - margin_bottom);
148 andreas 3909
	}
3910
 
88 andreas 3911
	// Grid vertical
232 andreas 3912
	paint.setPen(QPen(frame, 1, Qt::SolidLine));
88 andreas 3913
	paint.setFont(fntNormal);
3914
	paint.drawText(margin_left - 20, height - lineHeight, 40, lineHeight, Qt::AlignCenter, QString("00:00"));
3915
	paint.save();
3916
	paint.rotate(270);
218 andreas 3917
 
314 andreas 3918
	if(cuType == 1)
3919
		paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3920
	else
314 andreas 3921
		paint.setPen(QPen(barcol, 1, Qt::SolidLine));
222 andreas 3922
 
3923
	// Information on left side
314 andreas 3924
	if(cuType == 0)
3925
		paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n("Elevation (%1)").arg((Units == 1) ? "ft" : "m"));
3926
	else if(cuType == 1)
3927
		paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n("Speed (%1)").arg((Units == 1) ? "mph" : "km/h"));
218 andreas 3928
	else
314 andreas 3929
		paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n("Elevation (%1)").arg((Units == 1) ? "ft" : "m"));
218 andreas 3930
 
314 andreas 3931
	if(cuType == 2)
3932
		paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3933
	else
314 andreas 3934
		paint.setPen(QPen(blue, 1, Qt::SolidLine));
218 andreas 3935
 
222 andreas 3936
	// Information on right side
314 andreas 3937
	if(cuType < 2)
3938
		paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
218 andreas 3939
	else
314 andreas 3940
		paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Speed (%1)").arg((Units == 1) ? "mph" : "km/h"));
218 andreas 3941
 
88 andreas 3942
	paint.restore();
232 andreas 3943
	paint.setPen(QPen(mark, 1, Qt::SolidLine));
314 andreas 3944
 
222 andreas 3945
	// Draw the time scale on the bottom of the graphic
314 andreas 3946
	for(i = 0; (unsigned int)i < (max_time + ds.getPauseTime()); i++)
88 andreas 3947
	{
314 andreas 3948
		if(i > 0 && !(i % 600))	// every 10 minutes
3949
		{
3950
			x1 = x2 = margin_left + w_tick * i;
88 andreas 3951
 
314 andreas 3952
			if(x1 == (width - margin_right))
3953
				continue;
88 andreas 3954
 
314 andreas 3955
			y1 = 2;
3956
			y2 = height - margin_bottom;
3957
			paint.drawLine(x1, y1, x2, y2);
3958
			QTime tm(0, 0, 0);
3959
			tm = tm.addSecs(i);
3960
			paint.setPen(QPen(frame, 1, Qt::SolidLine));
230 andreas 3961
//	      paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((i >= 3600) ? "hh:mm:ss" : "mm:ss"));
314 andreas 3962
			paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
3963
			paint.setPen(QPen(mark, 1, Qt::SolidLine));
3964
		}
88 andreas 3965
	}
222 andreas 3966
 
3967
	// This is the total time, with pauses included, at the lower right
3968
	// corner of the graphic.
88 andreas 3969
	QTime tm(0, 0, 0);
3970
	QString qs;
249 andreas 3971
	tm = tm.addSecs(max_time + ds.getPauseTime());
232 andreas 3972
	paint.setPen(QPen(frame, 1, Qt::SolidLine));
230 andreas 3973
//	paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((max_time >= 3600) ? "hh:mm:ss" : "mm:ss"));
3974
	paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
88 andreas 3975
 
222 andreas 3976
	// Draw the minimal elevation, speed and/or heart rate
314 andreas 3977
	if(max_height > 0.0 || max_speed > 0.0)
88 andreas 3978
	{
314 andreas 3979
		// left side
3980
		if(cuType == 1)
3981
		{
3982
			paint.setPen(QPen(red, 1, Qt::SolidLine));
3983
			paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minSpeed));
3984
		}
3985
		else
3986
		{
3987
			paint.setPen(QPen(barcol, 1, Qt::SolidLine));
3988
			paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? minHeight / 0.304 : minHeight));
3989
		}
88 andreas 3990
	}
314 andreas 3991
 
3992
	if(max_hr > 0 || max_speed > 0.0)
88 andreas 3993
	{
314 andreas 3994
		// right side
3995
		if(cuType == 2)
3996
		{
3997
			paint.setPen(QPen(red, 1, Qt::SolidLine));
3998
			paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));
3999
		}
4000
		else
4001
		{
4002
			paint.setPen(QPen(blue, 1, Qt::SolidLine));
4003
			paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
4004
		}
88 andreas 4005
	}
4006
 
232 andreas 4007
	paint.setPen(QPen(mark, 1, Qt::SolidLine));
88 andreas 4008
 
4009
	// Grid horizontal
218 andreas 4010
	int factor = 0;
4011
	int target = 0;
4012
 
314 andreas 4013
	if(cuType == 0)	// Elevation and heart rate
218 andreas 4014
	{
314 andreas 4015
		factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxHr - minHr) / (rh / 12);
4016
		target = (meter) ? (int)(maxHeight - minHeight) : (maxHr - minHr);
222 andreas 4017
	}
314 andreas 4018
	else if(cuType == 1)	// Speed and heart rate
222 andreas 4019
	{
314 andreas 4020
		factor = (meter) ? (maxSpeed - minSpeed) / (rh / 12) : (maxHr - minHr) / (rh / 12);
4021
		target = (meter) ? (int)(maxSpeed - minSpeed) : (maxHr - minHr);
218 andreas 4022
	}
222 andreas 4023
	else			// Elevation and speed
218 andreas 4024
	{
314 andreas 4025
		factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxSpeed - minSpeed) / (rh / 12);
4026
		target = (meter) ? (int)(maxHeight - minHeight) : (int)(maxSpeed - minSpeed);
218 andreas 4027
	}
4028
 
222 andreas 4029
	// To prevent a division by zero error, we check the <factor>
314 andreas 4030
	if(factor == 0)
4031
		factor = 1;
222 andreas 4032
 
4033
	// Beside the horizontal part of the grid, we draw the scale on the
4034
	// left and the right side.
88 andreas 4035
	int oldy = height;
4036
 
314 andreas 4037
	for(i = 0; i < target; i++)
88 andreas 4038
	{
314 andreas 4039
		if(i > 0 && !(i % factor))
4040
		{
4041
			x1 = margin_left + 1;
4042
			x2 = width - margin_right - 1;
4043
			y1 = y2 = rh - h_tick * i;
88 andreas 4044
 
314 andreas 4045
			if(y1 < 12)
4046
				break;
88 andreas 4047
 
314 andreas 4048
			paint.drawLine(x1, y1, x2, y2);
88 andreas 4049
 
314 andreas 4050
			if(y1 < (oldy - lineHeight))
4051
			{
4052
				if(meter)
4053
				{
4054
					paint.setPen(QPen(barcol, 1, Qt::SolidLine));
218 andreas 4055
 
314 andreas 4056
					// left side
4057
					if(cuType == 1)
4058
					{
4059
						paint.setPen(QPen(red, 1, Qt::SolidLine));
4060
						paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + i));
4061
					}
4062
					else
4063
						paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));
222 andreas 4064
 
314 andreas 4065
					// right side
4066
					if(maxHr > 0 && cuType != 2)
4067
					{
4068
						double hrscale = (double)(maxHr - minHr) / (double)target;
4069
						paint.setPen(QPen(blue, 1, Qt::SolidLine));
4070
						paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", (int)((double)minHr + hrscale * (double)i)));
4071
					}
4072
					else
4073
					{
4074
						double spscale = (maxSpeed - minSpeed) / (double)target;
222 andreas 4075
 
314 andreas 4076
						if(cuType == 2)
4077
							paint.setPen(QPen(red, 1, Qt::SolidLine));
4078
						else
4079
							paint.setPen(QPen(blue, 1, Qt::SolidLine));
88 andreas 4080
 
314 andreas 4081
						paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", (minSpeed + spscale * (double)i)));
4082
					}
4083
				}
4084
				else
4085
				{
4086
					// right side
4087
					if(cuType == 2)
4088
					{
4089
						paint.setPen(QPen(red, 1, Qt::SolidLine));
4090
						paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
4091
					}
4092
					else
4093
					{
4094
						paint.setPen(QPen(blue, 1, Qt::SolidLine));
4095
						paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
4096
					}
4097
 
4098
					// left side
4099
					if((cuType == 0 || cuType == 2) && max_height > 0)
4100
					{
4101
						double hrscale = (maxHeight - minHeight) / (double)target;
4102
						paint.setPen(QPen(barcol, 1, Qt::SolidLine));
4103
						paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minHeight + hrscale * (double)i));
4104
					}
4105
					else if(max_speed > 0 && cuType == 1)
4106
					{
4107
						double hrscale = (maxSpeed - minSpeed) / (double)target;
4108
						paint.setPen(QPen(red, 1, Qt::SolidLine));
4109
						paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + hrscale * (double)i));
4110
					}
4111
				}
4112
 
4113
				paint.setPen(QPen(mark, 1, Qt::SolidLine));
4114
				oldy = y1;
4115
			}
88 andreas 4116
		}
4117
	}
4118
 
168 andreas 4119
	// To make our graphics more beautiful, we draw lines for the
88 andreas 4120
	// heart rate limits and the average heart rate.
314 andreas 4121
	if(max_hr > 0 && cuType != 2)
88 andreas 4122
	{
314 andreas 4123
		int ay1, ay2, ay3, ay4, ay5;
88 andreas 4124
 
314 andreas 4125
		x1 = margin_left + 1;
4126
		x2 = width - margin_right - 1;
88 andreas 4127
 
314 andreas 4128
		if(meter)
4129
		{
4130
			double hrscale = rh / (double)(maxHr - minHr);
4131
			ay1 = (double)rh - (double)(lower1 - minHr) * hrscale;
4132
			ay2 = (double)rh - (double)(lower2 - minHr) * hrscale;
4133
			ay3 = (double)rh - (double)(lower3 - minHr) * hrscale;
4134
			ay4 = (double)rh - (double)(upper3 - minHr) * hrscale;
4135
			ay5 = (double)rh - (double)(avg_hr - minHr) * hrscale;
4136
		}
4137
		else
4138
		{
4139
			ay1 = (double)rh - (double)(lower1 - minHr) * h_tick;
4140
			ay2 = (double)rh - (double)(lower2 - minHr) * h_tick;
4141
			ay3 = (double)rh - (double)(lower3 - minHr) * h_tick;
4142
			ay4 = (double)rh - (double)(upper3 - minHr) * h_tick;
4143
			ay5 = (double)rh - (double)(avg_hr - minHr) * h_tick;
4144
		}
88 andreas 4145
 
314 andreas 4146
		paint.setPen(QPen(barcol2, 1, Qt::DashLine));	// color for limits
88 andreas 4147
 
314 andreas 4148
		if(lower1 > minHr && lower1 < maxHr)
4149
			paint.drawLine(x1, ay1, x2, ay1);
88 andreas 4150
 
314 andreas 4151
		if(lower2 > minHr && lower2 < maxHr)
4152
			paint.drawLine(x1, ay2, x2, ay2);
88 andreas 4153
 
314 andreas 4154
		if(lower3 > minHr && lower3 < maxHr)
4155
			paint.drawLine(x1, ay3, x2, ay3);
88 andreas 4156
 
314 andreas 4157
		if(upper3 > minHr && upper3 < maxHr)
4158
			paint.drawLine(x1, ay4, x2, ay4);
88 andreas 4159
 
314 andreas 4160
		paint.setPen(QPen(red, 1, Qt::DashDotLine));	// color for average heart rate
88 andreas 4161
 
314 andreas 4162
		if(avg_hr > minHr && avg_hr < maxHr)
4163
			paint.drawLine(x1, ay5, x2, ay5);
88 andreas 4164
	}
4165
 
4166
	// Now we have a grid and we've done the scaling.
4167
	// This is the point where we draw the curves itself.
223 andreas 4168
	// We use different colors to draw the lines:
4169
	//
4170
	// Green: Elevation
4171
	// Red:   Speed
4172
	// Blue   Heart Rate
4173
	//
88 andreas 4174
	x1 = x2 = y1 = y2 = 0;
148 andreas 4175
	int hy1, hy2, hx1, hx2;
222 andreas 4176
	int sy1, sy2, sx1, sx2;
88 andreas 4177
	hy1 = hy2 = hx1 = hx2 = 0;
222 andreas 4178
	sy1 = sy2 = sx1 = sx2 = 0;
169 andreas 4179
	int hEc = 0;
4180
	i = 0;
4181
	AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
170 andreas 4182
	avgHfirst = avgHlast = 0;
314 andreas 4183
 
169 andreas 4184
	// To even the surface lines, we store every altitude in the
4185
	// memory, by building a chain. Then, if the user has set in the
4186
	// settings (Contour == true), we will even the line by calculating
4187
	// the average of 10 messure points and setting every value to the
4188
	// average, who is up or down more than 2 meters from the average.
314 andreas 4189
	while((point = ds.getPoint(i)) != 0)
169 andreas 4190
	{
314 andreas 4191
		if(point->alt > 20000.0 || point->alt < -1000.0)
4192
		{
4193
			i++;
4194
			continue;
4195
		}
168 andreas 4196
 
314 andreas 4197
		if(!avgHeight)
4198
		{
4199
			avgHeight = new AVGHEIGHT;
4200
			avgHeight->alt = point->alt;
4201
			avgHeight->pos = hEc;
4202
			avgHeight->prev = 0;
4203
			avgHeight->next = 0;
4204
			avgHakt = avgHeight;
4205
			avgHfirst = avgHeight;
4206
		}
4207
		else
4208
		{
4209
			avgHakt = new AVGHEIGHT;
4210
			avgHakt->alt = point->alt;
4211
			avgHakt->pos = hEc;
4212
			avgHakt->next = 0;
4213
			avgHakt->prev = avgHeight;
4214
			avgHeight->next = avgHakt;
4215
			avgHeight = avgHakt;
4216
		}
169 andreas 4217
 
314 andreas 4218
		// FIXME: Currently we can not draw below 0 meters, because the
4219
		// base line is always 0!
4220
		if(avgHakt->alt < minHeight)
4221
			avgHakt->alt = minHeight;
169 andreas 4222
 
314 andreas 4223
		hEc++;
4224
		i++;
169 andreas 4225
	}
4226
 
4227
	avgHlast = avgHeight;
314 andreas 4228
 
169 andreas 4229
	// If wanted, even the lines
314 andreas 4230
	if(Contour && hEc > 0 && cuType != 0)
169 andreas 4231
	{
314 andreas 4232
		double alt[100], avg, avg1, avg2, avg3, avg4;
4233
		int a, pos;
169 andreas 4234
 
314 andreas 4235
		for(i = 0; i < (hEc + 100); i += 100)
4236
		{
4237
			avg = avg1 = avg2 = avg3 = avg4 = 0.0;
4238
			pos = 0;
169 andreas 4239
 
314 andreas 4240
			for(a = 0; a < 100; a++)
4241
			{
4242
				alt[a] = getAvgAlt(avgHfirst, i + a);
4243
				avg += alt[a];
213 andreas 4244
 
314 andreas 4245
				if(a < 25)
4246
					avg1 += alt[a];
4247
				else if(a < 50)
4248
					avg2 += alt[a];
4249
				else if(a < 75)
4250
					avg3 += alt[a];
4251
				else
4252
					avg4 += alt[a];
4253
			}
169 andreas 4254
 
314 andreas 4255
			if((i + 100) >= hEc)
4256
				avg /= (double)(hEc - i) + 1.0;
4257
			else
4258
				avg /= 100.0;
169 andreas 4259
 
314 andreas 4260
			for(a = 0; a < 100; a++)
4261
			{
4262
				if((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
4263
				{
4264
					if((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
4265
						avgHakt->alt = avg;
4266
				}
4267
			}
4268
		}
169 andreas 4269
	}
4270
 
222 andreas 4271
	// plot the elevation, speed and/or heart rate. Depends on <cuType>)
168 andreas 4272
	i = 0;
169 andreas 4273
	int j = 0;
218 andreas 4274
	POINT *oldPoint = 0;
222 andreas 4275
	double speed = 0.0;	// calculated speed
4276
	bool pause = false;	// filter pause out of speed
4277
	unsigned long t1, t2;
4278
	t1 = t2 = 0;
314 andreas 4279
 
4280
	while((point = ds.getPoint(i)) != 0)
88 andreas 4281
	{
314 andreas 4282
		if(!oldPoint)
4283
			oldPoint = point;
218 andreas 4284
 
314 andreas 4285
		// calculate the y position based on the time
4286
		qt = garmin_dtime(point->time);
4287
		secs = zeit.secsTo(qt->time());
4288
		delete qt;
4289
		x2 = secs * w_tick + margin_left + 1;
4290
		hx2 = x2;
4291
		sx2 = x2;
88 andreas 4292
 
314 andreas 4293
		if(x1 == 0)
4294
			x1 = x2;
88 andreas 4295
 
314 andreas 4296
		if(hx1 == 0)
4297
			hx1 = hx2;
88 andreas 4298
 
314 andreas 4299
		if(sx1 == 0)
4300
			sx1 = sx2;
222 andreas 4301
 
314 andreas 4302
		// The speed is not very exact, because smallest time is
4303
		// one second. This allows a maximum error of 99 hundredths
4304
		// of a second, what is very close to one second. Because of
4305
		// this, speed seems to hop for every messure point. This
4306
		// looks ugly, but currently I don't know how to make it
4307
		// better.
4308
		if(cuType == 1 || cuType == 2)	// Draw speed?
4309
		{
4310
			double dist;
4311
			double sc;
168 andreas 4312
 
314 andreas 4313
			if(!pause && point->distance > 1.0e10)
4314
			{
4315
				pause = true;
4316
				t1 = point->time;
4317
			}
4318
			else if(pause)
4319
			{
4320
				pause = false;
4321
				t2 = point->time;
4322
				i += 2;
4323
				continue;
4324
			}
222 andreas 4325
 
314 andreas 4326
			if(point->distance >= 0.1 && point->distance < 1.0e10)
4327
			{
4328
				dist = point->distance - oldPoint->distance;
4329
				sc = point->time - oldPoint->time;
4330
				LAP *runde = ds.getLapT(point->time);
222 andreas 4331
 
314 andreas 4332
				if(t2 > t1)
4333
				{
4334
					sc -= t2 - t1;
222 andreas 4335
 
314 andreas 4336
					if(sc <= 0.0)
4337
						sc = 1.0;		// at least 1 second!
4338
				}
222 andreas 4339
 
314 andreas 4340
				speed = (dist / sc) * 3.6;
168 andreas 4341
 
314 andreas 4342
				if(runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
4343
					speed = runde->max_speed * 3.6;
223 andreas 4344
 
314 andreas 4345
				if(Units == 1)
4346
					speed /= 1.609344;
218 andreas 4347
 
314 andreas 4348
				if(speed < minSpeed || speed > 400.0)
4349
					speed = minSpeed;
218 andreas 4350
 
314 andreas 4351
				if((meter && cuType == 1) || (!meter && cuType == 2))
4352
					y2 = (double)rh - (speed - minSpeed) * h_tick;
4353
				else
4354
				{
4355
					double hrscale = rh / (maxSpeed - minSpeed);
4356
					y2 = (double)rh - (speed - minSpeed) * hrscale;
4357
				}
218 andreas 4358
 
314 andreas 4359
				if(y1 == 0)
4360
					y1 = y2;
218 andreas 4361
 
314 andreas 4362
				paint.setPen(QPen(red, 1, Qt::SolidLine));
4363
				paint.drawLine(x1, y1, x2, y2);
4364
				y1 = y2;
4365
				x1 = x2;
4366
				t1 = t2 = 0;
4367
				oldPoint = point;
4368
			}
4369
		}
222 andreas 4370
 
314 andreas 4371
		if(cuType == 0 || cuType == 2)		// Draw elevation?
4372
		{
4373
			if(point->alt < 20000.0 && point->alt > -1000.0)
4374
			{
4375
				double alt = getAvgAlt(avgHfirst, j);
88 andreas 4376
 
314 andreas 4377
				j++;
218 andreas 4378
 
314 andreas 4379
				if(meter)
4380
					sy2 = (double)rh - (alt - minHeight) * h_tick;
4381
				else
4382
				{
4383
					double hrscale = rh / (maxHeight - minHeight);
4384
					sy2 = (double)rh - (alt - minHeight) * hrscale;
4385
				}
218 andreas 4386
 
314 andreas 4387
				if(sy1 == 0)
4388
					sy1 = sy2;
218 andreas 4389
 
314 andreas 4390
				paint.setPen(QPen(barcol, 1, Qt::SolidLine));
4391
				paint.drawLine(sx1, sy1, sx2, sy2);
4392
				sy1 = sy2;
4393
				sx1 = sx2;
4394
			}
4395
		}
88 andreas 4396
 
314 andreas 4397
		if(point->heart_rate > 0 && cuType < 2)	// Draw heart rate?
4398
		{
4399
			if(meter)
4400
			{
4401
				double hrscale = rh / (double)(maxHr - minHr);
4402
				hy2 = (double)rh - (double)(point->heart_rate - minHr) * hrscale;
4403
			}
4404
			else
4405
				hy2 = (double)rh - (double)(point->heart_rate - minHr) * h_tick;
88 andreas 4406
 
314 andreas 4407
			if(hy1 == 0)
4408
				hy1 = hy2;
88 andreas 4409
 
314 andreas 4410
			paint.setPen(QPen(blue, 1, Qt::SolidLine));
4411
			paint.drawLine(hx1, hy1, hx2, hy2);
4412
			hy1 = hy2;
4413
			hx1 = hx2;
4414
		}
88 andreas 4415
 
314 andreas 4416
		i++;
88 andreas 4417
	}
4418
 
4419
	paint.end();
245 andreas 4420
	ui_sportwatcherWidgetBase.imgProfile->setPixmap(pmProfile);
88 andreas 4421
 
169 andreas 4422
	// free the chain of altitudes
4423
	avgHakt = avgHfirst;
4424
 
314 andreas 4425
	while(avgHakt)
169 andreas 4426
	{
314 andreas 4427
		avgHeight = avgHakt->next;
4428
		delete avgHakt;
4429
		avgHakt = avgHeight;
169 andreas 4430
	}
4431
 
246 andreas 4432
	DIRTY = false;
88 andreas 4433
}
4434
 
280 andreas 4435
void sportwatcherWidget::showThreeCurve(int pw, int ph)
250 andreas 4436
{
314 andreas 4437
	QPainter ptHR, ptElevation, ptSpeed;
4438
	int width, height, wdHR, htHR, wdElev, htElev, wdSpeed, htSpeed;
4439
	int i, secs;
4440
	int lineHeight, margin_left, margin_right, margin_bottom;
4441
	int x1, y1, x2, y2;		// Coordinates
4442
	double maxHeight, minHeight, maxSpeed, minSpeed;
4443
	int maxHr, minHr, rh, rhHR, rhElev, rhSpeed;
4444
	POINT *point;
4445
	RUN_NODE *rn;
4446
	LAP *lp;
4447
	double wtiHR, htiHR, wtiElev, htiElev, wtiSpeed, htiSpeed;
4448
	double w_tick, h_tick;		// Number of pixels one "tick" has;
4449
 
4450
	// This depends on the width and height
4451
	// of the image.
250 andreas 4452
	// First we draw a grid based on the min and max
4453
	// values detected in the function showLap(). In case
4454
	// all values are 0, we exit here.
314 andreas 4455
	if(min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
4456
		return;
250 andreas 4457
 
314 andreas 4458
	if(!ActivePrint && (!DIRTY || curTab != 2))
4459
		return;
250 andreas 4460
 
283 andreas 4461
	w_tick = h_tick = 0.0;
4462
	rh = 0;
4463
	width = height = 0;
314 andreas 4464
 
250 andreas 4465
	// Get the dimensions of the available draw area
4466
	// First for heart rate
314 andreas 4467
	if(!ActivePrint)
280 andreas 4468
	{
314 andreas 4469
		wdHR = ui_sportwatcherWidgetBase.grHR->width() - 2;
4470
		htHR = ui_sportwatcherWidgetBase.grHR->height();
4471
		pmHR = QPixmap(wdHR, htHR);
4472
		// Then for elevation
4473
		wdElev = ui_sportwatcherWidgetBase.grElevation->width() - 2;
4474
		htElev = ui_sportwatcherWidgetBase.grElevation->height();
4475
		pmElevation = QPixmap(wdElev, htElev);
4476
		// And at last for speed
4477
		wdSpeed = ui_sportwatcherWidgetBase.grSpeed->width() - 2;
4478
		htSpeed = ui_sportwatcherWidgetBase.grSpeed->height();
4479
		pmSpeed = QPixmap(wdSpeed, htSpeed);
4480
		// Initialize QPainter
4481
		ptHR.begin(&pmHR);
4482
		ptElevation.begin(&pmElevation);
4483
		ptSpeed.begin(&pmSpeed);
280 andreas 4484
	}
314 andreas 4485
	else if(ActivePrint && pw > 0 && ph > 0)
280 andreas 4486
	{
314 andreas 4487
		wdHR = wdElev = wdSpeed = pw;
4488
		htHR = htElev = htSpeed = ph;
4489
		prHR = prElevation = prSpeed = QPixmap(pw, ph);
4490
		ptHR.begin(&prHR);
4491
		ptElevation.begin(&prElevation);
4492
		ptSpeed.begin(&prSpeed);
280 andreas 4493
	}
4494
	else
314 andreas 4495
		return;
250 andreas 4496
 
4497
	// we need a somewhat bigger area to draw our curves than
4498
	// we have with the real min and max values.
314 andreas 4499
	if(max_height > 0.0)
250 andreas 4500
	{
314 andreas 4501
		double add = (max_height - min_height) / 100.0 * 5.0;	// Percent
250 andreas 4502
 
314 andreas 4503
		maxHeight = max_height + add;
4504
		minHeight = min_height - add;
250 andreas 4505
 
314 andreas 4506
		if(minHeight < 0.0)		// make sure, we are not too deep
4507
			minHeight = 0.0;
250 andreas 4508
	}
4509
	else
314 andreas 4510
		maxHeight = minHeight = 0.0;
250 andreas 4511
 
314 andreas 4512
	if(max_speed > 0.0)
250 andreas 4513
	{
314 andreas 4514
		double add = (max_speed - min_speed) / 100.0 * 5.0;	// Percent
250 andreas 4515
 
314 andreas 4516
		maxSpeed = max_speed + add;
4517
		minSpeed = min_speed - add;
250 andreas 4518
 
314 andreas 4519
		if(minSpeed < 0.0)		// make sure, we are not too deep
4520
			minSpeed = 0.0;
250 andreas 4521
	}
4522
	else
314 andreas 4523
		maxSpeed = minSpeed = 0.0;
250 andreas 4524
 
314 andreas 4525
	if(max_hr > 0)
250 andreas 4526
	{
314 andreas 4527
		maxHr = max_hr + 10;
4528
		minHr = min_hr - 10;
250 andreas 4529
 
314 andreas 4530
		if(minHr < 0)
4531
			minHr = 0;
250 andreas 4532
	}
4533
	else
314 andreas 4534
		maxHr = minHr = 0;
250 andreas 4535
 
4536
	// Define colors
4537
	QColor background(220, 220, 220);	// Background of graphic
4538
	QColor mark(255, 255, 255);		// Lines inside curve area
4539
	QColor hlight(180, 180, 180);		// area of current lap
4540
	hlight.setAlpha(128);			// 50% transparent
4541
	QColor frame(0, 0, 0);			// Text and borders
4542
	QColor barcol(151, 190, 13);		// heart rate
4543
	QColor barcol2(190, 151, 13);		// height over NN
4544
	QColor red(220, 128, 128);		// speed
4545
	QColor blue(0, 0, 240);
4546
	QFont fntNormal("Helvetica");
4547
//	QFont fntBold("Helvetica", 10, QFont::Bold);
4548
	fntNormal.setPixelSize(10);
4549
	fntNormal.setStyleHint(QFont::Helvetica);
4550
//	fntBold.setPixelSize(10);
4551
//	fntBold.setStyleHint(QFont::Helvetica);
4552
	// Calculate ticks
4553
	margin_left = 1;
4554
	margin_right = 40;
4555
	margin_bottom = 12;
4556
	lineHeight = 10;
4557
//	rh = height - margin_bottom - 1;
4558
 
4559
	// Calculate the ticks for width and height for every draw area
314 andreas 4560
	for(i = 0; i < 3; i++)
250 andreas 4561
	{
314 andreas 4562
		if(i == 2)	// Speed?
4563
		{
4564
			rhSpeed = htSpeed - margin_bottom - 1;
4565
			wtiSpeed = (double)(wdSpeed - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
4566
			htiSpeed = (double)rhSpeed / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
4567
		}
4568
		else if(i == 1)	// Elevation?
4569
		{
4570
			rhElev = htElev - margin_bottom - 1;
4571
			wtiElev = (double)(wdElev - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
4572
			htiElev = (double)rhElev / (maxHeight - minHeight);		// 1 tick = 1 meter
4573
		}
4574
		else			// heart rate
4575
		{
4576
			rhHR = htHR - margin_bottom - 1;
4577
			wtiHR = (double)(wdHR - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
4578
			htiHR = (double)rhHR / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
4579
		}
250 andreas 4580
	}
4581
 
4582
	// Fill background with background colors
4583
	ptHR.fillRect(0, 0, wdHR + 4, htHR + 4, background);
4584
	ptElevation.fillRect(0, 0, wdElev + 4, htElev + 4, background);
4585
	ptSpeed.fillRect(0, 0, wdSpeed + 4, htSpeed + 4, background);
4586
	// Draw a grid with markers at every 10 minutes
4587
	ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4588
	ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4589
	ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4590
	// Bottom border line
4591
	x1 = margin_left;
4592
 
4593
	y1 = htHR - margin_bottom;
4594
	x2 = wdHR - margin_right;
4595
	y2 = y1;
4596
	ptHR.drawLine(x1, y1, x2, y2);
4597
 
4598
	y1 = htElev - margin_bottom;
4599
	x2 = wdElev - margin_right;
4600
	y2 = y1;
4601
	ptElevation.drawLine(x1, y1, x2, y2);
4602
 
4603
	y1 = htSpeed - margin_bottom;
4604
	x2 = wdSpeed - margin_right;
4605
	y2 = y1;
4606
	ptSpeed.drawLine(x1, y1, x2, y2);
4607
 
4608
	// Left border line
4609
	x1 = x2 = margin_left;
4610
	y1 = 2;
4611
	y2 = htHR - margin_bottom;
4612
	ptHR.drawLine(x1, y1, x2, y2);
314 andreas 4613
 
250 andreas 4614
	y2 = htElev - margin_bottom;
4615
	ptElevation.drawLine(x1, y1, x2, y2);
314 andreas 4616
 
250 andreas 4617
	y2 = htSpeed - margin_bottom;
4618
	ptSpeed.drawLine(x1, y1, x2, y2);
314 andreas 4619
 
250 andreas 4620
	// right border line
4621
	x1 = x2 = wdHR - margin_right;
4622
	ptHR.drawLine(x1, y1, x2, y2);
4623
 
4624
	x1 = x2 = wdElev - margin_right;
4625
	ptElevation.drawLine(x1, y1, x2, y2);
4626
 
4627
	x1 = x2 = wdSpeed - margin_right;
4628
	ptSpeed.drawLine(x1, y1, x2, y2);
4629
 
4630
	// Draw some darker lines to show the laps, if we have one
4631
	QDateTime *qt;
4632
	QTime zeit = StartTime.time();
4633
	rn = ds.getRunNode();
4634
	ptHR.setPen(QPen(hlight, 1, Qt::SolidLine));
4635
	ptElevation.setPen(QPen(hlight, 1, Qt::SolidLine));
4636
	ptSpeed.setPen(QPen(hlight, 1, Qt::SolidLine));
4637
 
314 andreas 4638
	for(i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
250 andreas 4639
	{
314 andreas 4640
		if((lp = ds.getLap(i)) == NULL)
4641
			continue;
250 andreas 4642
 
314 andreas 4643
		qt = garmin_dtime(lp->start_time);
4644
		secs = zeit.secsTo(qt->time());
4645
		delete qt;
4646
		// heart rate
4647
		x1 = secs * wtiHR + margin_left + 1;
4648
		ptHR.drawLine(x1, 2, x1, htHR - margin_bottom);
4649
		// Elevation
4650
		x1 = secs * wtiElev + margin_left + 1;
4651
		ptElevation.drawLine(x1, 2, x1, htElev - margin_bottom);
4652
		// Speed
4653
		x1 = secs * wtiSpeed + margin_left + 1;
4654
		ptSpeed.drawLine(x1, 2, x1, htSpeed - margin_bottom);
250 andreas 4655
	}
4656
 
4657
	// Grid vertical
4658
	ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4659
	ptHR.setFont(fntNormal);
4660
	ptHR.drawText(margin_left, htHR - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));
314 andreas 4661
 
250 andreas 4662
	ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4663
	ptElevation.setFont(fntNormal);
4664
	ptElevation.drawText(margin_left, htElev - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));
314 andreas 4665
 
250 andreas 4666
	ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4667
	ptSpeed.setFont(fntNormal);
4668
	ptSpeed.drawText(margin_left, htSpeed - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));
314 andreas 4669
 
250 andreas 4670
	ptHR.save();
4671
	ptHR.rotate(270);
4672
	ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
4673
 
4674
	ptElevation.save();
4675
	ptElevation.rotate(270);
4676
	ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
314 andreas 4677
 
250 andreas 4678
	ptSpeed.save();
4679
	ptSpeed.rotate(270);
4680
	ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4681
 
4682
	// Information on right side
4683
	ptHR.drawText((htHR + 4) * -1, wdHR - 1 - lineHeight, htHR - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
283 andreas 4684
	ptElevation.drawText((htElev + 4) * -1, wdElev - 1 - lineHeight, htElev - 2, lineHeight, Qt::AlignCenter, i18n("Elevation (%1)").arg((Units == 1) ? "ft" : "m"));
4685
	ptSpeed.drawText((htSpeed + 4) * -1, wdSpeed - 1 - lineHeight, htSpeed - 2, lineHeight, Qt::AlignCenter, i18n("Speed (%1)").arg((Units == 1) ? "mph" : "km/h"));
250 andreas 4686
 
4687
	// restore to normal
4688
	ptHR.restore();
4689
	ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4690
 
4691
	ptElevation.restore();
4692
	ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4693
 
4694
	ptSpeed.restore();
4695
	ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
314 andreas 4696
 
250 andreas 4697
	// Draw the time scale on the bottom of the graphic
314 andreas 4698
	for(i = 0; (unsigned int)i < (max_time + ds.getPauseTime()); i++)
250 andreas 4699
	{
314 andreas 4700
		bool loop = false;
250 andreas 4701
 
314 andreas 4702
		if(i > 0 && !(i % 600))	// every 10 minutes
4703
		{
4704
			for(int j = 0; j < 3; j++)
4705
			{
4706
				switch(j)
4707
				{
4708
					case 0: w_tick = wtiHR; width = wdHR; height = htHR; break;
4709
					case 1: w_tick = wtiElev; width = wdElev; height = htElev; break;
4710
					case 2: w_tick = wtiSpeed; width = wdSpeed; height = htSpeed; break;
4711
				}
250 andreas 4712
 
314 andreas 4713
				x1 = x2 = margin_left + w_tick * i;
250 andreas 4714
 
314 andreas 4715
				if(x1 == (width - margin_right - 25))
4716
				{
4717
					loop = true;
4718
					break;
4719
				}
250 andreas 4720
 
314 andreas 4721
				y1 = 2;
4722
				y2 = height - margin_bottom;
4723
				QTime tm(0, 0, 0);
4724
				tm = tm.addSecs(i);
250 andreas 4725
 
314 andreas 4726
				if(j == 0)
4727
				{
4728
					ptHR.drawLine(x1, y1, x2, y2);
4729
					ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4730
					ptHR.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
4731
					ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4732
				}
4733
				else if(j == 1)
4734
				{
4735
					ptElevation.drawLine(x1, y1, x2, y2);
4736
					ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4737
					ptElevation.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
4738
					ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4739
				}
4740
				else
4741
				{
4742
					ptSpeed.drawLine(x1, y1, x2, y2);
4743
					ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4744
					ptSpeed.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
4745
					ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4746
				}
4747
			}
250 andreas 4748
 
314 andreas 4749
			if(loop)
4750
			{
4751
				loop = false;
4752
				continue;
4753
			}
4754
		}
250 andreas 4755
	}
4756
 
4757
	// This is the total time, with pauses included, at the lower right
4758
	// corner of the graphic.
4759
	QTime tm(0, 0, 0);
4760
	QString qs;
4761
	tm = tm.addSecs(max_time + ds.getPauseTime());
4762
	ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4763
	ptHR.drawText(wdHR - margin_right - 25, htHR - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
4764
 
4765
	ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4766
	ptElevation.drawText(wdElev - margin_right - 25, htElev - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
4767
 
4768
	ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4769
	ptSpeed.drawText(wdSpeed - margin_right - 25, htSpeed - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
4770
 
4771
	// Draw the minimal elevation, speed and heart rate
4772
	// Heart rate
4773
	ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
4774
	ptHR.drawText(wdHR - margin_right + 2, htHR - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
4775
	// Elevation
4776
	ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
4777
	ptElevation.drawText(wdElev - margin_right + 2, htElev - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", (Units == 1) ? minHeight / 0.304 : minHeight));
4778
	// Speed
4779
	ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4780
	ptSpeed.drawText(wdSpeed - margin_right + 2, htSpeed - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));
4781
 
4782
	ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4783
	ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4784
	ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4785
 
4786
	// Grid horizontal
4787
	int factor = 0;
4788
	int target = 0;
4789
 
314 andreas 4790
	for(int j = 0; j < 3; j++)
250 andreas 4791
	{
314 andreas 4792
		switch(j)
4793
		{
4794
			case 0: width = wdHR; height = htHR; w_tick = wtiHR; h_tick = htiHR; rh = rhHR;
4795
				factor = (maxHr - minHr) / (rhHR / 12);
4796
				target = (maxHr - minHr);
4797
				break;
250 andreas 4798
 
314 andreas 4799
			case 1: width = wdElev; height = htElev; w_tick = wtiElev; h_tick = htiElev; rh = rhElev;
4800
				factor = (maxHeight - minHeight) / (rhElev / 12);
4801
				target = (int)(maxHeight - minHeight);
4802
				break;
250 andreas 4803
 
314 andreas 4804
			case 2: width = wdSpeed; height = htSpeed; w_tick = wtiSpeed; h_tick = htiSpeed; rh = rhSpeed;
4805
				factor = (maxSpeed - minSpeed) / (rhSpeed / 12);
4806
				target = (int)(maxSpeed - minSpeed);
4807
				break;
4808
		}
250 andreas 4809
 
314 andreas 4810
		// To prevent a division by zero error, we check the <factor>
4811
		if(factor == 0)
4812
			factor = 1;
250 andreas 4813
 
314 andreas 4814
		// Beside the horizontal part of the grid, we draw the scale on the
4815
		// the right side too.
4816
		int oldy = height;
250 andreas 4817
 
314 andreas 4818
		for(i = 0; i < target; i++)
4819
		{
4820
			if(i > 0 && !(i % factor))
4821
			{
4822
				x1 = margin_left + 1;
4823
				x2 = width - margin_right - 1;
4824
				y1 = y2 = rh - h_tick * i;
250 andreas 4825
 
314 andreas 4826
				if(y1 < 12)
4827
					break;
250 andreas 4828
 
314 andreas 4829
				switch(j)
4830
				{
4831
					case 0:
4832
						ptHR.drawLine(x1, y1, x2, y2);
4833
						ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
4834
						ptHR.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
4835
						ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4836
						break;
250 andreas 4837
 
314 andreas 4838
					case 1:
4839
						ptElevation.drawLine(x1, y1, x2, y2);
4840
						ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
4841
						ptElevation.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));
4842
						ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4843
						break;
250 andreas 4844
 
314 andreas 4845
					case 2:
4846
						ptSpeed.drawLine(x1, y1, x2, y2);
4847
						ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4848
						ptSpeed.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
4849
						ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4850
						break;
4851
				}
250 andreas 4852
 
314 andreas 4853
				oldy = y1;
4854
			}
4855
		}
250 andreas 4856
	}
4857
 
4858
	// To make our graphics more beautiful, we draw lines for the
4859
	// heart rate limits and the average heart rate.
314 andreas 4860
	if(max_hr > 0)
250 andreas 4861
	{
314 andreas 4862
		int ay1, ay2, ay3, ay4, ay5;
250 andreas 4863
 
314 andreas 4864
		x1 = margin_left + 1;
4865
		x2 = wdHR - margin_right - 1;
250 andreas 4866
 
314 andreas 4867
		ay1 = (double)rh - (double)(lower1 - minHr) * htiHR;
4868
		ay2 = (double)rh - (double)(lower2 - minHr) * htiHR;
4869
		ay3 = (double)rh - (double)(lower3 - minHr) * htiHR;
4870
		ay4 = (double)rh - (double)(upper3 - minHr) * htiHR;
4871
		ay5 = (double)rh - (double)(avg_hr - minHr) * htiHR;
250 andreas 4872
 
314 andreas 4873
		ptHR.setPen(QPen(barcol2, 1, Qt::DashLine));	// color for limits
250 andreas 4874
 
314 andreas 4875
		if(lower1 > minHr && lower1 < maxHr)
4876
			ptHR.drawLine(x1, ay1, x2, ay1);
250 andreas 4877
 
314 andreas 4878
		if(lower2 > minHr && lower2 < maxHr)
4879
			ptHR.drawLine(x1, ay2, x2, ay2);
250 andreas 4880
 
314 andreas 4881
		if(lower3 > minHr && lower3 < maxHr)
4882
			ptHR.drawLine(x1, ay3, x2, ay3);
250 andreas 4883
 
314 andreas 4884
		if(upper3 > minHr && upper3 < maxHr)
4885
			ptHR.drawLine(x1, ay4, x2, ay4);
250 andreas 4886
 
314 andreas 4887
		ptHR.setPen(QPen(red, 1, Qt::DashDotLine));	// color for average heart rate
250 andreas 4888
 
314 andreas 4889
		if(avg_hr > minHr && avg_hr < maxHr)
4890
			ptHR.drawLine(x1, ay5, x2, ay5);
250 andreas 4891
	}
4892
 
4893
	// Now we have a grid and we've done the scaling.
4894
	// This is the point where we draw the curves itself.
4895
	// We use different colors to draw the lines:
4896
	//
4897
	// Green: Elevation
4898
	// Red:   Speed
4899
	// Blue   Heart Rate
4900
	//
4901
	x1 = x2 = y1 = y2 = 0;
4902
	int hy1, hy2, hx1, hx2;
4903
	int sy1, sy2, sx1, sx2;
4904
	hy1 = hy2 = hx1 = hx2 = 0;
4905
	sy1 = sy2 = sx1 = sx2 = 0;
4906
	int hEc = 0;
4907
	i = 0;
4908
	AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
4909
	avgHfirst = avgHlast = 0;
314 andreas 4910
 
250 andreas 4911
	// To even the surface lines, we store every altitude in the
4912
	// memory, by building a chain. Then, if the user has set in the
4913
	// settings (Contour == true), we will even the line by calculating
4914
	// the average of 10 messure points and setting every value to the
4915
	// average, who is up or down more than 2 meters from the average.
314 andreas 4916
	while((point = ds.getPoint(i)) != 0)
250 andreas 4917
	{
314 andreas 4918
		if(point->alt > 20000.0 || point->alt < -1000.0)
4919
		{
4920
			i++;
4921
			continue;
4922
		}
250 andreas 4923
 
314 andreas 4924
		if(!avgHeight)
4925
		{
4926
			avgHeight = new AVGHEIGHT;
4927
			avgHeight->alt = point->alt;
4928
			avgHeight->pos = hEc;
4929
			avgHeight->prev = 0;
4930
			avgHeight->next = 0;
4931
			avgHakt = avgHeight;
4932
			avgHfirst = avgHeight;
4933
		}
4934
		else
4935
		{
4936
			avgHakt = new AVGHEIGHT;
4937
			avgHakt->alt = point->alt;
4938
			avgHakt->pos = hEc;
4939
			avgHakt->next = 0;
4940
			avgHakt->prev = avgHeight;
4941
			avgHeight->next = avgHakt;
4942
			avgHeight = avgHakt;
4943
		}
250 andreas 4944
 
314 andreas 4945
		// FIXME: Currently we can not draw below 0 meters, because the
4946
		// base line is always 0!
4947
		if(avgHakt->alt < minHeight)
4948
			avgHakt->alt = minHeight;
250 andreas 4949
 
314 andreas 4950
		hEc++;
4951
		i++;
250 andreas 4952
	}
4953
 
4954
	avgHlast = avgHeight;
314 andreas 4955
 
250 andreas 4956
	// If wanted, even the lines
314 andreas 4957
	if(Contour && hEc > 0)
250 andreas 4958
	{
314 andreas 4959
		double alt[100], avg, avg1, avg2, avg3, avg4;
4960
		int a, pos;
250 andreas 4961
 
314 andreas 4962
		for(i = 0; i < (hEc + 100); i += 100)
4963
		{
4964
			avg = avg1 = avg2 = avg3 = avg4 = 0.0;
4965
			pos = 0;
250 andreas 4966
 
314 andreas 4967
			for(a = 0; a < 100; a++)
4968
			{
4969
				alt[a] = getAvgAlt(avgHfirst, i + a);
4970
				avg += alt[a];
250 andreas 4971
 
314 andreas 4972
				if(a < 25)
4973
					avg1 += alt[a];
4974
				else if(a < 50)
4975
					avg2 += alt[a];
4976
				else if(a < 75)
4977
					avg3 += alt[a];
4978
				else
4979
					avg4 += alt[a];
4980
			}
250 andreas 4981
 
314 andreas 4982
			if((i + 100) >= hEc)
4983
				avg /= (double)(hEc - i) + 1.0;
4984
			else
4985
				avg /= 100.0;
250 andreas 4986
 
314 andreas 4987
			for(a = 0; a < 100; a++)
4988
			{
4989
				if((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
4990
				{
4991
					if((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
4992
						avgHakt->alt = avg;
4993
				}
4994
			}
4995
		}
250 andreas 4996
	}
4997
 
4998
	// plot the elevation, speed and/or heart rate. Depends on <cuType>)
4999
	i = 0;
5000
	int j = 0;
5001
	POINT *oldPoint = 0;
5002
	double speed = 0.0;	// calculated speed
5003
	bool pause = false;	// filter pause out of speed
5004
	unsigned long t1, t2;
5005
	t1 = t2 = 0;
314 andreas 5006
 
5007
	while((point = ds.getPoint(i)) != 0)
250 andreas 5008
	{
314 andreas 5009
		bool loop = false;
250 andreas 5010
 
314 andreas 5011
		if(!oldPoint)
5012
			oldPoint = point;
250 andreas 5013
 
314 andreas 5014
		// calculate the y position based on the time
5015
		qt = garmin_dtime(point->time);
5016
		secs = zeit.secsTo(qt->time());
5017
		delete qt;
250 andreas 5018
 
314 andreas 5019
		for(int c = 0; c < 3; c++)
5020
		{
5021
			if(c == 0)
5022
			{
5023
				x2 = secs * wtiHR + margin_left + 1;
5024
				hx2 = x2;
5025
				sx2 = x2;
250 andreas 5026
 
314 andreas 5027
				if(x1 == 0)
5028
					x1 = x2;
250 andreas 5029
 
314 andreas 5030
				if(hx1 == 0)
5031
					hx1 = hx2;
250 andreas 5032
 
314 andreas 5033
				if(sx1 == 0)
5034
					sx1 = sx2;
5035
			}
5036
			else if(c == 1)
5037
			{
5038
				x2 = secs * wtiElev + margin_left + 1;
5039
				hx2 = x2;
5040
				sx2 = x2;
250 andreas 5041
 
314 andreas 5042
				if(x1 == 0)
5043
					x1 = x2;
250 andreas 5044
 
314 andreas 5045
				if(hx1 == 0)
5046
					hx1 = hx2;
250 andreas 5047
 
314 andreas 5048
				if(sx1 == 0)
5049
					sx1 = sx2;
5050
			}
5051
			else
5052
			{
5053
				x2 = secs * wtiSpeed + margin_left + 1;
5054
				hx2 = x2;
5055
				sx2 = x2;
250 andreas 5056
 
314 andreas 5057
				if(x1 == 0)
5058
					x1 = x2;
250 andreas 5059
 
314 andreas 5060
				if(hx1 == 0)
5061
					hx1 = hx2;
250 andreas 5062
 
314 andreas 5063
				if(sx1 == 0)
5064
					sx1 = sx2;
5065
			}
250 andreas 5066
 
314 andreas 5067
			// The speed is not very exact, because smallest time is
5068
			// one second. This allows a maximum error of 99 hundredths
5069
			// of a second, what is very close to one second. Because of
5070
			// this, speed seems to hop for every messure point. This
5071
			// looks ugly, but currently I don't know how to make it
5072
			// better.
5073
			if(c == 2)	// Draw speed?
5074
			{
5075
				double dist;
5076
				double sc;
250 andreas 5077
 
314 andreas 5078
				if(!pause && point->distance > 1.0e10)
5079
				{
5080
					pause = true;
5081
					t1 = point->time;
5082
				}
5083
				else if(pause)
5084
				{
5085
					pause = false;
5086
					t2 = point->time;
5087
					i += 2;
5088
					loop = true;
5089
				}
250 andreas 5090
 
314 andreas 5091
				if(point->distance >= 0.1 && point->distance < 1.0e10)
5092
				{
5093
					dist = point->distance - oldPoint->distance;
5094
					sc = point->time - oldPoint->time;
5095
					LAP *runde = ds.getLapT(point->time);
250 andreas 5096
 
314 andreas 5097
					if(t2 > t1)
5098
					{
5099
						sc -= t2 - t1;
250 andreas 5100
 
314 andreas 5101
						if(sc <= 0.0)
5102
							sc = 1.0;		// at least 1 second!
5103
					}
250 andreas 5104
 
314 andreas 5105
					speed = (dist / sc) * 3.6;
250 andreas 5106
 
314 andreas 5107
					if(runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
5108
						speed = runde->max_speed * 3.6;
250 andreas 5109
 
314 andreas 5110
					if(Units == 1)
5111
						speed /= 1.609344;
250 andreas 5112
 
314 andreas 5113
					if(speed < minSpeed || speed > 400.0)
5114
						speed = minSpeed;
250 andreas 5115
 
314 andreas 5116
					y2 = (double)rh - (speed - minSpeed) * htiSpeed;
250 andreas 5117
 
314 andreas 5118
					if(y1 == 0)
5119
						y1 = y2;
250 andreas 5120
 
314 andreas 5121
					ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
5122
					ptSpeed.drawLine(x1, y1, x2, y2);
5123
					y1 = y2;
5124
					x1 = x2;
5125
					t1 = t2 = 0;
5126
					oldPoint = point;
5127
				}
5128
			}
250 andreas 5129
 
314 andreas 5130
			if(c == 1)		// Draw elevation?
5131
			{
5132
				if(point->alt < 20000.0 && point->alt > -1000.0)
5133
				{
5134
					double alt = getAvgAlt(avgHfirst, j);
250 andreas 5135
 
314 andreas 5136
					j++;
250 andreas 5137
 
314 andreas 5138
					sy2 = (double)rh - (alt - minHeight) * htiElev;
250 andreas 5139
 
314 andreas 5140
					if(sy1 == 0)
5141
						sy1 = sy2;
250 andreas 5142
 
314 andreas 5143
					ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
5144
					ptElevation.drawLine(sx1, sy1, sx2, sy2);
5145
					sy1 = sy2;
5146
					sx1 = sx2;
5147
				}
5148
			}
250 andreas 5149
 
314 andreas 5150
			if(point->heart_rate > 0 && c == 0)	// Draw heart rate?
5151
			{
5152
				hy2 = (double)rh - (double)(point->heart_rate - minHr) * htiHR;
250 andreas 5153
 
314 andreas 5154
				if(hy1 == 0)
5155
					hy1 = hy2;
250 andreas 5156
 
314 andreas 5157
				ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
5158
				ptHR.drawLine(hx1, hy1, hx2, hy2);
5159
				hy1 = hy2;
5160
				hx1 = hx2;
5161
			}
5162
		}
250 andreas 5163
 
314 andreas 5164
		if(loop)
5165
		{
5166
			loop = false;
5167
			continue;
5168
		}
5169
 
5170
		i++;
250 andreas 5171
	}
5172
 
5173
	ptHR.end();
5174
	ptElevation.end();
5175
	ptSpeed.end();
5176
 
314 andreas 5177
	if(!ActivePrint)
280 andreas 5178
	{
314 andreas 5179
		ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5180
		ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5181
		ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
280 andreas 5182
	}
314 andreas 5183
 
250 andreas 5184
	// free the chain of altitudes
5185
	avgHakt = avgHfirst;
5186
 
314 andreas 5187
	while(avgHakt)
250 andreas 5188
	{
314 andreas 5189
		avgHeight = avgHakt->next;
5190
		delete avgHakt;
5191
		avgHakt = avgHeight;
250 andreas 5192
	}
5193
 
5194
	DIRTY = false;
5195
}
5196
 
169 andreas 5197
double sportwatcherWidget::getAvgAlt(AVGHEIGHT *avgHeight, int pos)
5198
{
314 andreas 5199
	AVGHEIGHT *akt;
169 andreas 5200
 
314 andreas 5201
	if(!avgHeight)
5202
		return 0.0;
170 andreas 5203
 
169 andreas 5204
	akt = avgHeight;
5205
 
314 andreas 5206
	while(akt)
169 andreas 5207
	{
314 andreas 5208
		if(akt->pos == pos)
5209
			return akt->alt;
169 andreas 5210
 
314 andreas 5211
		akt = akt->next;
169 andreas 5212
	}
5213
 
5214
	return 0.0;
5215
}
5216
 
5217
AVGHEIGHT *sportwatcherWidget::getAvgPtr(AVGHEIGHT *avgHeight, int pos)
5218
{
314 andreas 5219
	AVGHEIGHT *akt;
169 andreas 5220
 
5221
	akt = avgHeight;
5222
 
314 andreas 5223
	while(akt)
169 andreas 5224
	{
314 andreas 5225
		if(akt->pos == pos)
5226
			return akt;
169 andreas 5227
 
314 andreas 5228
		akt = akt->next;
169 andreas 5229
	}
5230
 
5231
	return 0;
5232
}
5233
 
246 andreas 5234
void sportwatcherWidget::resizeEvent(QResizeEvent *e)
88 andreas 5235
{
314 andreas 5236
	if(e->size() != e->oldSize())
5237
		DIRTY = true;
246 andreas 5238
 
132 andreas 5239
	showTrack(zfactor);
88 andreas 5240
	showCurves();
250 andreas 5241
	tabDirt2 = true;
5242
 
314 andreas 5243
	if(curTab == 2)
250 andreas 5244
	{
314 andreas 5245
		showThreeCurve();
5246
		tabDirt2 = false;
250 andreas 5247
	}
5248
 
314 andreas 5249
	DIRTY = false;
88 andreas 5250
}
5251
 
132 andreas 5252
void sportwatcherWidget::mouseMoveEvent(QMouseEvent *e)
5253
{
314 andreas 5254
	QPoint pos(0, 0);
5255
	QPoint ev = ui_sportwatcherWidgetBase.imgMap->mapFrom(this, e->pos());
5256
	static QRect coord;
88 andreas 5257
 
314 andreas 5258
	DIRTY = true;
246 andreas 5259
 
314 andreas 5260
	if(curTab == 0)
132 andreas 5261
	{
314 andreas 5262
		if(!stateHand)
5263
			return;
250 andreas 5264
 
314 andreas 5265
		if(ev.x() >= pos.x() &&
5266
		                  ev.y() >= pos.y() &&
5267
		                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.imgMap->geometry().width()) &&
5268
		                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.imgMap->geometry().height()))
5269
		{
5270
			if(lmbPressed == 1)
5271
			{
5272
				coord.setCoords(ev.x(), ev.y(), 0, 0);
5273
				lmbPressed = 0;
5274
			}
5275
			else
5276
			{
5277
				coord.setRight(ev.x());
5278
				coord.setBottom(ev.y());
5279
			}
250 andreas 5280
 
314 andreas 5281
			if(lmbPressed == 2)
5282
			{
5283
				showTrack(zfactor, coord, mapLap);
5284
				lmbPressed = 0;
5285
			}
5286
		}
250 andreas 5287
	}
5288
 
314 andreas 5289
	if(curTab == 2)
250 andreas 5290
	{
314 andreas 5291
		// look in which of the three QLabels the mouse is, if it is in
5292
		// one of them.
5293
		ev = ui_sportwatcherWidgetBase.grHR->mapFrom(this, e->pos());
250 andreas 5294
 
314 andreas 5295
		if(ev.x() >= pos.x() &&
5296
		                  ev.y() >= pos.y() &&
5297
		                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grHR->geometry().width()) &&
5298
		                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grHR->geometry().height()))
5299
		{
5300
			drawGrHR(ev.x(), ev.y());
5301
			drawGrElev(ev.x(), -1);
5302
			drawGrSpeed(ev.x(), -1);
5303
		}
132 andreas 5304
 
314 andreas 5305
		ev = ui_sportwatcherWidgetBase.grElevation->mapFrom(this, e->pos());
250 andreas 5306
 
314 andreas 5307
		if(ev.x() >= pos.x() &&
5308
		                  ev.y() >= pos.y() &&
5309
		                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grElevation->geometry().width()) &&
5310
		                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grElevation->geometry().height()))
5311
		{
5312
			drawGrHR(ev.x(), -1);
5313
			drawGrElev(ev.x(), ev.y());
5314
			drawGrSpeed(ev.x(), -1);
5315
		}
250 andreas 5316
 
314 andreas 5317
		ev = ui_sportwatcherWidgetBase.grSpeed->mapFrom(this, e->pos());
250 andreas 5318
 
314 andreas 5319
		if(ev.x() >= pos.x() &&
5320
		                  ev.y() >= pos.y() &&
5321
		                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grSpeed->geometry().width()) &&
5322
		                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grSpeed->geometry().height()))
5323
		{
5324
			drawGrHR(ev.x(), -1);
5325
			drawGrElev(ev.x(), -1);
5326
			drawGrSpeed(ev.x(), ev.y());
5327
		}
132 andreas 5328
	}
246 andreas 5329
 
314 andreas 5330
	DIRTY = false;
132 andreas 5331
}
5332
 
5333
void sportwatcherWidget::mousePressEvent(QMouseEvent *e)
5334
{
314 andreas 5335
	if(stateHand && e->button() == Qt::LeftButton)
5336
		lmbPressed = 1;	// Left Mouse Button is pressed
5337
	else if(stateHand)
5338
		lmbPressed = 0;	// Wrong button is pressed
132 andreas 5339
 
314 andreas 5340
	if(stateGlas)
132 andreas 5341
	{
314 andreas 5342
		if(e->button() == Qt::LeftButton)
5343
			btGlasPlusSlot();
5344
		else if(e->button() == Qt::RightButton)
5345
			btGlasMinusSlot();
132 andreas 5346
	}
5347
}
5348
 
5349
void sportwatcherWidget::mouseReleaseEvent(QMouseEvent *e)
5350
{
314 andreas 5351
	if(stateHand && e->button() == Qt::LeftButton)
132 andreas 5352
	{
314 andreas 5353
		lmbPressed = 2;	// Left Mouse Button was released
5354
		mouseMoveEvent(e);
132 andreas 5355
	}
5356
}
5357
 
88 andreas 5358
/*
250 andreas 5359
 * Private functions to draw cross and/or a bar to reflect the mouse
5360
 * pointer on tab 2.
5361
 */
314 andreas 5362
void sportwatcherWidget::drawGrHR(int x, int y)
250 andreas 5363
{
314 andreas 5364
	int width, height;
5365
	QPixmap pm = pmHR.copy(pmHR.rect());
5366
	QPainter paint;
250 andreas 5367
 
5368
	width = ui_sportwatcherWidgetBase.grHR->width();
5369
	height = ui_sportwatcherWidgetBase.grHR->height();
5370
	ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5371
 
314 andreas 5372
	if(x > (width - 40) || y > (height - 12) || x < 1)
250 andreas 5373
	{
314 andreas 5374
		ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5375
		ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5376
		return;
250 andreas 5377
	}
5378
 
314 andreas 5379
	if(tabDirt2)
250 andreas 5380
	{
314 andreas 5381
		DIRTY = true;
5382
		showThreeCurve();
5383
		tabDirt2 = false;
5384
		DIRTY = false;
250 andreas 5385
	}
5386
 
5387
	paint.begin(&pm);
5388
	QColor black(0, 0, 0);
314 andreas 5389
	black.setAlpha(128);
250 andreas 5390
	paint.setPen(QPen(black, 1, Qt::SolidLine));
314 andreas 5391
 
250 andreas 5392
	// horizontal line, if y != -1
314 andreas 5393
	if(y >= 0)
5394
		paint.drawLine(2, y, width - 41, y);
250 andreas 5395
 
5396
	// vertical line
5397
	paint.drawLine(x, 1, x, height - 13);
5398
	paint.end();
5399
	ui_sportwatcherWidgetBase.grHR->setPixmap(pm);
5400
}
5401
 
314 andreas 5402
void sportwatcherWidget::drawGrElev(int x, int y)
250 andreas 5403
{
314 andreas 5404
	int width, height;
5405
	QPixmap pm = pmElevation.copy(pmElevation.rect());
5406
	QPainter paint;
250 andreas 5407
 
5408
	width = ui_sportwatcherWidgetBase.grElevation->width();
5409
	height = ui_sportwatcherWidgetBase.grElevation->height();
5410
	ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5411
 
314 andreas 5412
	if(x > (width - 40) || y > (height - 12) || x < 1)
250 andreas 5413
	{
314 andreas 5414
		ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5415
		ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5416
		return;
250 andreas 5417
	}
5418
 
314 andreas 5419
	if(tabDirt2)
250 andreas 5420
	{
314 andreas 5421
		DIRTY = true;
5422
		showThreeCurve();
5423
		tabDirt2 = false;
5424
		DIRTY = false;
250 andreas 5425
	}
5426
 
5427
	paint.begin(&pm);
5428
	QColor black(0, 0, 0);
314 andreas 5429
	black.setAlpha(128);
250 andreas 5430
	paint.setPen(QPen(black, 1, Qt::SolidLine));
314 andreas 5431
 
250 andreas 5432
	// horizontal line, if y != -1
314 andreas 5433
	if(y >= 0)
5434
		paint.drawLine(2, y, width - 41, y);
250 andreas 5435
 
5436
	// vertical line
5437
	paint.drawLine(x, 1, x, height - 13);
5438
	paint.end();
5439
	ui_sportwatcherWidgetBase.grElevation->setPixmap(pm);
5440
}
5441
 
314 andreas 5442
void sportwatcherWidget::drawGrSpeed(int x, int y)
250 andreas 5443
{
314 andreas 5444
	int width, height;
5445
	QPixmap pm = pmSpeed.copy(pmSpeed.rect());
5446
	QPainter paint;
250 andreas 5447
 
5448
	width = ui_sportwatcherWidgetBase.grSpeed->width();
5449
	height = ui_sportwatcherWidgetBase.grSpeed->height();
5450
	ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5451
 
314 andreas 5452
	if(x > (width - 40) || y > (height - 12) || x < 1)
250 andreas 5453
	{
314 andreas 5454
		ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5455
		ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5456
		return;
250 andreas 5457
	}
5458
 
314 andreas 5459
	if(tabDirt2)
250 andreas 5460
	{
314 andreas 5461
		DIRTY = true;
5462
		showThreeCurve();
5463
		tabDirt2 = false;
5464
		DIRTY = false;
250 andreas 5465
	}
5466
 
5467
	paint.begin(&pm);
5468
	QColor black(0, 0, 0);
314 andreas 5469
	black.setAlpha(128);
250 andreas 5470
	paint.setPen(QPen(black, 1, Qt::SolidLine));
314 andreas 5471
 
250 andreas 5472
	// horizontal line, if y != -1
314 andreas 5473
	if(y >= 0)
5474
		paint.drawLine(2, y, width - 41, y);
250 andreas 5475
 
5476
	// vertical line
5477
	paint.drawLine(x, 1, x, height - 13);
5478
	paint.end();
5479
	ui_sportwatcherWidgetBase.grSpeed->setPixmap(pm);
5480
}
5481
 
5482
/*
88 andreas 5483
 * Private functions to help decode the data
5484
 */
314 andreas 5485
QDateTime *sportwatcherWidget::garmin_dtime(uint32 t)
88 andreas 5486
{
314 andreas 5487
	time_t     tval;
5488
	struct tm  tmval;
5489
	QTime ti;
5490
	QDate dt;
5491
	QDateTime *qt;
88 andreas 5492
 
314 andreas 5493
	if(t == 0)
5494
		return new QDateTime(QDate(1900, 1, 1), QTime(0, 0, 0, 0));
88 andreas 5495
 
5496
	tval = t + TIME_OFFSET;
314 andreas 5497
	localtime_r(&tval, &tmval);
88 andreas 5498
	qt = new QDateTime();
314 andreas 5499
	qt->setDate(QDate(tmval.tm_year + 1900, tmval.tm_mon + 1, tmval.tm_mday));
88 andreas 5500
	qt->setTime(QTime(tmval.tm_hour, tmval.tm_min, tmval.tm_sec, 0));
5501
	/* OK.  Done. */
5502
	return qt;
5503
}
5504
 
104 andreas 5505
bool sportwatcherWidget::writeTag(const QFile &fn, const QString &str, int indent)
5506
{
314 andreas 5507
	QString qs;
5508
	char *p;
232 andreas 5509
//QCString qcs;
314 andreas 5510
	int i;
88 andreas 5511
 
314 andreas 5512
	if(indent > 0)
5513
		qs.fill(' ', indent * 3);
171 andreas 5514
 
104 andreas 5515
	qs.append(str);
232 andreas 5516
//	qcs = qs.utf8();
5517
//	qstrcpy(p, qcs);
314 andreas 5518
	p = strdup(qs.toUtf8().data());
104 andreas 5519
	i = strlen(p);
5520
 
314 andreas 5521
	if(write(fn.handle(), p, i) != i)
104 andreas 5522
	{
314 andreas 5523
		free(p);
5524
		return false;
104 andreas 5525
	}
5526
 
314 andreas 5527
	free(p);
104 andreas 5528
	return true;
5529
}
5530
 
232 andreas 5531
#if defined HAVE_GDAL
151 andreas 5532
bool sportwatcherWidget::writeWMSTag(double llat, double llon, double rlat, double rlon, int width, int height)
5533
{
314 andreas 5534
	QFile fl(MAP);
5535
	QString xml, s, srs, crs, styles, bSize, ext;
5536
	QDir dir = QDir::home();
5537
	QString path = dir.absolutePath();
5538
	int item, isrs;
5539
	double _llat, _llon, _rlat, _rlon;
5540
	bool offline, square;
151 andreas 5541
 
314 andreas 5542
	if(!fl.open(QIODevice::ReadWrite | QIODevice::Truncate))
151 andreas 5543
	{
314 andreas 5544
		KMessageBox::error(this, i18n("Error opening or creating the WMS tag file!\nPlease check file name and/or permissions."));
5545
		return false;
151 andreas 5546
	}
5547
 
314 andreas 5548
	KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
5549
	KConfigGroup wms(&cfg, "WMS");
232 andreas 5550
	square = wms.readEntry("Square", false);
5551
	styles = wms.readEntry("Styles", QString(""));
152 andreas 5552
 
151 andreas 5553
	xml = "<GDAL_WMS>\n";
5554
	xml += "   <Service name=\"WMS\">\n";
5555
	xml += "      <Version>1.1.1</Version>\n";
232 andreas 5556
	xml += "      <ServerURL>" + wms.readEntry("ServerURL", "http://onearth.jpl.nasa.gov/wms.cgi") + "?</serverURL>\n";
5557
	isrs = wms.readEntry("SRS", 0);
157 andreas 5558
	_llon = llon;
5559
	_llat = llat;
5560
	_rlon = rlon;
5561
	_rlat = rlat;
5562
	offline = false;
152 andreas 5563
 
314 andreas 5564
	switch(isrs)
152 andreas 5565
	{
314 andreas 5566
		case 0: srs = QString("EPSG:4326"); break;
157 andreas 5567
 
314 andreas 5568
		case 1:
5569
			srs = QString("EPSG:31257");
5570
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31257, width, height, square);
5571
			break;
157 andreas 5572
 
314 andreas 5573
		case 2:
5574
			srs = QString("EPSG:31258");
5575
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31258, width, height, square);
5576
			break;
157 andreas 5577
 
314 andreas 5578
		case 3:
5579
			srs = QString("EPSG:31259");
5580
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31259, width, height, square);
5581
			break;
157 andreas 5582
 
314 andreas 5583
		case 4:
5584
			srs = QString("EPSG:31286");
5585
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31286, width, height, square);
5586
			break;
157 andreas 5587
 
314 andreas 5588
		case 5:
5589
			srs = QString("EPSG:31287");
5590
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31287, width, height, square);
5591
			break;
157 andreas 5592
 
314 andreas 5593
		case 6:
5594
			srs = QString("EPSG:31288");
5595
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31288, width, height, square);
5596
			break;
157 andreas 5597
 
314 andreas 5598
		case 7:
5599
			srs = QString("EPSG:900913");
5600
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 900913, width, height, square);
5601
			break;
299 andreas 5602
 
314 andreas 5603
		case 8:
5604
			srs = QString("EPSG:3395");
5605
			offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 3395, width, height, square);
5606
			break;
299 andreas 5607
 
314 andreas 5608
		default: srs = QString("EPSG:4326");
152 andreas 5609
	}
5610
 
5611
	xml += "      <SRS>" + srs + "</SRS>\n";
232 andreas 5612
	item = wms.readEntry("CRS", 0);
152 andreas 5613
 
314 andreas 5614
	switch(item)
152 andreas 5615
	{
314 andreas 5616
		case 0: crs = QString("CRS:83"); break;
5617
		case 1: crs = QString("CRS:84"); break;
5618
		case 2: crs = QString("EPSG:4326"); break;
5619
		case 3: crs = QString("EPSG:31259"); break;
5620
		case 4: crs = QString("EPSG:31287"); break;
5621
		case 5: crs = QString("EPSG:900913"); break;
5622
		case 6: crs = QString("EPSG:3395"); break;
5623
		default: crs = QString("CRS:84"); break;
152 andreas 5624
	}
5625
 
5626
	xml += "      <CRS>" + crs + "</CRS>\n";
232 andreas 5627
	item = wms.readEntry("Image", 2);
152 andreas 5628
	xml += "      <ImageFormat>image/";
5629
 
314 andreas 5630
	switch(item)
152 andreas 5631
	{
314 andreas 5632
		case 0: xml += "gif"; ext = QString(".gif"); break;
5633
		case 1: xml += "jpeg"; ext = QString(".jpg"); break;
5634
		case 2: xml += "png"; ext = QString(".png"); break;
5635
		case 3: xml += "tiff"; ext = QString(".tif"); break;
5636
		default: xml += "png"; ext = QString(".png");
152 andreas 5637
	}
5638
 
5639
	xml += "</ImageFormat>\n";
5640
 
232 andreas 5641
	xml += "      <Layers>" + wms.readEntry("Layer", QString("")) + "</Layers>\n";
152 andreas 5642
 
314 andreas 5643
	if(!styles.isEmpty())
5644
		xml += "      <Styles>" + styles + "</Styles>\n";
152 andreas 5645
 
151 andreas 5646
	xml += "      <BBoxOrder>xyXY</BBoxOrder>\n";
5647
	xml += "   </Service>\n";
5648
	xml += "   <DataWindow>\n";
314 andreas 5649
	s.sprintf("%f", _llat);
151 andreas 5650
	xml += "      <UpperLeftX>" + s + "</UpperLeftX>\n";
314 andreas 5651
	s.sprintf("%f", _llon);
151 andreas 5652
	xml += "      <UpperLeftY>" + s + "</UpperLeftY>\n";
314 andreas 5653
	s.sprintf("%f", _rlat);
151 andreas 5654
	xml += "      <LowerRightX>" + s + "</LowerRightX>\n";
314 andreas 5655
	s.sprintf("%f", _rlon);
151 andreas 5656
	xml += "      <LowerRightY>" + s + "</LowerRightY>\n";
314 andreas 5657
	s.sprintf("%d", width);
151 andreas 5658
	xml += "      <SizeX>" + s + "</SizeX>\n";
314 andreas 5659
	s.sprintf("%d", height);
151 andreas 5660
	xml += "      <SizeY>" + s + "</SizeY>\n";
5661
	xml += "   </DataWindow>\n";
157 andreas 5662
 
314 andreas 5663
	/*	switch (isrs)
5664
		{
5665
		   case 0: srs = QString("EPSG:4326"); break;
5666
		   case 1: srs = QString("EPSG:31259"); break;
5667
		   case 2: srs = QString("EPSG:31286"); break;
5668
		   case 3: srs = QString("EPSG:31287"); break;
5669
		   case 4: srs = QString("EPSG:31288"); break;
5670
		   default: srs = QString("EPSG:4326");
5671
		}
5672
	*/
157 andreas 5673
//	srs = QString("EPSG:4326");
299 andreas 5674
	xml += "   <Projection>" + crs + "</Projection>\n";
232 andreas 5675
	xml += "   <BandsCount>" + wms.readEntry("Bands", QString("3")) + "</BandsCount>\n";
5676
	item = wms.readEntry("Tile", 2);
152 andreas 5677
 
314 andreas 5678
	switch(item)
152 andreas 5679
	{
314 andreas 5680
		case 0: bSize = QString("64"); break;
5681
		case 1: bSize = QString("128"); break;
5682
		case 2: bSize = QString("256"); break;
5683
		case 3: bSize = QString("512"); break;
5684
		case 4: bSize = QString("1024"); break;
5685
		default: bSize = QString("256");
152 andreas 5686
	}
5687
 
5688
	xml += "   <BlockSizeX>" + bSize + "</BlockSizeX>\n";
5689
	xml += "   <BlockSizeY>" + bSize + "</BlockSizeY>\n";
232 andreas 5690
	xml += "   <OverviewCount>" + wms.readEntry("Overview", QString("10")) + "</OverviewCount>\n";
151 andreas 5691
	xml += "   <Cache>\n";
152 andreas 5692
	xml += "      <Path>" + path + "/.gdalwmscache" + "</Path>\n";
232 andreas 5693
	xml += "      <Depth>" + wms.readEntry("Depth", QString("2")) + "</Depth>\n";
152 andreas 5694
	xml += "      <Extension>" + ext + "</Extension>\n";
151 andreas 5695
	xml += "   </Cache>\n";
232 andreas 5696
	QString off((wms.readEntry("Offline", false)) ? "true" : "false");
5697
	QString adv((wms.readEntry("Advice", false)) ? "true" : "false");
5698
	QString ver((wms.readEntry("Verify", true)) ? "true" : "false");
157 andreas 5699
 
314 andreas 5700
	if(offline)
5701
		xml += "   <OfflineMode>true</OfflineMode>\n";
157 andreas 5702
	else
314 andreas 5703
		xml += "   <OfflineMode>" + off + "</OfflineMode>\n";
157 andreas 5704
 
152 andreas 5705
	xml += "   <AdviseRead>" + adv + "</AdviseRead>\n";
5706
	xml += "   <VerifyAdviseRead>" + ver + "</VerifyAdviseRead>\n";
151 andreas 5707
	xml += "</GDAL_WMS>\n";
5708
 
314 andreas 5709
	write(fl.handle(), xml.toAscii().data(), strlen(xml.toAscii().data()));
151 andreas 5710
	fl.close();
5711
	return true;
5712
}
5713
 
314 andreas 5714
bool sportwatcherWidget::transCoords(double *x1, double *y1, double *x2, double *y2, int code, int width, int height, bool square)
151 andreas 5715
{
314 andreas 5716
	OGRSpatialReference oSourceSRS, oTargetSRS;
5717
	OGRCoordinateTransformation *poCT;
157 andreas 5718
 
314 andreas 5719
	oSourceSRS.SetWellKnownGeogCS("WGS84");
157 andreas 5720
	oTargetSRS.importFromEPSG(code);
314 andreas 5721
	poCT = OGRCreateCoordinateTransformation(&oSourceSRS, &oTargetSRS);
157 andreas 5722
 
314 andreas 5723
	if(poCT == NULL || !poCT->Transform(1, x1, y1))
157 andreas 5724
	{
314 andreas 5725
		KMessageBox::error(this, i18n("Translation between coordinate systems failed!"));
157 andreas 5726
 
314 andreas 5727
		if(poCT != NULL)
5728
			delete poCT;
157 andreas 5729
 
314 andreas 5730
		return true;
157 andreas 5731
	}
5732
 
314 andreas 5733
	if(poCT != NULL)
157 andreas 5734
	{
314 andreas 5735
		poCT->Transform(1, x2, y2);
5736
		delete poCT;
157 andreas 5737
	}
5738
 
314 andreas 5739
	if(square)
157 andreas 5740
	{
314 andreas 5741
		double wdiff = (double)((long)(*x1 - *x2) / (width / 2 * 2) * (width / 2 * 2));
5742
		double hdiff = (double)((long)(*y2 - *y1) / (height / 2 * 2) * (height / 2 * 2));
157 andreas 5743
 
314 andreas 5744
		*x2 = *x1 - wdiff; // * (double)mFactor;
5745
		*y2 = *y1 + hdiff; // * (double)mFactor;
157 andreas 5746
//	   *x2 = *x1 - (double)((long)(wdiff / mFactor * mFactor));
5747
//	   *y2 = *y1 - (double)((long)(hdiff / mFactor * mFactor));
314 andreas 5748
		/*	   wdiff = wdiff - (*x1 - *x2);
5749
			   hdiff = hdiff - (*y2 - *y1);
5750
			   *x1 -= wdiff / 2.0;
5751
			   *x2 -= wdiff / 2.0;
5752
			   *y1 += hdiff / 2.0;
5753
			   *y2 += hdiff / 2.0; */
157 andreas 5754
	}
5755
 
5756
	return false;
151 andreas 5757
}
5758
 
314 andreas 5759
QString *sportwatcherWidget::getProjection(int isrs, QString *srs)
158 andreas 5760
{
314 andreas 5761
	switch(isrs)
158 andreas 5762
	{
314 andreas 5763
		case 0: *srs = QString("EPSG:4326"); break;
5764
		case 1: *srs = QString("EPSG:31257"); break;
5765
		case 2: *srs = QString("EPSG:31258"); break;
5766
		case 3: *srs = QString("EPSG:31259"); break;
5767
		case 4: *srs = QString("EPSG:31286"); break;
5768
		case 5: *srs = QString("EPSG:31287"); break;
5769
		case 6: *srs = QString("EPSG:31288"); break;
5770
		default: *srs = QString("EPSG:4326");
158 andreas 5771
	}
5772
 
5773
	return srs;
5774
}
5775
 
5776
bool sportwatcherWidget::warpImage(QString fn, QString *fName)
5777
{
314 andreas 5778
	GDALDatasetH  hSrcDS, hDstDS;
5779
	GDALDataset *inSet, *outSet;
5780
	GDALDataType eDT;
5781
	GDALRasterBand *poBand;
5782
	GDALDriverH hDriver;
5783
	char hv0[256];
5784
	int nXSize, nYSize;
5785
	double adfGeoTransform[6];
5786
	double oriLeftLon, oriRightLon, oriLeftLat, oriRightLat;
158 andreas 5787
 
159 andreas 5788
 
5789
	// Loading the user set geo coords of our source image and
5790
	// load the projection used for that image
314 andreas 5791
	KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
5792
	KConfigGroup ic(&cfg, "ImageCoords");
232 andreas 5793
	oriLeftLon = ic.readEntry("LeftLon", 0.0);
5794
	oriLeftLat = ic.readEntry("LeftLat", 0.0);
5795
	oriRightLon = ic.readEntry("RightLon", 0.0);
5796
	oriRightLat = ic.readEntry("RightLat", 0.0);
5797
	int isrs = ic.readEntry("SRS", 0);
159 andreas 5798
 
158 andreas 5799
	// Create a temporary file name for our output file
314 andreas 5800
	strcpy(hv0, "/tmp/SportWatcherTIFFXXXXXX");
5801
	mkdtemp(&hv0[0]);
158 andreas 5802
	*fName = QString(hv0) + ".tif";
5803
 
5804
	// Open input and output files.
314 andreas 5805
	if((hSrcDS = GDALOpen(fn.toAscii().data(), GA_ReadOnly)) == NULL)
158 andreas 5806
	{
314 andreas 5807
		KMessageBox::error(this, i18n("Error opening an image file!"));
5808
		return false;
158 andreas 5809
	}
5810
 
5811
	inSet = (GDALDataset *)hSrcDS;
5812
	// Create output with same datatype as first input band.
314 andreas 5813
	poBand = inSet->GetRasterBand(1);
5814
	eDT = poBand->GetRasterDataType();
158 andreas 5815
 
314 andreas 5816
	if((hDriver = GDALGetDriverByName("GTiff")) == NULL)
158 andreas 5817
	{
314 andreas 5818
		KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
5819
		GDALClose(hSrcDS);
5820
		return false;
158 andreas 5821
	}
5822
 
5823
	// Get dimensions of image and set transform data
5824
	int nRasterCount = inSet->GetRasterCount();
5825
	nXSize = inSet->GetRasterXSize();
5826
	nYSize = inSet->GetRasterYSize();
5827
 
159 andreas 5828
	// cut the wanted region out of image
314 andreas 5829
	transform *tf = new transform(oriLeftLat, oriLeftLon, oriRightLat, oriRightLon);
159 andreas 5830
	tf->setDimensions(nXSize, nYSize);
158 andreas 5831
 
314 andreas 5832
	if(!tf->cutImage(geoRect.llat, geoRect.llon, geoRect.rlat, geoRect.rlon, fn))
159 andreas 5833
	{
314 andreas 5834
		GDALClose(hSrcDS);
5835
		return false;
159 andreas 5836
	}
158 andreas 5837
 
314 andreas 5838
	GDALClose(hSrcDS);
159 andreas 5839
	QString nfn = fn + "_tmp.png";
158 andreas 5840
 
159 andreas 5841
	// repeat the part above and open the now cutted part of the image.
5842
	// Open input and output files.
314 andreas 5843
	if((hSrcDS = GDALOpen(nfn.toAscii().data(), GA_ReadOnly)) == NULL)
159 andreas 5844
	{
314 andreas 5845
		KMessageBox::error(this, i18n("Error opening an image file!"));
5846
		return false;
159 andreas 5847
	}
158 andreas 5848
 
159 andreas 5849
	inSet = (GDALDataset *)hSrcDS;
5850
	// Create output with same datatype as first input band.
314 andreas 5851
	poBand = inSet->GetRasterBand(1);
5852
	eDT = poBand->GetRasterDataType();
158 andreas 5853
 
314 andreas 5854
	if((hDriver = GDALGetDriverByName("GTiff")) == NULL)
158 andreas 5855
	{
314 andreas 5856
		KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
5857
		GDALClose(hSrcDS);
5858
		return false;
158 andreas 5859
	}
5860
 
159 andreas 5861
	// Get dimensions of image and set transform data
5862
	nRasterCount = inSet->GetRasterCount();
5863
	nXSize = inSet->GetRasterXSize();
5864
	nYSize = inSet->GetRasterYSize();
5865
 
158 andreas 5866
	// Set the values needed to transform the image
5867
	OGRSpatialReference iSRS;
5868
	const char *iWKT;
314 andreas 5869
 
5870
	switch(isrs)
158 andreas 5871
	{
314 andreas 5872
		case 0: iSRS.importFromEPSG(4326); break;
5873
		case 1: iSRS.importFromEPSG(31257); break;
5874
		case 2: iSRS.importFromEPSG(31258); break;
5875
		case 3: iSRS.importFromEPSG(31259); break;
5876
		case 4: iSRS.importFromEPSG(31286); break;
5877
		case 5: iSRS.importFromEPSG(31287); break;
5878
		case 6: iSRS.importFromEPSG(31288); break;
5879
		default: iSRS.importFromEPSG(4326);
158 andreas 5880
	}
5881
 
314 andreas 5882
	iSRS.exportToWkt((char **)&iWKT);
158 andreas 5883
 
314 andreas 5884
	if(inSet->SetProjection(iWKT) != CE_None)
158 andreas 5885
	{
314 andreas 5886
		KMessageBox::error(this, i18n("Error setting projection on source!"));
5887
		GDALClose(hSrcDS);
5888
		return false;
158 andreas 5889
	}
5890
 
159 andreas 5891
	adfGeoTransform[0] = geoRect.llon;
5892
	adfGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)nXSize;
158 andreas 5893
	adfGeoTransform[2] = 0.0;
159 andreas 5894
	adfGeoTransform[3] = geoRect.llat;
158 andreas 5895
	adfGeoTransform[4] = 0.0;
159 andreas 5896
	adfGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)nYSize);
158 andreas 5897
 
314 andreas 5898
	if(inSet->SetGeoTransform(&adfGeoTransform[0]) != CE_None)
158 andreas 5899
	{
314 andreas 5900
		KMessageBox::error(this, i18n("Error setting geo transform data to source!"));
5901
		GDALClose(hSrcDS);
5902
		return false;
158 andreas 5903
	}
5904
 
159 andreas 5905
	// Get Source coordinate system.
158 andreas 5906
	const char *pszSrcWKT, *pszDstWKT = NULL;
5907
 
314 andreas 5908
	if((pszSrcWKT = GDALGetProjectionRef(hSrcDS)) == NULL)
158 andreas 5909
	{
314 andreas 5910
		KMessageBox::error(this, i18n("Error getting the projection reference"));
5911
		GDALClose(hSrcDS);
5912
		return false;
158 andreas 5913
	}
5914
 
5915
	// Setup output coordinate system that is UTM ? WGS84.
5916
	OGRSpatialReference oSRS;
5917
 
159 andreas 5918
//	oSRS.SetUTM( 0, TRUE );
158 andreas 5919
	oSRS.SetWellKnownGeogCS("WGS84");
314 andreas 5920
	oSRS.exportToWkt((char **)&pszDstWKT);
158 andreas 5921
 
159 andreas 5922
	// Create the output file.
158 andreas 5923
	double adfDstGeoTransform[6];
159 andreas 5924
	adfDstGeoTransform[0] = geoRect.llon;
5925
	adfDstGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)geoRect.width;
158 andreas 5926
	adfDstGeoTransform[2] = 0.0;
5927
	adfDstGeoTransform[3] = geoRect.llat;
5928
	adfDstGeoTransform[4] = 0.0;
159 andreas 5929
	adfDstGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)geoRect.height);
158 andreas 5930
 
314 andreas 5931
	if((hDstDS = GDALCreate(hDriver, fName->toAscii().data(), geoRect.width, geoRect.height,
5932
	                        nRasterCount, eDT, NULL)) == NULL)
158 andreas 5933
	{
314 andreas 5934
		KMessageBox::error(this, i18n("Error creating a temporary image file! (%1)").arg(*fName));
5935
		GDALClose(hSrcDS);
5936
		return false;
158 andreas 5937
	}
5938
 
5939
	outSet = (GDALDataset *)hDstDS;
5940
 
314 andreas 5941
	for(int i = 0; i < nRasterCount; i++)
159 andreas 5942
	{
314 andreas 5943
		poBand = outSet->GetRasterBand(i + 1);
5944
		poBand->Fill(0.0);
159 andreas 5945
	}
5946
 
314 andreas 5947
	if(outSet->SetProjection(pszDstWKT) != CE_None)
158 andreas 5948
	{
314 andreas 5949
		KMessageBox::error(this, i18n("Error setting projection on destination!"));
5950
		GDALClose(hDstDS);
5951
		GDALClose(hSrcDS);
5952
		unlink(fName->toAscii().data());
5953
		return false;
158 andreas 5954
	}
5955
 
314 andreas 5956
	if(outSet->SetGeoTransform(&adfDstGeoTransform[0]) != CE_None)
158 andreas 5957
	{
314 andreas 5958
		KMessageBox::error(this, i18n("Error setting geo transform data to destination!"));
5959
		GDALClose(hDstDS);
5960
		GDALClose(hSrcDS);
5961
		unlink(fName->toAscii().data());
5962
		return false;
158 andreas 5963
	}
159 andreas 5964
 
158 andreas 5965
	// Copy the color table, if required.
5966
	GDALColorTableH hCT;
5967
 
314 andreas 5968
	for(int i = 0; i < nRasterCount; i++)
158 andreas 5969
	{
314 andreas 5970
		hCT = GDALGetRasterColorTable(inSet->GetRasterBand(i + 1));
158 andreas 5971
 
314 andreas 5972
		if(hCT != NULL)
5973
			GDALSetRasterColorTable(outSet->GetRasterBand(i + 1), hCT);
158 andreas 5974
	}
5975
 
5976
	// Setup warp options.
5977
	GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();
5978
 
5979
	psWarpOptions->hSrcDS = hSrcDS;
5980
	psWarpOptions->hDstDS = hDstDS;
5981
 
5982
	psWarpOptions->nBandCount = nRasterCount;
5983
	psWarpOptions->panSrcBands =
314 andreas 5984
	         (int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount);
158 andreas 5985
	psWarpOptions->panDstBands =
314 andreas 5986
	         (int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount);
158 andreas 5987
 
314 andreas 5988
	for(int i = 0; i < nRasterCount; i++)
158 andreas 5989
	{
314 andreas 5990
		psWarpOptions->panSrcBands[i] = i + 1;
5991
		psWarpOptions->panDstBands[i] = i + 1;
158 andreas 5992
	}
5993
 
159 andreas 5994
//	psWarpOptions->pfnProgress = GDALTermProgress;
158 andreas 5995
 
5996
	// Establish reprojection transformer.
5997
	psWarpOptions->pTransformerArg =
314 andreas 5998
	         GDALCreateGenImgProjTransformer(hSrcDS,
5999
	                           GDALGetProjectionRef(hSrcDS),
6000
	                           hDstDS,
6001
	                           GDALGetProjectionRef(hDstDS),
6002
	                           FALSE, 0.0, 1);
158 andreas 6003
 
6004
	psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
6005
 
6006
	// Initialize and execute the warp operation.
6007
	GDALWarpOperation oOperation;
6008
 
314 andreas 6009
	if(oOperation.Initialize(psWarpOptions) != CE_None)
158 andreas 6010
	{
314 andreas 6011
		KMessageBox::error(this, i18n("Error initializing warp operation!"));
6012
		GDALClose(hDstDS);
6013
		GDALClose(hSrcDS);
6014
		unlink(fName->toAscii().data());
6015
		return false;
158 andreas 6016
	}
6017
 
314 andreas 6018
	oOperation.ChunkAndWarpMulti(0, 0, geoRect.width, geoRect.height);
6019
	GDALDestroyGenImgProjTransformer(psWarpOptions->pTransformerArg);
158 andreas 6020
	GDALDestroyWarpOptions(psWarpOptions);
6021
 
314 andreas 6022
	GDALClose(hDstDS);
6023
	GDALClose(hSrcDS);
6024
	unlink(nfn.toAscii().data());
158 andreas 6025
	return true;
6026
}
6027
 
151 andreas 6028
#endif
6029
 
283 andreas 6030
#ifdef HAVE_GDAL
6031
void spwErrorHandler(CPLErr err, int num, const char *msg)
6032
{
314 andreas 6033
	ERRMSG *akt;
6034
	char et[32], hv0[4096];
283 andreas 6035
 
314 andreas 6036
	if(err == CE_None || !msg)
6037
		return;
283 andreas 6038
 
314 andreas 6039
	if(err == CE_Fatal)
6040
		std::cerr << "ERROR " << num << ": " << msg << endl;
283 andreas 6041
 
314 andreas 6042
	if(!firstError)
283 andreas 6043
	{
314 andreas 6044
		firstError = new ERRMSG;
6045
		memset(firstError, 0, sizeof(ERRMSG));
6046
		akt = firstError;
283 andreas 6047
	}
6048
	else
6049
	{
314 andreas 6050
		akt = firstError;
283 andreas 6051
 
314 andreas 6052
		while(akt)
6053
		{
6054
			if(!akt->next)
6055
				break;
283 andreas 6056
 
314 andreas 6057
			akt = akt->next;
6058
		}
283 andreas 6059
 
314 andreas 6060
		akt->next = new ERRMSG;
6061
		akt = akt->next;
6062
		memset(akt, 0, sizeof(ERRMSG));
283 andreas 6063
	}
6064
 
314 andreas 6065
	switch(err)
283 andreas 6066
	{
314 andreas 6067
		case CE_None: strcpy(et, "None"); break;
6068
		case CE_Debug: strcpy(et, "DEBUG"); break;
6069
		case CE_Warning: strcpy(et, "Warning"); break;
6070
		case CE_Failure: strcpy(et, "Failure"); break;
6071
		case CE_Fatal: strcpy(et, "Fatal"); break;
283 andreas 6072
	}
6073
 
6074
	memset(hv0, 0, sizeof(hv0));
314 andreas 6075
	strncpy(hv0, msg, 4000);
6076
	sprintf(akt->msg, "ERROR TYPE %s - %d: %s", et, num, hv0);
283 andreas 6077
}
6078
 
6079
void destroyErrors()
6080
{
314 andreas 6081
	ERRMSG *akt;
283 andreas 6082
 
314 andreas 6083
	if(!firstError)
6084
		return;
283 andreas 6085
 
6086
	akt = firstError;
6087
 
314 andreas 6088
	while(akt)
283 andreas 6089
	{
314 andreas 6090
		firstError = akt->next;
6091
		delete akt;
6092
		akt = firstError;
283 andreas 6093
	}
6094
 
6095
	firstError = 0;
6096
}
6097
 
6098
QString catGDALError()
6099
{
314 andreas 6100
	QString err;
6101
	ERRMSG *akt = firstError;
283 andreas 6102
 
314 andreas 6103
	while(akt)
283 andreas 6104
	{
314 andreas 6105
		err += QString(akt->msg) + "\n";
6106
		akt = akt->next;
283 andreas 6107
	}
6108
 
6109
	destroyErrors();
6110
	return err;
6111
}
6112
#endif
6113
 
88 andreas 6114
#include "sportwatcherwidget.moc"
6115