Subversion Repositories public

Rev

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

/***************************************************************************
 *   Copyright (C) 2007 - 2013 by Andreas Theofilu                         *
 *   andreas@theosys.at                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation version 3 of the License.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "config.h"
#include "managefile.h"
#include "sportwatcherwidget.h"
#include "settingswidget.h"
#include "progresswidget.h"
#include "wmsbase.h"
#include "coordinateswidget.h"
#include "shapewidget.h"
#include <string.h>

#include <iostream>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <KConfig>
#include <klocale.h>
#include <k3listview.h>
#include <kaboutdata.h>
#include <kaboutapplicationdialog.h>
#include <kinputdialog.h>
#include <kglobalsettings.h>
#include <kcombobox.h>
#include <qapplication.h>
#include <qstring.h>
#include <qdatetime.h>
#include <qtoolbutton.h>
#include <qcursor.h>
#include <qregexp.h>
#include <QMouseEvent>
#include <QRect>
#include <QRegion>
#include <KIcon>
#include <QPrintDialog>
#include <QPrinter>

#if defined HAVE_GDAL
#include <gdal/ogr_spatialref.h>
#include <gdal/ogrsf_frmts.h>
#include <gdal/gdalwarper.h>
#include <gdal/ogrsf_frmts.h>
#include "GDALError.h"
#endif

#include "garmin.h"
#include "transform.h"

#if defined HAVE_MAPNIK
#include "render.h"
#endif

using std::cout;
using std::cerr;
using std::clog;
using std::endl;


typedef struct
{
        double lon;
        double lat;
} posn_type;

#if defined HAVE_GDAL
typedef struct ERRMSG
{
        char msg[4096];
        ERRMSG *next;
} ERRMSG;

ERRMSG *firstError;
#endif

sportwatcherWidget::sportwatcherWidget(QWidget *parent)
{
        ui_sportwatcherWidgetBase.setupUi(this);

#if defined HAVE_GDAL
        mFactor = 10;           // Factor to calculate square pixels
        firstError = 0;
#endif
        mama = parent;
        gmn = 0;
        min_hr = max_hr = avg_hr = 0;
        min_height = max_height = 0.0;
        max_time = 0;
        zfactor = 0;
        mapLap = 0;
        mapPan = QRect(0, 0, 0, 0);
        stateHand = stateFlag = stateGlas = false;
        oldTransX = oldTransY = 0.0;
        lmbPressed = 0;
        DIRTY = true;
        curTab = ui_sportwatcherWidgetBase.tabView->currentIndex();
        tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
        ActivePrint = false;    // true if we are printing on paper
        kl = new KLocale(QString("kdesktop"), 0);

        // Load the config parameters
        KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
        KConfigGroup ic(&cfg, "SportWatcher");
        lower1 = ic.readEntry("lower1", 0);
        lower2 = ic.readEntry("lower2", 0);
        lower3 = ic.readEntry("lower3", 0);
        upper1 = ic.readEntry("upper1", 0);
        upper2 = ic.readEntry("upper2", 0);
        upper3 = ic.readEntry("upper3", 0);
        MaxHr = ic.readEntry("maxHr", 180);
        restHr = ic.readEntry("restHr", 60);
        vo2max = ic.readEntry("vo2max", 50);
        weight = ic.readEntry("weight", 70);
        sampleTime = ic.readEntry("seconds", 15);
        Serial = ic.readEntry("Serial", false);
        Forerunner = ic.readEntry("Forerunner", false);
        Contour = ic.readEntry("Contour", false);
        Device = ic.readEntry("Device", "/dev/ttyUSB0");
        Data = ic.readEntry("Data", QDir::home().absolutePath() + "/.sportwatcher");
        HRM = ic.readEntry("HRM", QDir::home().absolutePath() + "/polar");
        MAP = ic.readEntry("MAP", QDir::home().absolutePath() + "/.sportwatcher/track.wms");
        Units = ic.readEntry("Units", 0);
        MapType = ic.readEntry("MapType", 7);
#ifdef HAVE_GDAL
        // set our own error handler here
        CPLSetErrorHandler((CPLErrorHandler)spwErrorHandler);
#endif

}

sportwatcherWidget::~sportwatcherWidget()
{
        destroy();
        delete kl;
#ifdef HAVE_GDAL
        // destroy the error handler here
        CPLSetErrorHandler(NULL);
#endif
}

void sportwatcherWidget::destroy()
{
        if(gmn)
                garmin_free_data(gmn);

        gmn = 0;
        oldTransX = oldTransY = 0.0;
}

void sportwatcherWidget::Initialize()
{
        // Set some widget settings
        ui_sportwatcherWidgetBase.btHand->setIcon(KIcon("hand"));
        ui_sportwatcherWidgetBase.btGlas->setIcon(KIcon("glas"));
        ui_sportwatcherWidgetBase.btGlasMinus->setIcon(KIcon("glas_minus"));
        ui_sportwatcherWidgetBase.btGlasPlus->setIcon(KIcon("glas_plus"));
        ui_sportwatcherWidgetBase.btFlag->setIcon(KIcon("flag"));
        ui_sportwatcherWidgetBase.btFullscreen->setIcon(KIcon("fullscreen"));

        if(curTab != 0)
        {
                ui_sportwatcherWidgetBase.tabView->setCurrentIndex(0);
                curTab = ui_sportwatcherWidgetBase.tabView->currentIndex();
        }

//      btHand->setToggleButton(true);
//      btGlas->setToggleButton(true);
        // Fill the activities
        getActivities();
#if defined HAVE_GDAL
        // Initialize the GDAL
        GDALAllRegister();
        poDataset = 0;
#endif
}

QTreeWidgetItem *sportwatcherWidget::findElement(QTreeWidget *wdg, const QString &val)
{
        QTreeWidgetItem *item, *child, *subchild;

        if(!wdg)
                return 0;

        for(int a = 0; a < wdg->topLevelItemCount(); a++)
        {
                if(!(item = wdg->topLevelItem(a)))
                        continue;

                for(int j = 0; j < item->childCount(); j++)
                {
                        if(!(child = item->child(j)))
                                continue;

                        if(child->data(0, Qt::UserRole).toString() == val)
                                return child;

                        for(int i = 0; i < child->childCount(); i++)
                        {
                                if(!(subchild = child->child(i)))
                                        continue;

                                if(subchild->data(0, Qt::UserRole).toString() == val)
                                        return subchild;
                        }
                }
        }

        return 0;
}

/*
 * Search for a directory named .sportwatcher in the home directory of
 * the user and search for *.gmn files. Open the files and read the header
 * to find the basic data of activities. Then add the information into
 * the activities KListView.
 */
void sportwatcherWidget::getActivities()
{
        QString path, txt;
        QDir mdir, dir = QDir::home();
        QStringList years, months;
        QTreeWidgetItem *running, *biking, *other, *year_run, *year_bike, *year_other;
        QTreeWidgetItem *el;
        QList<QTreeWidgetItem *> item;
        int i, j;
        int y_run, y_bike, y_other;
        RUN_NODE *rn;
        LAP *lap;

        if(Data.isEmpty())
        {
                path = dir.homePath();
                path.append("/.sportwatcher");
        }
        else
                path = Data;

        dir.setPath(path);
        dir.refresh();

        if(!dir.exists())
        {
                dir.mkdir(path);
                return;
        }

        destroy();

        if(!ui_sportwatcherWidgetBase.liActivities)
        {
                KMessageBox::error(this, i18n("Error initializing some widgets of main window!"));
                return;
        }

        ui_sportwatcherWidgetBase.liActivities->clear();
        ui_sportwatcherWidgetBase.liActivities->setSortingEnabled(false);
        ui_sportwatcherWidgetBase.liActivities->setColumnCount(1);

        running = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
        biking = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
        other = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);

        if(!other || !biking || !running)
        {
                KMessageBox::error(this, i18n("Not enough memory to initilize application!"));
                return;
        }

        running->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
        biking->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
        other->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);

        running->setText(0, i18n("Running"));
        biking->setText(0, i18n("Biking"));
        other->setText(0, i18n("Others"));

        KIcon fld(QString("history"));
        running->setIcon(0, fld);
        biking->setIcon(0, fld);
        other->setIcon(0, fld);

        running->setStatusTip(0, i18n("\"Running\" activities."));
        biking->setStatusTip(0, i18n("\"Biking\" activities."));
        other->setStatusTip(0, i18n("\"Other\" and \"Multisport\" activities."));

        dir.cd(path);
        dir.setFilter(QDir::Dirs | QDir::NoSymLinks);
        dir.setSorting(QDir::Name);
        dir.refresh();
        QFileInfoList list = dir.entryInfoList();

        if(!list.size())
                return;

        for(i = 0; i < list.size(); i++)                // Years
        {
                QFileInfo fileInfo = list.at(i);

                if(fileInfo.fileName() == QString(".") || fileInfo.fileName() == QString(".."))
                        continue;

                years += fileInfo.absoluteFilePath();
        }

        for(i = 0; i < years.size(); ++i)
        {
                if(months.size() > 0)
                        months.clear();

                dir.setPath(years.at(i));
                dir.refresh();
                list = dir.entryInfoList();

                if(!list.size())
                        continue;

                for(j = 0; j < list.size(); j++)                // Months
                {
                        QFileInfo fileInfo = list.at(j);

                        if(fileInfo.fileName() == QString(".") || fileInfo.fileName() == QString(".."))
                                continue;

                        months += fileInfo.absoluteFilePath();
                }

                for(j = 0; j < months.size(); ++j)
                {
                        mdir.setPath(months.at(j));
                        mdir.cd(months.at(j));
                        mdir.setFilter(QDir::Files | QDir::NoSymLinks);
                        mdir.setSorting(QDir::Name);
                        mdir.setNameFilters(QStringList("*.gmn"));
                        mdir.refresh();
                        list = mdir.entryInfoList();

                        if(!list.size())
                                continue;

                        for(int a = 0; a < list.size(); a++)            // Files
                        {
                                QFileInfo fileInfo = list.at(a);

                                files += fileInfo.absoluteFilePath();
                        }
                }
        }

        y_run = y_bike = y_other = 0;
        year_run = year_bike = year_other = 0;

        // Open every file and read its head
        for(i = 0; i < files.size(); ++i)
        {
                QTreeWidgetItem *yr, *yb, *yo;

                if(findElement(ui_sportwatcherWidgetBase.liActivities, files.at(i)))
                        continue;

                spw.destroy();

                if(spw.setFileName(files.at(i).toAscii().constData()) == -1)
                        return;

                if(gmn)
                {
                        garmin_free_data(gmn);
                        gmn = 0;
                }

                if(!(gmn = spw.readFile()))
                        continue;

                ds.destroy();
                ds.garmin_print_data(gmn);
                rn = ds.getRunNode();

                if(!rn)
                        return;

                lap = ds.getLap(rn->run->first_lap_index);

                if(!lap)
                        return;

                const QDateTime *qt = garmin_dtime(lap->start_time);
                // By default set the name of the session to the date and time
                // it was recorded.
                QString idx = kl->formatDateTime(*qt, KLocale::ShortDate, true);
                QString stTip = kl->formatDateTime(*qt, KLocale::LongDate, true);

                // If we have a custom name for this session, set it.
                if(strlen(rn->run->workout.name) > 1 && strlen(rn->run->workout.name) < 16 && isalpha(rn->run->workout.name[0]))
                        idx = QString(rn->run->workout.name);

                switch(rn->run->sport_type)
                {
                        case D1000_running:
                                yr = findElement(ui_sportwatcherWidgetBase.liActivities, QString("run_%1").arg(qt->date().year()));

                                if(!yr && qt->date().year() != y_run)
                                {
                                        year_run = new QTreeWidgetItem(running, running, QTreeWidgetItem::Type);
                                        y_run = qt->date().year();
                                        year_run->setText(0, QString("%1").arg(y_run));
                                        year_run->setData(0, Qt::UserRole, QString("run_%1").arg(y_run));
                                        year_run->setIcon(0, KIcon(QString("today")));
                                        year_run->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
                                }
                                else
                                        year_run = yr;

                                el = new QTreeWidgetItem(year_run, year_run, QTreeWidgetItem::Type);
                                el->setText(0, idx);
                                el->setData(0, Qt::UserRole, files.at(i));
                                el->setIcon(0, KIcon(QString("spw-running")));
                                el->setStatusTip(0, stTip);
                                el->setToolTip(0, stTip);
                                el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
                                break;

                        case D1000_biking:
                                yb = findElement(ui_sportwatcherWidgetBase.liActivities, QString("bike_%1").arg(qt->date().year()));

                                if(!yb && qt->date().year() != y_bike)
                                {
                                        year_bike = new QTreeWidgetItem(biking, biking, QTreeWidgetItem::Type);
                                        y_bike = qt->date().year();
                                        year_bike->setText(0, QString("%1").arg(y_bike));
                                        year_bike->setData(0, Qt::UserRole, QString("bike_%1").arg(y_bike));
                                        year_bike->setIcon(0, KIcon(QString("today")));
                                        year_bike->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
                                }
                                else
                                        year_bike = yb;

                                el = new QTreeWidgetItem(year_bike, year_bike, QTreeWidgetItem::Type);
                                el->setText(0, idx);
                                el->setData(0, Qt::UserRole, files.at(i));
                                el->setStatusTip(0, stTip);
                                el->setToolTip(0, stTip);
                                el->setIcon(0, KIcon(QString("bike")));
                                el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
                                break;

                        case D1000_other:
                        default:
                                yo = findElement(ui_sportwatcherWidgetBase.liActivities, QString("other_%1").arg(qt->date().year()));

                                if(!yo && qt->date().year() != y_other)
                                {
                                        year_other = new QTreeWidgetItem(other, other, QTreeWidgetItem::Type);
                                        y_other = qt->date().year();
                                        year_other->setText(0, QString("%1").arg(y_other));
                                        year_other->setData(0, Qt::UserRole, QString("other_%1").arg(y_other));
                                        year_other->setIcon(0, KIcon(QString("today")));
                                        year_other->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
                                }
                                else
                                        year_other = yo;

                                el = new QTreeWidgetItem(year_other, year_other, QTreeWidgetItem::Type);
                                el->setText(0, idx);
                                el->setData(0, Qt::UserRole, files.at(i));
                                el->setStatusTip(0, stTip);
                                el->setToolTip(0, stTip);
                                el->setIcon(0, KIcon(QString("other")));
                                el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
                }

                delete qt;
        }

        ui_sportwatcherWidgetBase.liActivities->setItemExpanded(running, true);

        if(year_run)
                ui_sportwatcherWidgetBase.liActivities->setItemExpanded(year_run, true);

        if(gmn)
                garmin_free_data(gmn);

        gmn = 0;
}

/*$SPECIALIZATION$*/
void sportwatcherWidget::btFullscreenSlot()
{
        oldTransX = oldTransY = 0.0;
        mapPan.setCoords(0, 0, 0, 0);
        DIRTY = true;
        showTrack(0);
        DIRTY = false;
}

void sportwatcherWidget::btGlasMinusSlot()
{
        bool sh = stateHand;

        stateHand = false;
        DIRTY = true;
        showTrack(zfactor - 1000);
        DIRTY = false;
        stateHand = sh;
}

void sportwatcherWidget::btGlasPlusSlot()
{
        bool sh = stateHand;

        stateHand = false;
        DIRTY = true;
        showTrack(zfactor + 1000);
        DIRTY = false;
        stateHand = sh;
}

void sportwatcherWidget::btHandSlot()
{
        QCursor cs;

        if(stateGlas)
        {
                stateGlas = false;
                ui_sportwatcherWidgetBase.btGlas->toggle();
        }

        stateHand = (stateHand) ? false : true;

        if(stateHand)
                cs.setShape(Qt::PointingHandCursor);
        else
                cs.setShape(Qt::ArrowCursor);

        ui_sportwatcherWidgetBase.imgMap->setCursor(cs);
}

void sportwatcherWidget::btGlasSlot()
{
        QCursor cs;

        if(stateHand)
        {
                stateHand = false;
                ui_sportwatcherWidgetBase.btHand->toggle();
        }

        stateGlas = (stateGlas) ? false : true;

        if(stateGlas)
                cs.setShape(Qt::ForbiddenCursor);
        else
                cs.setShape(Qt::ArrowCursor);

        ui_sportwatcherWidgetBase.imgMap->setCursor(cs);
}

void sportwatcherWidget::btFlagSlot()
{
}

void sportwatcherWidget::liLapsSlot(Q3ListViewItem *item)
{
        QString sl;
        int l;
        int idx;
        RUN_NODE *rn;
        LAP *lap;

        if(!item)
                return;

        DIRTY = true;
        sl = item->text(0).mid(4, 3);
        l = sl.toInt();

        if(l <= 0)
        {
                // Show the whole map and track
                showTrack(zfactor, mapPan, 0);
                // Don't mark any lap. Just display normal.
                showCurves(0);
                return;
        }

        rn = ds.getRunNode();
        idx = rn->run->first_lap_index;
        lap = ds.getLap(idx + l - 1);
        // Show the part of the track, corresponding to the selected lap
        showTrack(zfactor, mapPan, lap);
        // Mark the selected lap
        showCurves(lap);
        DIRTY = false;
}

void sportwatcherWidget::liActivitiesSlot(QTreeWidgetItem *item, int)
{
        if(!item)
                return;

        spw.destroy();

        if(spw.setFileName(item->data(0, Qt::UserRole).toString().toAscii().constData()) == -1)
                return;

        if(gmn)
                garmin_free_data(gmn);

        gmn = spw.readFile();
        zfactor = 0;

        // Make sure, the currently not visible tabs will be redrawn as soon
        // as they are visible.
        switch(curTab)
        {
                case 0: tabDirt1 = tabDirt2 = tabDirt3 = true; break;
                case 1: tabDirt0 = tabDirt2 = tabDirt3 = true; break;
                case 2: tabDirt0 = tabDirt1 = tabDirt3 = true; break;
                case 3: tabDirt0 = tabDirt1 = tabDirt2 = true; break;
        }

        // Display the just loaded sport session
        DIRTY = true;
        showLaps();
        showTrack();
        showCurves();

        if(curTab == 2)
        {
                showThreeCurve();
                tabDirt2 = false;
        }

        DIRTY = false;
}

/*
 * The following function is called, when the user clicks the print button.
 * It then prints the currently loaded activity. First the laps and on a
 * seperate page the map, heart rate, elevation and speed.
 *
 * The function uses the already existing function showTrack() to draw an
 * optional map and the track on it. It uses the function showThreeCurve()
 * to draw the heart rate, elevation and speed. Only the laps are drawn
 * directly in this function.
 */
void sportwatcherWidget::filePrint()
{
        QPrinter printer(QPrinter::HighResolution);
        QDateTime dt;
        QTime t, st;
        QDateTime *qt;
        QRectF rect;
        QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
        QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
        QString qs_totdist, hv0;
        LAP *lap;
        POINT *point;
        RUN_NODE *rakt, *rn;
        int laps, i, anz, cad, page, firstPage, lastPage;
        qreal extMil[4];
        double sum_dsc, old_asc, old_dsc;
        double totdist, lineH, aktLine;
        bool printed = false;

        if(!gmn)
        {
                KMessageBox::error(this, i18n("You must select an activity first!"));
                return;
        }

        printer.setCreator(QString("SportWatcher"));
        printer.setDocName(QString("SportWatcher_%1").arg(QString(VERSION)));
        QPrintDialog printDialog(&printer, this);

        if(!printDialog.exec() == QDialog::Accepted)
                return;

        if(!(rn = ds.getRunNode()))
                return;

        // We dont care about page margins of a printer. Instead we assume
        // a frame from about 20mm arround the page. European paper size is
        // A4 (210x297mm) and the output is optimized for this.
        totdist = 0;
        extMil[0] = 20.0;
        extMil[1] = 20.0;
        extMil[2] = 210.0 - 20.0;
        extMil[3] = 279.0 - 20.0;
        lineH = 4.5;    // The height of a line with 10pt letters
        page = 1;       // The page number
        firstPage = printer.fromPage();
        lastPage = printer.toPage();

        if(!printArea.begin(&printer))
        {
                KMessageBox::error(this, i18n("Error initializing printer! Printing is currently not available!"));
                return;
        }

        ActivePrint = true;
        rakt = rn;
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

        while(rakt)
        {
                // Check for a supported run type
                if(rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
                                  rakt->run->type == data_D1010)
                {
                        int ahr;
                        double distance, speed, mspeed;
                        QDate dat;

                        printArea.setFont(QFont(QString("Helvetica"), 12, QFont::Bold, false));
                        rect.setCoords(milToPixel(extMil[0], printer),
                                       milToPixel(extMil[1], printer, true),
                                       milToPixel(extMil[0] + 170, printer),
                                       milToPixel(extMil[1] + 7.0, printer, true));
                        printArea.setPen(QPen(QBrush(QColor("black")), (qreal)milToPixel(0.5, printer, false)));

                        if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                          (lastPage == 0 && firstPage == 0))
                        {
                                printArea.drawRect(rect);
                                printed = true;
                        }

                        if(!(lap = ds.getLap(rakt->run->first_lap_index)))
                        {
                                ActivePrint = false;
                                QApplication::restoreOverrideCursor();
                                return;
                        }

                        if(strlen(rn->run->workout.name) > 1 && strlen(rn->run->workout.name) < 16 && isalpha(rn->run->workout.name[0]))
                                hv0 = QString(rakt->run->workout.name);
                        else
                        {
                                qt = garmin_dtime(lap->start_time);
                                hv0 = kl->formatDate(qt->date(), KLocale::ShortDate) + " ";
                                hv0.append(qt->toString("hh:mm:ss"));
                                delete qt;
                        }

                        // Set the name depending on the sport type
                        // This is used on the tab "Summary"
                        switch(rakt->run->sport_type)
                        {
                                case D1000_running: qs_name = i18n("Running: "); break;
                                case D1000_biking:  qs_name = i18n("Biking: "); break;
                                case D1000_other:   qs_name = i18n("Other: "); break;
                                default:
                                        qs_name = i18n("Unknown: ");
                        }

                        // Print the headline inside the frame
                        if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                          (lastPage == 0 && firstPage == 0))
                        {
                                printArea.drawText(rect, Qt::AlignHCenter, QString("%1%2").arg(qs_name).arg(hv0));
                                // Print the headline of the table
                                printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Bold, false));
                                rect.setCoords(milToPixel(extMil[0], printer), milToPixel(extMil[1] + 10, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(extMil[0] + 10 + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Lap"));
                                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));
                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Distance"));
                                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));
                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Time"));
                                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));
                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Speed"));
                                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));
                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Heart rate"));
                                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));
                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Cadence"));
                                aktLine = extMil[1] + 10.0 + lineH;
                                printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
                                aktLine += 1.0;
                                printed = true;
                        }
                        else
                        {
                                aktLine = extMil[1] + 10.0 + lineH;
                                aktLine += 1.0;
                        }

                        // Prepare to print the first line
                        qt = garmin_dtime(lap->start_time);
                        StartTime = *qt;
                        st = qt->time();
                        dat = qt->date();
                        delete qt;
                        qt = 0;

                        // Find the last track
                        if(!(point = ds.getLastPoint()))
                        {
                                QApplication::restoreOverrideCursor();
                                KMessageBox::error(this, i18n("Error getting the last messure point!"));
                                ActivePrint = false;
                                return;
                        }

                        qt = garmin_dtime(point->time);
                        t = qt->time();
                        t.setHMS(0, 0, 0);
                        t = t.addSecs(ds.getTotalTime());
                        qt->setDate(dat);
                        qt->setTime(t);
                        qs_name = kl->formatDate(dat, KLocale::ShortDate);
                        qs_name.append(" ");
                        qs_name.append(kl->formatTime(st, true));
                        max_time = ds.getTotalTime();
                        qs_etime = QString(qt->toString("hh:mm:ss.zzz"));

                        distance = 0.0;
                        mspeed = 0;
                        ahr = 0;
                        anz = 0;
                        cad = 0;
                        sum_dsc = old_asc = old_dsc = 0;

                        // Find out the total distance, calories, maximum speed,
                        // maximum heart rate and the average heart rate. Get this
                        // values from the lap summary the watch made.
                        for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
                        {
                                if((lap = ds.getLap(i)) == NULL)
                                        continue;

                                distance += lap->total_distance;

                                if(lap->avg_cadence != 0xff)
                                        cad += lap->avg_cadence;

                                ahr += lap->avg_heart_rate;
                                anz++;

                                if(lap->max_speed > mspeed)
                                        mspeed = lap->max_speed;
                        }

                        total_distance = distance = ds.getTotalDistance();

                        if(Units == 1)          // Statute?
                                qs_distance.sprintf("%.2f ft", distance / 0.304);
                        else
                                qs_distance.sprintf("%.2f m", distance);

                        if(distance > 0)
                        {
                                QTime tt = qt->time();
                                long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;

                                if(Units == 0)
                                        secs = secs * (1000.0 / distance * 100.0);
                                else
                                        secs = secs * (1609.344 / distance * 100.0);

                                int h = secs / 3600;
                                int m = (secs - (h * 3600)) / 60;
                                int s = secs - ((h * 3600) + (m * 60));
                                t = QTime(h, m, s, 0);
                                qs_avgpace = QString("  ") + kl->formatTime(t, true);

                                if(Units == 0)
                                        qs_avgpace.append(QString(" /km"));
                                else
                                        qs_avgpace.append(QString(" /mi"));
                        }

                        if(Units == 1)          // Statute?
                                speed = distance / ds.getTotalTime() * 3.6 / 1.609344;
                        else
                                speed = distance / ds.getTotalTime() * 3.6;

                        qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
                        qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
                        qs_avghr.sprintf("%d bpm", ahr / anz);

                        if(cad > 0)
                                qs_avgcadence.sprintf("%d", cad / anz);

                        // Print out the summary line and draw twi thin lines underneath
                        if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                          (lastPage == 0 && firstPage == 0))
                        {
                                printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Normal, false));
                                rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignLeft, qs_name);
                                rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_distance, false));
                                rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignRight, qs_etime);
                                rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_avgspeed, false));
                                rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignRight, qs_avghr);
                                rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignRight, qs_avgcadence);
                                aktLine += (lineH + (lineH / 3.0));
                                printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.1, printer, false)));
                                printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
                                printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine + 0.5, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + 0.5, printer, true));
                                aktLine += (lineH / 3.0);
                                printed = true;
                        }
                        else
                        {
                                aktLine += (lineH + (lineH / 3.0));
                                aktLine += (lineH / 3.0);
                        }

                        delete qt;
                        /* Get the laps. */
                        laps = 1;

                        for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
                        {
                                double spd;
                                char *un;

                                if((lap = ds.getLap(i)) == NULL)
                                        continue;

                                qt = garmin_dtime(lap->start_time);
                                qs_name.sprintf("Lap %03d - ", laps);
                                qs_name.append(kl->formatTime(qt->time(), true));
                                qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
                                totdist += (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance;
                                qs_totdist.sprintf("%2.f %s", totdist, (Units == 1) ? "ft" : "m");
                                t = QTime(0, 0, 0, 0);
                                t = t.addMSecs(lap->total_time * 10);
                                qs_etime = t.toString("hh:mm:ss.zzz");
                                spd = lap->total_distance / (lap->total_time / 100.0);
                                delete qt;
                                qt = 0;

                                if(Units == 0)
                                {
                                        un = (char *)"km/h";
                                        spd *= 3.6;
                                }
                                else
                                {
                                        spd *= 3.6 / 1.609344;
                                        un = (char *)"mph";
                                }

                                qs_avgspeed.sprintf("%.2f %s", spd, un);

                                if(lap->total_distance > 0 && lap->total_time != 0)
                                {
                                        double fact;

                                        if(Units == 0)
                                                fact = 1000.0;          // 1 km
                                        else
                                                fact = 1609.344;                // 1 mile in meters

                                        long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
                                        int h = secs / 3600;
                                        int m = (secs - (h * 3600)) / 60;
                                        int s = secs - ((h * 3600) + (m * 60));
                                        t = QTime(h, m, s, 0);
                                        qs_avgpace = kl->formatTime(t, true);

                                        if(Units == 0)
                                                qs_avgpace.append(QString(" /km"));
                                        else
                                                qs_avgpace.append(QString(" /mi"));
                                }

                                qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);

                                if(lap->avg_cadence != 0xff)
                                        qs_avgcadence.sprintf("%d", lap->avg_cadence);

                                // Draw a new detail line
                                if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                                  (lastPage == 0 && firstPage == 0))
                                {
                                        rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(aktLine + lineH, printer, true));
                                        printArea.drawText(rect, Qt::AlignLeft, qs_name);
                                        rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(aktLine + lineH, printer, true));
                                        printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_distance, false));
                                        rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(aktLine + lineH, printer, true));
                                        printArea.drawText(rect, Qt::AlignRight, qs_etime);
                                        rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(aktLine + lineH, printer, true));
                                        printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_avgspeed, false));
                                        rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(aktLine + lineH, printer, true));
                                        printArea.drawText(rect, Qt::AlignRight, qs_avghr);
                                        rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
                                        printArea.drawText(rect, Qt::AlignRight, qs_avgcadence);
                                        printed = true;
                                }

                                aktLine += lineH;

                                if(aktLine >= extMil[3])        // Print on the next page
                                {
                                        aktLine = extMil[3] + 10.0;

                                        if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                                          (lastPage == 0 && firstPage == 0))
                                        {
                                                printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
                                                rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
                                                aktLine = extMil[1];
                                                printed = true;
                                        }
                                        else
                                                aktLine = extMil[1];

                                        if(printed)
                                                printer.newPage();

                                        page++;

                                        // Print the headline of the table
                                        if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                                          (lastPage == 0 && firstPage == 0))
                                        {
                                                printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Bold, false));
                                                rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 35, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Lap"));
                                                rect.setCoords(milToPixel(extMil[0] + 35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 60, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Distance"));
                                                rect.setCoords(milToPixel(extMil[0] + 60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 85, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Time"));
                                                rect.setCoords(milToPixel(extMil[0] + 85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 122, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Speed"));
                                                rect.setCoords(milToPixel(extMil[0] + 122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 147, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Heart rate"));
                                                rect.setCoords(milToPixel(extMil[0] + 147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine + lineH, printer, true));
                                                printArea.drawText(rect, Qt::AlignHCenter, i18n("Cadence"));
                                                aktLine += lineH;
                                                printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.5, printer, false)));
                                                printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
                                                aktLine += 1.0;
                                                printed = true;
                                        }
                                        else
                                        {
                                                aktLine += lineH;
                                                aktLine += 1.0;
                                        }

                                        printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Normal, false));
                                }

                                delete qt;
                                laps++;
                        }

                        aktLine = extMil[3] + 10.0;

                        if((lastPage > 0 && page >= firstPage && page <= lastPage) ||
                                          (lastPage == 0 && firstPage == 0))
                        {
                                printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
                                rect.setCoords(milToPixel(extMil[0], printer),
                                               milToPixel(aktLine, printer, true),
                                               milToPixel(extMil[0] + 170, printer),
                                               milToPixel(aktLine + lineH, printer, true));
                                printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
                                printed = true;
                        }

                        aktLine = extMil[1];
                        page++;

                        if(printed && (page <= lastPage || lastPage == 0))
                                printer.newPage();

                        if((lastPage > 0 && (page < firstPage || page > lastPage)))
                                break;

                        // Draw the map on top of a new page
                        // Use 1/3 of the available height for the map
                        qreal resFact = 8;      // The factor to calculate the resolution for pixmaps
                        int width = (int)(milToPixel(170, printer) / resFact);
                        int height = (int)(milToPixel(extMil[3] - extMil[1], printer, true) / resFact);
                        pmPrMap = QPixmap(width, height / 3);   // 1/3 of page height
                        DIRTY = true;
                        int ct = curTab;
                        curTab = 1;
                        QApplication::restoreOverrideCursor();
                        showTrack();
                        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
                        DIRTY = false;
                        curTab = ct;
                        printArea.drawPixmap(milToPixel(extMil[0], printer),
                                             milToPixel(extMil[1], printer),
                                             pmPrMap.scaled((int)milToPixel(170, printer),
                                                            (int)milToPixel(extMil[3] - extMil[1], printer, true) / 3,
                                                            Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
                        // Put a frame around the map
                        rect.setCoords(milToPixel(extMil[0], printer), milToPixel(extMil[1], printer, true),
                                       milToPixel(extMil[0] + 170, printer),
                                       milToPixel(extMil[1], printer, true) + (milToPixel(extMil[3] - extMil[1], printer, true) / 3));
                        printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.2, printer)));
                        printArea.drawRect(rect);
                        aktLine = (extMil[3] - extMil[1]) / 3.0 + extMil[1] + lineH;

                        // Draw the heart rate diagram
                        rect.setCoords(milToPixel(extMil[0], printer),
                                       milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[2], printer),
                                       milToPixel(aktLine + lineH, printer, true));
                        printArea.drawText(rect, Qt::AlignLeft, i18n("Heart rate:"));
                        aktLine += lineH;
                        qreal pixHeight = (extMil[3] - aktLine) / 3.0 - lineH * 2.0;
                        int realH = (int)milToPixel(pixHeight, printer, true);
                        height = realH / (int)resFact;
                        showThreeCurve(width, height);  // Calculate the curves
                        printArea.drawPixmap(milToPixel(extMil[0], printer),
                                             milToPixel(aktLine, printer, true),
                                             prHR.scaled((int)milToPixel(170, printer),
                                                         realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
                        rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[0] + 170, printer),
                                       milToPixel(aktLine + pixHeight, printer, true));
                        printArea.drawRect(rect);
                        aktLine += pixHeight + lineH;

                        // Draw the elevation diagram
                        rect.setCoords(milToPixel(extMil[0], printer),
                                       milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[2], printer),
                                       milToPixel(aktLine + lineH, printer, true));
                        printArea.drawText(rect, Qt::AlignLeft, i18n("Elevation:"));
                        aktLine += lineH;
                        printArea.drawPixmap(milToPixel(extMil[0], printer),
                                             milToPixel(aktLine, printer, true),
                                             prElevation.scaled((int)milToPixel(170, printer),
                                                                realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
                        rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[0] + 170, printer),
                                       milToPixel(aktLine + pixHeight, printer, true));
                        printArea.drawRect(rect);
                        aktLine += pixHeight + lineH;

                        // Draw the speed diagram
                        rect.setCoords(milToPixel(extMil[0], printer),
                                       milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[2], printer),
                                       milToPixel(aktLine + lineH, printer, true));
                        printArea.drawText(rect, Qt::AlignLeft, i18n("Speed:"));
                        aktLine += lineH;
                        printArea.drawPixmap(milToPixel(extMil[0], printer),
                                             milToPixel(aktLine, printer, true),
                                             prSpeed.scaled((int)milToPixel(170, printer),
                                                            realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
                        rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[0] + 170, printer),
                                       milToPixel(aktLine + pixHeight, printer, true));
                        printArea.drawRect(rect);

                        // Print the page number at the right bottom of the page
                        aktLine = extMil[3] + 10.0;
                        printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
                        rect.setCoords(milToPixel(extMil[0], printer),
                                       milToPixel(aktLine, printer, true),
                                       milToPixel(extMil[0] + 170, printer),
                                       milToPixel(aktLine + lineH, printer, true));
                        printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
                }

                rakt = rakt->next;
        }

        printArea.end();
        // Mark printing as done
        ActivePrint = false;
        QApplication::restoreOverrideCursor();
}

qreal sportwatcherWidget::milToPixel(qreal dist, QPrinter &pr, bool dir)
{
        QSizeF r = pr.paperSize(QPrinter::DevicePixel);
        QSizeF m = pr.paperSize(QPrinter::Millimeter);

        if(!dir)        // width
                return r.width() / m.width() * dist;
        else
                return r.height() / m.height() * dist;
}

/*
 * This function allows the user to choose a file name, where we save the
 * actual lap in Garmins own TCX format. This format is simply a XML-file.
 * For details about the schema of this file look at
 * http://developer.garmin.com/schemas/tcx/v2/
 */
void sportwatcherWidget::fileSaveAs()
{
        QString fname;
        QFile fn;
        QString buffer;
        RUN_NODE *rn, *rakt;
        LAP *lap;
        POINT *point;
        int indent, i;
        QDateTime *qt;
        KUrl sDir("~/");
        QRegExp rx("(\\.tcx|\\.gpx|\\.osm)$");

        if(!gmn)
        {
                KMessageBox::error(this, i18n("Currently no activity is selected!"));
                return;
        }

        rx.setPatternSyntax(QRegExp::RegExp);
        fname = KFileDialog::getSaveFileName(sDir, QString("*.tcx|Garmin Training Center (*.tcx)\n*.gpx|GPS Excange Format (*.gpx)\n*.osm|OpenStreetMap (*.osm)"), this, QString("SportWatcher"));

        if(fname.isEmpty())
                return;

        if(rx.indexIn(fname) < 0)
        {
                KMessageBox::error(this, i18n("The file %1 has no valid file extension!").arg(fname));
                return;
        }

        fn.setFileName(fname);

        if(fn.exists())
        {
                if(KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
                        return;
        }

        rx.setPattern("*.gpx");
        rx.setPatternSyntax(QRegExp::Wildcard);

        if(rx.exactMatch(fname))        // Should we create a *.gpx file?
        {
                sportwatcherWidget::saveGPX(fname);
                return;
        }

        rx.setPattern("*.osm");
        rx.setPatternSyntax(QRegExp::Wildcard);

        if(rx.exactMatch(fname))        // Should we create a *.osm file?
        {
                sportwatcherWidget::saveOSM(fname);
                return;
        }

        // No, we create a *.tcx file!
        indent = 0;
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);

        if((point = ds.getPoint(lap->start_time)) == 0)
        {
                KMessageBox::error(this, i18n("No data to save!"));
                return;
        }

        if(!fn.open(QIODevice::ReadWrite | QIODevice::Truncate))
        {
                KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fname));
                return;
        }

        buffer = QString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
        buffer.append("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\" ");
        buffer.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
        buffer.append("xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 ");
        buffer.append("http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd\">\n\n");
        writeTag(fn, buffer, indent);
        buffer = QString("<folders/>\n\n");
        writeTag(fn, buffer, indent);

        // Open a course
        QFileInfo finfo(fname);
        buffer = QString("<Courses>\n   <Course>\n      <name>%1</name>\n").arg(QFileInfo(finfo).baseName());
        writeTag(fn, buffer, indent);
        indent = 2;

        rakt = rn;

        while(rakt)
        {
                if(rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
                                  rakt->run->type != data_D1010)
                {
                        rakt = rakt->next;
                        continue;
                }

                for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
                {
                        if((lap = ds.getLap(i)) == NULL)
                                continue;

                        // Write the information of the lap
                        writeTag(fn, QString("<Lap>\n"), indent);
                        indent++;
                        buffer.sprintf("<TotalTimeSeconds>%f</TotalTimeSeconds>\n", (double)lap->total_time / 100.0);
                        writeTag(fn, buffer, indent);
                        qt = garmin_dtime(lap->start_time);
                        buffer = QString("<StartTime>%1</StartTime>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
                        writeTag(fn, buffer, indent);
                        buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", lap->total_distance);
                        writeTag(fn, buffer, indent);

                        writeTag(fn, QString("<BeginPosition>\n"), indent);
                        indent++;
                        buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->begin.lat));
                        writeTag(fn, buffer, indent);
                        buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->begin.lon));
                        writeTag(fn, buffer, indent);
                        indent--;
                        writeTag(fn, QString("</BeginPosition>\n"), indent);

                        writeTag(fn, QString("<EndPosition>\n"), indent);
                        indent++;
                        buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->end.lat));
                        writeTag(fn, buffer, indent);
                        buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->end.lon));
                        writeTag(fn, buffer, indent);
                        indent--;
                        writeTag(fn, QString("</EndPosition>\n"), indent);

                        writeTag(fn, QString("<AverageHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
                        indent++;
                        buffer.sprintf("<Value>%d</Value>\n", lap->avg_heart_rate);
                        writeTag(fn, buffer, indent);
                        indent--;
                        writeTag(fn, QString("</AverageHeartRateBpm>\n"), indent);

                        writeTag(fn, QString("<MaximumHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
                        indent++;
                        buffer.sprintf("<Value>%d</Value>\n", lap->max_heart_rate);
                        writeTag(fn, buffer, indent);
                        indent--;
                        writeTag(fn, QString("</MaximumHeartRateBpm>\n"), indent);

                        if(lap->avg_cadence < 255)
                        {
                                buffer.sprintf("<AverageCadence>%d</AverageCadence>\n", lap->avg_cadence);
                                writeTag(fn, buffer, indent);
                                buffer.sprintf("<Cadence>%d</Cadence>\n", lap->avg_cadence);
                                writeTag(fn, buffer, indent);
                        }

                        buffer = QString("<Intensity>%1</Intensity>\n").arg((!lap->intensity) ? "Active" : "Resting");
                        writeTag(fn, buffer, indent);

                        buffer.sprintf("<Calories>%d</Calories>\n", lap->calories);
                        writeTag(fn, buffer, indent);

                        buffer.sprintf("<MaximumSpeed>%f</MaximumSpeed>\n", lap->max_speed);
                        writeTag(fn, buffer, indent);
                        indent--;
                        writeTag(fn, QString("</Lap>\n"), indent);

                        point = ds.getPoint(lap->start_time);
                        writeTag(fn, QString("<Track>\n"), indent);
                        indent++;

                        while(point)
                        {
                                if(point->time > (lap->start_time + (lap->total_time / 100)))
                                        break;

                                writeTag(fn, QString("<Trackpoint>\n"), indent);
                                indent++;
                                qt = garmin_dtime(point->time);
                                buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
                                writeTag(fn, buffer, indent);
                                delete qt;
                                writeTag(fn, QString("<Position>\n"), indent);
                                indent++;
                                buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(point->posn.lat));
                                writeTag(fn, buffer, indent);
                                buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(point->posn.lon));
                                writeTag(fn, buffer, indent);
                                indent--;
                                writeTag(fn, QString("</Position>\n"), indent);

                                if(point->alt < 20000.0)
                                {
                                        buffer.sprintf("<AltitudeMeters>%f</AltitudeMeters>\n", point->alt);
                                        writeTag(fn, buffer, indent);
                                }

                                buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", point->distance);
                                writeTag(fn, buffer, indent);

                                if(point->heart_rate > 0 && point->heart_rate < 250)
                                {
                                        writeTag(fn, QString("<HeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
                                        indent++;
                                        buffer.sprintf("<Value>%d</Value>\n", point->heart_rate);
                                        writeTag(fn, buffer, indent);
                                        indent--;
                                        writeTag(fn, QString("</HeartRateBpm>\n"), indent);
                                }

                                if(point->cadence < 0xff)
                                {
                                        buffer.sprintf("<Cadence>%d</Cadence>\n", point->cadence);
                                        writeTag(fn, buffer, indent);
                                }

                                buffer.sprintf("<SensorState>%s</SensorState>\n", (!point->sensor) ? "Absent" : "Present");
                                writeTag(fn, buffer, indent);
                                indent--;
                                writeTag(fn, QString("</Trackpoint>\n"), indent);
                                point = ds.getPoint(point->time + 1);
                        }

                        indent--;
                        writeTag(fn, QString("</Track>\n"), indent);
                }

                indent--;
                writeTag(fn, QString("</Course>\n"), indent);
                indent--;
                writeTag(fn, QString("</Courses>\n"), indent);
                rakt = rakt->next;
        }

        // Write information about device
        // Here my personal signature is written :-)
        writeTag(fn, QString("<Author xsi:type=\"Application_t\">\n"), indent);
        indent++;
        writeTag(fn, QString("<Name>SportWatcher</Name>\n"), indent);
        writeTag(fn, QString("<Build>\n"), indent);
        indent++;
        writeTag(fn, QString("<Version>\n"), indent);
        indent++;
        writeTag(fn, QString("<VersionMajor>0</VersionMajor>\n"), indent);
        writeTag(fn, QString("<VersionMinor>1</VersionMinor>\n"), indent);
        writeTag(fn, QString("<BuildMajor>0</BuildMajor>\n"), indent);
        writeTag(fn, QString("<BuildMinor>0</BuildMinor>\n"), indent);
        indent--;
        writeTag(fn, QString("</Version>\n"), indent);
        writeTag(fn, QString("<Type>Beta</Type>\n"), indent);
        writeTag(fn, QString("<Time>Jan 31 2008, 00:00:00</Time>\n"), indent);
        writeTag(fn, QString("<Builder>theosys</Builder>\n"), indent);
        indent--;
        writeTag(fn, QString("</Build>\n"), indent);
        writeTag(fn, QString("<LangID>EN</LangID>\n"), indent);
        writeTag(fn, QString("<PartNumber>000-00000-00</PartNumber>\n"), indent);
        indent--;
        writeTag(fn, QString("</Author>\n"), indent);
        writeTag(fn, QString("</TrainingCenterDatabase>\n"), indent);

        fn.close();
        KMessageBox::information(this, i18n("File ") + fname + i18n(" was written successfully."));
}

void sportwatcherWidget::fileSave()
{
        KMessageBox::information(this, i18n("This function is currently not implemented!"));
}

void sportwatcherWidget::saveGPX(const QString &fn)
{
        QFile qf;
        QString buffer;
        RUN_NODE *rn, *rakt;
        LAP *lap;
        POINT *point;
        int indent;
        unsigned int i;
        QDateTime *qt;
        double minLat, minLon, maxLat, maxLon;

        indent = 0;
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);

        if((point = ds.getPoint(lap->start_time)) == 0)
        {
                KMessageBox::error(this, i18n("No data to save!"));
                return;
        }

        qf.setFileName(fn);

        if(!qf.open(QIODevice::ReadWrite | QIODevice::Truncate))
        {
                KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fn));
                return;
        }

        buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
        buffer.append("<gpx version=\"1.1\" creator=\"TheoSys SportWatcher\" xmlns=\"http://www.topografix.com/GPX/1/1\">\n");
        buffer.append("   <metadata>\n");
        indent = 0;
        writeTag(qf, buffer, indent);

        // Find the edges of our coordinates
        // We need this information in the header (metadata)
        rakt = rn;
        minLat = -90.0;
        minLon = -180.0;
        maxLat = 90.0;
        maxLon = 180.0;

        while(rakt)
        {
                if(rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
                                  rakt->run->type != data_D1010)
                {
                        rakt = rakt->next;
                        continue;
                }

                i = rakt->run->first_lap_index;

                // get the first lap
                if((lap = ds.getLap(i)) == NULL)
                        continue;

                i = 0;

                // iterate the points associated with the laps
                while((point = ds.getPoint(i)) != 0)
                {
                        if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
                        {
                                i = point->time + 1;
                                continue;
                        }

                        if(SEMI2DEG(point->posn.lat) > minLat)
                                minLat = SEMI2DEG(point->posn.lat);

                        if(SEMI2DEG(point->posn.lat) < maxLat)
                                maxLat = SEMI2DEG(point->posn.lat);

                        if(SEMI2DEG(point->posn.lon) > minLon)
                                minLon = SEMI2DEG(point->posn.lon);

                        if(SEMI2DEG(point->posn.lon) < maxLon)
                                maxLon = SEMI2DEG(point->posn.lon);

                        i = point->time + 1;
                }

                rakt = rakt->next;
        }

        buffer.sprintf("      <bounds minlat=\"%f\" minlon=\"%f\" maxlat=\"%f\" maxlon=\"%f\" />\n",
                       maxLat, minLon, minLat, maxLon);
        buffer.append("   </metadata>\n");
        buffer.append("   <trk>\n");
        buffer.append("      <trkseg>\n");
        writeTag(qf, buffer, indent);
        indent = 3;
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);
        i = 0;

        while((point = ds.getPoint(i)) != 0)
        {
                if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
                {
                        i = point->time + 1;
                        continue;
                }

                buffer.sprintf("<trkpt lat=\"%f\" lon=\"%f\">\n",
                               SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
                writeTag(qf, buffer, indent);
                indent++;
                buffer.sprintf("<ele>%f</ele>\n", point->alt);
                writeTag(qf, buffer, indent);
                qt = garmin_dtime(point->time);
                buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
                writeTag(qf, buffer, indent);
                indent--;
                writeTag(qf, QString("</trkpt>\n"), indent);
                i = point->time + 1;
        }

        indent = 0;
        buffer = QString("      </trkseg>\n");
        buffer.append("   </trk>\n");
        buffer.append("</gpx>\n");
        writeTag(qf, buffer, indent);
        qf.close();
        KMessageBox::information(this, i18n("File ") + fn + i18n(" was written successfully."));
}

void sportwatcherWidget::saveOSM(const QString &fn)
{
        QFile qf;
        QString buffer;
        RUN_NODE *rn, *rakt;
        LAP *lap;
        POINT *point;
        int indent, id, j;
        unsigned int i;
        double minLat, minLon, maxLat, maxLon;
        QDateTime *qt;

        indent = 0;
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);

        if((point = ds.getPoint(lap->start_time)) == 0)
        {
                KMessageBox::error(this, i18n("No data to save!"));
                return;
        }

        qf.setFileName(fn);

        if(!qf.open(QIODevice::ReadWrite | QIODevice::Truncate))
        {
                KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fn));
                return;
        }

        buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
        buffer.append("<osm version=\"0.5\" generator=\"TheoSys SportWatcher\">\n");
        indent = 0;
        writeTag(qf, buffer, indent);
        // Find the edges of our coordinates
        // We need this information in the header (metadata)
        rakt = rn;
        minLat = -90.0;
        minLon = -180.0;
        maxLat = 90.0;
        maxLon = 180.0;

        while(rakt)
        {
                if(rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
                                  rakt->run->type != data_D1010)
                {
                        rakt = rakt->next;
                        continue;
                }

                i = rakt->run->first_lap_index;

                // get the first lap
                if((lap = ds.getLap(i)) == NULL)
                        continue;

                i = 0;

                // iterate the points associated with the laps
                while((point = ds.getPoint(i)) != 0)
                {
                        if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
                        {
                                i = point->time + 1;
                                continue;
                        }

                        if(SEMI2DEG(point->posn.lat) > minLat)
                                minLat = SEMI2DEG(point->posn.lat);

                        if(SEMI2DEG(point->posn.lat) < maxLat)
                                maxLat = SEMI2DEG(point->posn.lat);

                        if(SEMI2DEG(point->posn.lon) > minLon)
                                minLon = SEMI2DEG(point->posn.lon);

                        if(SEMI2DEG(point->posn.lon) < maxLon)
                                maxLon = SEMI2DEG(point->posn.lon);

                        i = point->time + 1;
                }

                rakt = rakt->next;
        }

        buffer.sprintf("   <bound box='%f,%f,%f,%f' origin='http://www.openstreetmap.org/api/0.5' />\n",
                       maxLat, minLon, minLat, maxLon);
        writeTag(qf, buffer, indent);
        indent = 1;
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);
        i = 0;
        id = -1;

        while((point = ds.getPoint(i)) != 0)
        {
                if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
                {
                        i = point->time + 1;
                        continue;
                }

                buffer.sprintf("<node id='%d' action='modify' visible='true' lat=\"%f\" lon=\"%f\">\n",
                               id, SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
                writeTag(qf, buffer, indent);
                indent++;
                buffer = QString("<tag k='created_by' v='TheoSys Sportwatcher' />\n");
                writeTag(qf, buffer, indent);
                buffer = QString("<tag k='highway' v='tertiary' />\n");
                writeTag(qf, buffer, indent);
                indent--;
                writeTag(qf, QString("</node>\n"), indent);
                id--;
                i = point->time + 1;
        }

        qt = garmin_dtime(lap->start_time);
        buffer.sprintf("<way id='%d' action='modify' visible='true' timestamp='%s'>\n",
                       id, QString(qt->toString("yyyy-MM-ddThh:mm:ssZ")).toAscii().data());
        writeTag(qf, buffer, indent);
        indent++;

        for(j = -1; j > id; j--)
        {
                buffer.sprintf("<nd ref='%d' />\n", j);
                writeTag(qf, buffer, indent);
        }

        indent--;
        writeTag(qf, QString("</way>\n"), indent);
        indent = 0;
        writeTag(qf, QString("</osm>\n"), indent);
        qf.close();
        KMessageBox::information(this, i18n("File %1 was written successfully.").arg(fn));
}

void sportwatcherWidget::fileOpen()
{
        QString fname = KFileDialog::getOpenFileName(Data, QString("*.gmn"), this, QString("SportWatcher"));
        int m;

        if(fname.isEmpty())
                return;

        spw.destroy();

        if(spw.setFileName(fname.toAscii().data()) == -1)
                return;

        if(gmn)
                garmin_free_data(gmn);

        gmn = spw.readFile();
        zfactor = 0;

        if((m = garmin_count_error()) > 0)
        {
                int i, key = -1;

                for(i = 0; i < m; i++)
                        KMessageBox::error(this, QString(garmin_get_next_error(&key)));

                garmin_clear_errors();
                return;
        }

        DIRTY = true;
        tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
        showLaps();
        showTrack();
        showCurves();

        if(curTab == 2)
        {
                showThreeCurve();
                tabDirt2 = false;
        }

        tabDirt0 = tabDirt3 = false;
        DIRTY = false;
}

/**
 * This function is called from the XML parser in "gmn_import"
 * whenever an activity is complete.
 * Necessary because there may be more than one activity in a history
 * file.
 */
void sportwatcherWidget::saveImported(void *gd)
{
gmn_import import;
QString tgfile, fld, px;
RUN_NODE *rn;
LAP *lap;
garmin_data *g = (garmin_data *)gd;
QFileInfo datei;
QPixmap qpx;
QList<QTreeWidgetItem *>item;
QTreeWidgetItem *el, *it;

        if(!g)
        {
                std::cerr << "sportwatcherWidget::saveImported: Empty data! Nothing was saved!" << std::endl;
                return;
        }

        // Find the filename;
        // It consists of the date and the time.
        // We need this information to set the correct path to store the file.
        tgfile = Data;          // The base path
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);
        QDateTime *qt = garmin_dtime(lap->start_time);
        tgfile.append(qt->toString("/yyyy"));   // year is a folder
        tgfile.append(qt->toString("/MM"));     // month is a folder
        tgfile.append(qt->toString("/yyyyMMddThhmmss"));        // The file name
        tgfile.append(".gmn");          // Extension of file name
        datei.setFile(tgfile);
std:cerr << "sportwatcherWidget::saveImported:Saving to file " << datei.absoluteFilePath().toAscii().data() << std::endl;
        // save the data to a real file, but only if it doesn't exist allready.
        garmin_save_all(g, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 0);

        // in case the item is already in the list on the left side, we
        // only highlight the item.
        item = ui_sportwatcherWidgetBase.liActivities->findItems(tgfile, Qt::MatchExactly);

        if(item.size() > 0)
        {
                ui_sportwatcherWidgetBase.liActivities->setItemSelected(item.at(0), true);
                ui_sportwatcherWidgetBase.liActivities->setCurrentItem(item.at(0));
                return;
        }

        // insert everything into the list on the left side
        switch(rn->run->sport_type)
        {
                case D1000_running:
                        fld = i18n("Running");
                        px = QString("spw-running");
                break;

                case D1000_biking:
                        fld = i18n("Biking");
                        px = QString("bike");
                break;

                default:
                        fld = i18n("Others");
                        px = QString("other");
        }

        // Do we have allready so items in the list?
        item = ui_sportwatcherWidgetBase.liActivities->findItems(fld, Qt::MatchExactly);

        if(item.size() > 0)
        {
                el = new QTreeWidgetItem(item.at(0));
                el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
                el->setData(0, Qt::UserRole, tgfile);
                el->setIcon(0, KIcon(px));
        }
        else    // no, this is the first item. (shouldn't be!)
        {
                it = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
                it->setText(0, fld);
                it->setIcon(0, KIcon(QString("history")));

                el = new QTreeWidgetItem(item.at(0));
                el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
                el->setData(0, Qt::UserRole, tgfile);
                el->setIcon(0, KIcon(px));
        }
}

void sportwatcherWidget::fileImport()
{
QString fname = KFileDialog::getOpenFileName(QString("~/"), QString("*.tcx"), this, QString("SportWatcher"));
gmn_import import;
int m;
QString tgfile, fld, px;
QPixmap qpx;
QFileInfo datei;
QList<QTreeWidgetItem *>item;
QTreeWidgetItem *el, *it;
LAP *lap;
RUN_NODE *rn;

        if(fname.isEmpty())
                return;

        import.connectCallback(this);
        import.setFile(fname);

        if((m = import.import()) != 0)
        {
                KMessageBox::error(this, QString(import.getError(m)));
                return;
        }

        if(gmn)
        {
                garmin_free_data(gmn);
                gmn = 0;
        }

        if(!(gmn = import.getGarminData()))
                return;

        DIRTY = true;
        tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
        showLaps();
        showTrack();
        showCurves();

        if(curTab == 2)
        {
                showThreeCurve();
                tabDirt2 = false;
        }

        tabDirt0 = tabDirt3 = false;
        DIRTY = false;

        // Find the filename;
        // It consists of the date and the time.
        // We need this information to set the correct path to store the file.
        tgfile = Data;          // The base path
        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);
        QDateTime *qt = garmin_dtime(lap->start_time);
        tgfile.append(qt->toString("/yyyy"));   // year is a folder
        tgfile.append(qt->toString("/MM"));     // month is a folder
        tgfile.append(qt->toString("/yyyyMMddThhmmss"));        // The file name
        tgfile.append(".gmn");          // Extension of file name
        datei.setFile(tgfile);
        std:cerr << "sportwatcherWidget::fileImport:Saving to file " << datei.absoluteFilePath().toAscii().data() << std::endl;
        // save the data to a real file, but only if it doesn't exist allready.
        garmin_save_all(gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 0);

        // in case the item is already in the list on the left side, we
        // only highlight the item.
        item = ui_sportwatcherWidgetBase.liActivities->findItems(tgfile, Qt::MatchExactly);

        if(item.size() > 0)
        {
                ui_sportwatcherWidgetBase.liActivities->setItemSelected(item.at(0), true);
                ui_sportwatcherWidgetBase.liActivities->setCurrentItem(item.at(0));
                return;
        }

        // insert everything into the list on the left side
        switch(rn->run->sport_type)
        {
                case D1000_running:
                        fld = i18n("Running");
                        px = QString("spw-running");
                break;

                case D1000_biking:
                        fld = i18n("Biking");
                        px = QString("bike");
                break;

                default:
                        fld = i18n("Others");
                        px = QString("other");
        }

        // Do we have allready so items in the list?
        item = ui_sportwatcherWidgetBase.liActivities->findItems(fld, Qt::MatchExactly);

        if(item.size() > 0)
        {
                el = new QTreeWidgetItem(item.at(0));
                el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
                el->setData(0, Qt::UserRole, tgfile);
                el->setIcon(0, KIcon(px));
        }
        else    // no, this is the first item. (shouldn't be!)
        {
                it = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
                it->setText(0, fld);
                it->setIcon(0, KIcon(QString("history")));

                el = new QTreeWidgetItem(item.at(0));
                el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
                el->setData(0, Qt::UserRole, tgfile);
                el->setIcon(0, KIcon(px));
        }
}

/*
 * Display a small dialog to rename the currently loaded session.
 */
void sportwatcherWidget::editRename()
{
        bool ok;
        QString name, inhalt;
        QList<QTreeWidgetItem *> item;
        QTreeWidgetItem *lvItem;
        QFileInfo datei;
        RUN_NODE *rn;
        LAP *lap;
        garmin_list *list;
        D1009 *n;

        if(!gmn)
        {
                KMessageBox::error(this, i18n("There is no session selected!"));
                return;
        }

        rn = ds.getRunNode();
        item = ui_sportwatcherWidgetBase.liActivities->selectedItems();
        lvItem = item.first();

        if(!isdigit(rn->run->workout.name[0]))
                inhalt = lvItem->text(0);
        else
                inhalt.clear();

        name = KInputDialog::getText(i18n("Rename session"), i18n("Session name"),
                                     inhalt, &ok, this, (QValidator *)0, QString("Nxxxxxxxxxxxxxx"),
                                     i18n("Enter a new name for the currently selected activity."));

        if(!ok)
                return;

        if(name.length() <= 1)
        {
                lap = ds.getLap(rn->run->first_lap_index);
                const QDateTime *qt = garmin_dtime(lap->start_time);
                QString idx = kl->formatDateTime(*qt, KLocale::ShortDate, true);
                lvItem->setText(0, idx);
                datei.setFile(lvItem->data(0, Qt::UserRole).toString());
                garmin_save_all(gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 1);
                delete qt;
                return;
        }

        strncpy(rn->run->workout.name, name.toAscii().data(), 16);

        if(gmn->type != data_Dlist)
        {
                KMessageBox::error(this, i18n("editRename: Unexpected structure type %1 found!").arg(gmn->type));
                return;
        }

        list = (garmin_list *)gmn->data;

        if(list->head->data->type != data_D1009)        // This should be the run node
        {
                KMessageBox::error(this, i18n("editRename: The run node was not found!"));
                return;
        }

        n = (D1009 *)list->head->data->data;
        strncpy(n->workout.name, rn->run->workout.name, 15);
        lvItem->setText(0, name);
        datei.setFile(lvItem->data(0, Qt::UserRole).toString());
        garmin_save_all(gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 1);
}

void sportwatcherWidget::fileNew()
{
        progressWidget *dlg = new progressWidget(this);

        dlg->show();

        if(!dlg->Download())
        {
                int m, key;

                key = -1;

                for(m = 0; m < garmin_count_error(); m++)
                        KMessageBox::error(this, QString(garmin_get_next_error(&key)));
        }
        else
                getActivities();

        garmin_clear_errors();
        delete dlg;
}

/*
 * This function is called, when the user clicks at the menu point
 * "Save Heart Rate".
 * First, a file dialog box is displayed, where the user can choose a
 * directory and a file name to save the heart rate.
 * If the file could successfully be created, the heart rate is saved
 * in the "HRM"-format. This is the native format Polar uses to store
 * heart rate data. I've choosen this format, because it's popular and
 * used by many other software too.
 */
void sportwatcherWidget::extrasSaveHR()
{
        QString fname, str1, str2;
        QFile fdfile;
        QDateTime *qt, *oldqt;
        QDate dat;
        QTime t;
        QDir dir = QDir::home();
        char hv0[256];
        RUN_NODE *rn;
        LAP *lap, *alap;
        POINT *point;
        int samples, smp, seconds, anz, nsec, samsec;
        int avgHeart, minHeart, maxHeart, aktHeart;
        int secRange1, secRange2, secRange3, secAbove, secBeyond;

        if(!gmn)
        {
                KMessageBox::information(this, i18n("There is no activity open"));
                return;
        }

        if(HRM.isEmpty())
                str1 = dir.path();
        else
                str1 = HRM;

        str1 +=  "/" + StartTime.toString("yyyyMMddThhmmss.zzz.hrm");
        fname = KFileDialog::getSaveFileName(str1, QString("*.hrm"), this, QString("SportWatcher"));

        if(fname.isEmpty())
                return;

        fdfile.setFileName(fname);

        if(fdfile.exists())
        {
                if(KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
                        return;
        }

        if(!fdfile.open(QIODevice::ReadWrite | QIODevice::Truncate))
        {
                KMessageBox::error(this, i18n("Error creating a file!\nPlease check permissions."));
                return;
        }

        rn = ds.getRunNode();
        lap = ds.getLap(rn->run->first_lap_index);
        t = StartTime.time();
        dat = StartTime.date();

        if((point = ds.getPoint(lap->start_time)) == 0)
        {
                fdfile.close();
                return;
        }

        strcpy(hv0, "[Params]\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        str1 = dat.toString("yyyyMMdd");
        str2 = t.toString("hh:mm:ss.z");
        sprintf(hv0, "Version=106\nMonitor=11\nSMode=000000000\nDate=%s\nStartTime=%s\n",
                str1.toAscii().data(), str2.toAscii().data());
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        t.setHMS(0, 0, 0);
        t = t.addSecs(max_time);
        str2 = t.toString("hh:mm:ss.z");

        switch(sampleTime)
        {
                case 0: samsec = 5; break;
                case 1: samsec = 15; break;
                case 2: samsec = 30; break;
                case 3: samsec = 60; break;
                default:
                        samsec = 15;
        }

        sprintf(hv0, "Length=%s\nInterval=%d\nUpper1=%d\nLower1=%d\nUpper2=%d\n",
                str2.toAscii().data(), samsec, upper1, lower1, upper2);
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        sprintf(hv0, "Lower2=%d\nUpper3=%d\nLower3=%d\nTimer1=00:00:00.0\n",
                lower2, upper3, lower3);
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        strcpy(hv0, "Timer2=00:00:00.0\nTimer3=00:00:00.0\nActiveLimit=0\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        sprintf(hv0, "MaxHR=%d\nRestHR=%d\nStartDelay=0\nVO2max=%d\nWeight=%d\n\n",
                MaxHr, restHr, vo2max, weight);
        write(fdfile.handle(), &hv0[0], strlen(hv0));

        // Write the intervall times. One block for every lap
        secRange1 = secRange2 = secRange3 = secAbove = secBeyond = 0;
        strcpy(hv0, "[IntTimes]\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        t.setHMS(0, 0, 0);

        for(unsigned int i = rn->run->first_lap_index; i < rn->run->last_lap_index; i++)
        {
                alap = ds.getLap(i);
                point = ds.getPoint(alap->start_time);
                oldqt = garmin_dtime(point->time);
                avgHeart = minHeart = maxHeart = aktHeart = 0;
                anz = 0;
                unsigned long lastTime = point->time;
                int totSec = 0;

                while(point)
                {
                        if(point->time > (alap->start_time + (alap->total_time / 100)))
                                break;

                        if(point->heart_rate > 0)
                        {
                                avgHeart += point->heart_rate;
                                nsec = point->time - lastTime;
                                totSec += nsec;

                                if(minHeart == 0 || minHeart > point->heart_rate)
                                        minHeart = point->heart_rate;

                                if(maxHeart < point->heart_rate)
                                        maxHeart = point->heart_rate;

                                if(aktHeart == 0 && totSec >= samsec)
                                        aktHeart = avgHeart / (anz + 1);

                                if(point->heart_rate < lower1)
                                        secBeyond += nsec;
                                else if(point->heart_rate < lower2)
                                        secRange1 += nsec;
                                else if(point->heart_rate < lower3)
                                        secRange2 += nsec;
                                else if(point->heart_rate < upper3)
                                        secRange3 += nsec;
                                else
                                        secAbove += nsec;

                                lastTime = point->time;
                                anz++;
                        }

                        point = ds.getPoint(point->time + 1);
                }

                t = t.addSecs(alap->total_time / 100);
                str1 = t.toString("hh:mm:ss.z");

                if(anz > 0)
                        avgHeart = avgHeart / anz;
                else
                        avgHeart = 0;

                sprintf(hv0, "%s\t %d\t %d\t %d\t %d\n",
                        str1.toAscii().data(), aktHeart, minHeart, avgHeart, maxHeart);
                write(fdfile.handle(), &hv0[0], strlen(hv0));
                strcpy(hv0, "32\t 0\t 0\t 0\t 0\t 0\n");
                write(fdfile.handle(), &hv0[0], strlen(hv0));
                strcpy(hv0, "0\t 0\t 0\t 0\t 0\n");
                write(fdfile.handle(), &hv0[0], strlen(hv0));
                sprintf(hv0, "0\t %d\t 0\t 0\t 0\t 0\n", (int)alap->total_distance);
                write(fdfile.handle(), &hv0[0], strlen(hv0));
                strcpy(hv0, "0\t 0\t 0\t 0\t 0\t 0\n");
                write(fdfile.handle(), &hv0[0], strlen(hv0));
        }

        strcpy(hv0, "\n[IntNotes]\n\n[ExtraData]\n\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));

        strcpy(hv0, "[Summary-123]\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // Time limits 1
        smp = max_time - secBeyond - secRange1 - secRange2 - secRange3 - secAbove;
        sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
                max_time, secRange1, secRange2 + secRange3,
                secAbove + secBeyond, smp);
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // limits 1
        sprintf(hv0, "%d\t %d\t %d\t %d\n",
                MaxHr, upper1, lower1, restHr);
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // Time limits 1
        sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
                max_time, secRange2, secRange1 + secRange3,
                secAbove + secBeyond, smp);
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // limits 2
        sprintf(hv0, "%d\t %d\t %d\t %d\n",
                MaxHr, upper2, lower2, restHr);
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // Time limits 2
        sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
                max_time, secRange3, secRange1 + secRange2,
                secAbove + secBeyond, smp);
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // limits 3
        sprintf(hv0, "%d\t %d\t %d\t %d\n",
                MaxHr, upper3, lower3, restHr);
        write(fdfile.handle(), &hv0[0], strlen(hv0));   // Time limits 3
        samples = max_time / samsec;
        sprintf(hv0, "0\t %u\n\n", samples);    // samples
        write(fdfile.handle(), &hv0[0], strlen(hv0));

        strcpy(hv0, "[Summary-TH]\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        sprintf(hv0, "%lu\t 0\t %lu\t %d\t %d\t 0\n", max_time, max_time - max_hr - restHr, max_hr, restHr);
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        sprintf(hv0, "%d\t %d\t %d\t %d\n", MaxHr, upper3, lower1, restHr);
        write(fdfile.handle(), &hv0[0], strlen(hv0));
        sprintf(hv0, "0\t %u\n\n", samples);    // samples
        write(fdfile.handle(), &hv0[0], strlen(hv0));

        sprintf(hv0, "[HRZones]\n%d\n%d\n%d\n%d\n%d\n%d\n0\n0\n0\n0\n0\n\n",
                MaxHr, upper3, upper2, upper1, lower1, restHr);
        write(fdfile.handle(), &hv0[0], strlen(hv0));

        strcpy(hv0, "[HRData]\n");
        write(fdfile.handle(), &hv0[0], strlen(hv0));

        smp = 0;                // average heart rate of 15 seconds
        seconds = 0;
        anz = 0;
        nsec = samsec;
        oldqt = garmin_dtime(lap->start_time);
        qt = 0;
        point = ds.getPoint(lap->start_time);

        while(point)
        {
                if(seconds >= nsec)
                {
                        if(anz > 0)
                        {
                                sprintf(hv0, "%d\n", smp / anz);
                                write(fdfile.handle(), &hv0[0], strlen(hv0));
                        }

                        if(smp > 0 && seconds >= (nsec + samsec))
                        {
                                if(anz <= 0)
                                        anz = 0;

                                for(int x = nsec; x < seconds; x += samsec)
                                {
                                        sprintf(hv0, "%d\n", smp / anz);
                                        write(fdfile.handle(), &hv0[0], strlen(hv0));
                                        nsec += samsec;
                                }
                        }

                        anz = 0;
                        smp = 0;
                        nsec += samsec;
                }

                qt = garmin_dtime(point->time);
                seconds += oldqt->secsTo(*qt);

                if(point->heart_rate > 0)
                {
                        smp += point->heart_rate;
                        anz++;
                }

                delete oldqt;
                oldqt = qt;
                point = ds.getPoint(point->time + 1);
        }

        fdfile.close();
        KMessageBox::information(this, i18n("File successfully written."));
}

void sportwatcherWidget::extrasSettings()
{
        settingsWidget *dlg = new settingsWidget(this);

        if(dlg->exec() == QDialog::Accepted)
        {
                KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
                KConfigGroup ic(&cfg, "SportWatcher");
                lower1 = ic.readEntry("lower1", 0);
                lower2 = ic.readEntry("lower2", 0);
                lower3 = ic.readEntry("lower3", 0);
                upper1 = ic.readEntry("upper1", 0);
                upper2 = ic.readEntry("upper2", 0);
                upper3 = ic.readEntry("upper3", 0);
                MaxHr = ic.readEntry("maxHr", 0);
                restHr = ic.readEntry("restHr", 0);
                vo2max = ic.readEntry("vo2max", 0);
                weight = ic.readEntry("weight", 0);
                sampleTime = ic.readEntry("seconds", 1);
                Serial = ic.readEntry("Serial", false);
                Contour = ic.readEntry("Contour", false);
                Device = ic.readEntry("Device", QString("/dev/ttyUSB0"));
                Forerunner = ic.readEntry("Forerunner", false);
                Data = ic.readEntry("Data", QString("/"));
                HRM = ic.readEntry("HRM", QString("/"));
                MAP = ic.readEntry("MAP", QString("/"));
                Units = ic.readEntry("Units", 0);
                MapType = ic.readEntry("MapType", 0);
        }

        delete dlg;
}

void sportwatcherWidget::extrasWMSSettings()
{
#if defined HAVE_GDAL

        if(MapType == MPT_BMP || MapType == MPT_GIF || MapType == MPT_PNG ||
                          MapType == MPT_TIF)
        {
                coordinatesWidget *idlg = new coordinatesWidget(this);
                idlg->exec();
                delete idlg;
                return;
        }

        if(MapType == MPT_WMS)
        {
                wmsbase *dlg = new wmsbase(this);
                dlg->exec();
                delete dlg;
        }

#if defined HAVE_MAPNIK

        if(MapType == MPT_SHP || MapType == MPT_OSM)
        {
                shapeWidget *dlg = new shapeWidget(this);

                if(MapType == MPT_SHP)
                        dlg->setMapType(shapeWidget::MAP_SHAPE);
                else
                        dlg->setMapType(shapeWidget::MAP_OSM);

                dlg->exec();
                delete dlg;
        }

#else
        KMessageBox::detailedSorry(this,
                                   i18n("This function was disabled at compile time because of missing Mapnik!"),
                                   i18n("SportWatcher needs Mapnik 0.6 or newer, to enable this function.\n") +
                                   i18n("If you like this to be working, install Mapnik and recompile the source."));
#endif

        if(MapType != MPT_WMS && MapType != MPT_SHP && MapType != MPT_OSM)
        {
                KMessageBox::detailedSorry(this,
                                           i18n("You have not choosen a WMS tag file or shape file directory!"),
                                           i18n("This dialog is especialy to set map specific parameters. ") +
                                           i18n("Therefore this dialog is temporary disabled. It will be ") +
                                           i18n("available again, as soon as you choose \"WMS server\" or ") +
                                           i18n("Shape file as your map type."));
                return;
        }

#else
        KMessageBox::detailedSorry(this,
                                   i18n("This function was disabled at compile time because of missing GDAL v1.x.x!"),
                                   i18n("Sportwatcher needs GDAL v1.5.x or newer, to enable this function.\n") +
                                   i18n("If you like this to be working, install GDAL and recompile the source!"));
#endif
}

/*
 * Functions to fill in the boxes of the main mask.
 */
void sportwatcherWidget::showLaps()
{
        QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
        QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
        QString qs_totdist;
        QDateTime dt;
        QTime t, st;
        QDateTime *qt;
        LAP *lap;
        POINT *point;
        RUN_NODE *rakt, *rn;
        int laps, i, anz, men, cad;
        double alt_asc, alt_dsc, sum_asc, sum_dsc, old_asc, old_dsc;
        double totdist;
        bool pause;

        if(!DIRTY)
                return;

        if(!gmn)
                return;

        if(gmn->type == data_Dnil)
        {
                KMessageBox::error(this, i18n("No data found!"));
                return;
        }

        if(gmn->type != data_Dlist)      /* List of data */
        {
                KMessageBox::error(this, i18n("Found unexpected data type %1!").arg(gmn->type));
                return;
        }

        ds.destroy();
        min_hr = max_hr = avg_hr = 0;
        min_height = max_height = 0.0;
        min_speed = max_speed = 0.0;
        totdist = 0.0;
        // Tab Summary
        ui_sportwatcherWidgetBase.liLaps->clear();
        ui_sportwatcherWidgetBase.liLaps->setAllColumnsShowFocus(true);
        // Tab Laps
        ui_sportwatcherWidgetBase.twLaps->clear();
        ds.garmin_print_data(gmn);

        if(!(rn = ds.getRunNode()))
                return;

        rakt = rn;
        // Tab Summary
        ui_sportwatcherWidgetBase.liLaps->setRootIsDecorated(true);

        for(i = 1; i < 12; i++)
                ui_sportwatcherWidgetBase.liLaps->setColumnAlignment(i, Qt::AlignRight);

        // Tab Laps
        ui_sportwatcherWidgetBase.edTotalDistance->clear();
        ui_sportwatcherWidgetBase.edTotalTime->clear();
        ui_sportwatcherWidgetBase.edAvgSpeed->clear();
        ui_sportwatcherWidgetBase.edTotalHeight->clear();
        ui_sportwatcherWidgetBase.edAvgHR->clear();
        ui_sportwatcherWidgetBase.edLapNumber->clear();

        qs_name = qs_distance = qs_etime = qs_avgpace = qs_avgspeed = qs_maxspeed = QString("");
        qs_calories = qs_avghr = qs_maxhr = qs_avgcadence = qs_ascent = qs_descent = QString("");
        men = 0;
        cad = 0;

        // The main loop.
        // If a supported run type is detected, it will be processed.
        while(rakt)
        {
                // Check for a supported run type
                if(rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
                                  rakt->run->type == data_D1010)
                {
                        int cal, ahr, mhr;
                        double distance, speed, mspeed;
                        QDate dat;

                        // Set the name depending on the sport type
                        // This is used on the tab "Summary"
                        switch(rakt->run->sport_type)
                        {
                                case D1000_running: qs_name = i18n("Running: "); break;
                                case D1000_biking:  qs_name = i18n("Biking: "); break;
                                case D1000_other:   qs_name = i18n("Other: "); break;
                                default:
                                        qs_name = i18n("Unknown: ");
                        }

                        if(!(lap = ds.getLap(rakt->run->first_lap_index)))
                                return;

                        qt = garmin_dtime(lap->start_time);
                        StartTime = *qt;
                        st = qt->time();
                        dat = qt->date();
                        delete qt;
                        qt = 0;

                        // Find the last track;
                        //    It is possible to delete laps directly on the watch,
                        //    so we can't be sure the last lap is really the last one.
                        //    Tracks are not deleted and the last track contains the
                        //    summuraries we need.
                        if(!(point = ds.getLastPoint()))
                        {
                                KMessageBox::error(this, i18n("Error getting the last messure point!"));
                                return;
                        }

                        qt = garmin_dtime(point->time);
                        t = qt->time();
                        t.setHMS(0, 0, 0);
                        t = t.addSecs(ds.getTotalTime());
                        qt->setDate(dat);
                        qt->setTime(t);
                        qs_name.append(kl->formatDate(dat, KLocale::ShortDate));
                        qs_name.append(" ");
                        qs_name.append(kl->formatTime(st, true));
                        max_time = ds.getTotalTime();
                        qs_etime = QString(qt->toString("hh:mm:ss.zzz"));

                        distance = 0.0;
                        cal = 0;
                        mspeed = 0;
                        ahr = mhr = 0;
                        anz = 0;
                        cad = 0;
                        sum_asc = sum_dsc = old_asc = old_dsc = 0;

                        // Find out the total distance, calories, maximum speed,
                        // maximum heart rate and the average heart rate. Get this
                        // values from the lap summary the watch made.
                        for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
                        {
                                if((lap = ds.getLap(i)) == NULL)
                                        continue;

                                distance += lap->total_distance;
                                cal += lap->calories;

                                if(lap->avg_cadence != 0xff)
                                        cad += lap->avg_cadence;

                                ahr += lap->avg_heart_rate;
                                anz++;

                                if(lap->max_speed > mspeed)
                                        mspeed = lap->max_speed;

                                if(lap->max_heart_rate > mhr)
                                        mhr = lap->max_heart_rate;
                        }

                        total_distance = distance = ds.getTotalDistance();

                        if(Units == 1)          // Statute?
                                qs_distance.sprintf("%.2f ft", distance / 0.304);
                        else
                                qs_distance.sprintf("%.2f m", distance);

                        if(distance > 0)
                        {
                                QTime tt = qt->time();
                                long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;

                                if(Units == 0)
                                        secs = secs * (1000.0 / distance * 100.0);
                                else
                                        secs = secs * (1609.344 / distance * 100.0);

                                int h = secs / 3600;
                                int m = (secs - (h * 3600)) / 60;
                                int s = secs - ((h * 3600) + (m * 60));
                                t = QTime(h, m, s, 0);
                                qs_avgpace = QString("  ") + kl->formatTime(t, true);

                                if(Units == 0)
                                        qs_avgpace.append(QString(" /km"));
                                else
                                        qs_avgpace.append(QString(" /mi"));
                        }

                        if(Units == 1)          // Statute?
                                speed = distance / ds.getTotalTime() * 3.6 / 1.609344;
                        else
                                speed = distance / ds.getTotalTime() * 3.6;

                        qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
                        qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
                        qs_calories.sprintf("%d", cal);
                        qs_avghr.sprintf("%d bpm", ahr / anz);
                        qs_maxhr.sprintf("%d bpm", mhr);

                        if(cad > 0)
                                qs_avgcadence.sprintf("%d", cad / anz);

                        // Add the summary line columns to the tab "Summary"
                        K3ListViewItem *element = new K3ListViewItem(ui_sportwatcherWidgetBase.liLaps,
                                          qs_name, kl->formatNumber(qs_distance, false),
                                          qs_etime, qs_avgpace, kl->formatNumber(qs_avgspeed, false),
                                          kl->formatNumber(qs_maxspeed, false), qs_calories, qs_avghr);
                        element->setText(8, qs_maxhr);
                        element->setText(9, qs_avgcadence);
                        element->setText(10, kl->formatNumber(qs_ascent, false));
                        element->setText(11, kl->formatNumber(qs_descent, false));
                        element->sortChildItems(0, false);
                        element->setOpen(true);
                        element->setPixmap(0, KIcon(QString("activity")).pixmap(16));
                        ui_sportwatcherWidgetBase.liLaps->insertItem(element);
                        // Add some of the summaries to the fields on the tab "Lap details"
                        ui_sportwatcherWidgetBase.edTotalDistance->setAlignment(Qt::AlignRight);
                        ui_sportwatcherWidgetBase.edTotalDistance->insert(kl->formatNumber(qs_distance, false));
                        ui_sportwatcherWidgetBase.edTotalTime->setAlignment(Qt::AlignRight);
                        ui_sportwatcherWidgetBase.edTotalTime->insert(qs_etime);
                        ui_sportwatcherWidgetBase.edAvgSpeed->setAlignment(Qt::AlignRight);
                        ui_sportwatcherWidgetBase.edAvgSpeed->insert(kl->formatNumber(qs_avgspeed, false));
                        ui_sportwatcherWidgetBase.edTotalHeight->setAlignment(Qt::AlignRight);
                        ui_sportwatcherWidgetBase.edTotalHeight->insert(kl->formatNumber(qs_ascent, false));
                        ui_sportwatcherWidgetBase.edAvgHR->setAlignment(Qt::AlignRight);
                        ui_sportwatcherWidgetBase.edAvgHR->insert(qs_avghr);
                        delete qt;
                        /* Get the laps. */
                        laps = 1;

                        for(i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
                        {
                                double spd;
                                char *un;

                                if((lap = ds.getLap(i)) == NULL)
                                        continue;

                                qt = garmin_dtime(lap->start_time);
                                qs_name.sprintf("Lap %03d - ", laps);
                                qs_name.append(kl->formatTime(qt->time(), true));
                                qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
                                totdist += (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance;
                                qs_totdist.sprintf("%2.f %s", totdist, (Units == 1) ? "ft" : "m");
                                t = QTime(0, 0, 0, 0);
                                t = t.addMSecs(lap->total_time * 10);
                                qs_etime = t.toString("hh:mm:ss.zzz");
                                spd = lap->total_distance / (lap->total_time / 100.0);
                                delete qt;
                                qt = 0;

                                if(Units == 0)
                                {
                                        un = (char *)"km/h";
                                        spd *= 3.6;
                                }
                                else
                                {
                                        spd *= 3.6 / 1.609344;
                                        un = (char *)"mph";
                                }

                                qs_avgspeed.sprintf("%.2f %s", spd, un);
                                qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? lap->max_speed * 3.6 / 1.609344 : lap->max_speed * 3.6, un);
                                qs_calories.sprintf("%d", lap->calories);

                                if(lap->total_distance > 0 && lap->total_time != 0)
                                {
                                        double fact;

                                        if(Units == 0)
                                                fact = 1000.0;          // 1 km
                                        else
                                                fact = 1609.344;                // 1 mile in meters

                                        long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
                                        int h = secs / 3600;
                                        int m = (secs - (h * 3600)) / 60;
                                        int s = secs - ((h * 3600) + (m * 60));
                                        t = QTime(h, m, s, 0);
                                        qs_avgpace = kl->formatTime(t, true);

                                        if(Units == 0)
                                                qs_avgpace.append(QString(" /km"));
                                        else
                                                qs_avgpace.append(QString(" /mi"));
                                }

                                qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
                                qs_maxhr.sprintf("%d bpm", lap->max_heart_rate);

                                anz = 0;
                                alt_asc = alt_dsc = 0;
                                // Add a new detail line to the tab "Lap details"
                                QTreeWidgetItem * trdetail = new QTreeWidgetItem(ui_sportwatcherWidgetBase.twLaps);

                                if((point = ds.getPoint(lap->start_time)) != 0)
                                {
                                        if(point->alt < 20000)
                                        {
                                                alt_dsc = alt_asc = point->alt;

                                                if(old_asc == 0)
                                                        old_asc = alt_asc;

                                                if(old_dsc == 0)
                                                        old_dsc = alt_dsc;
                                        }
                                        else
                                                alt_dsc = alt_asc = 0;

                                        POINT *oldPoint = 0;
                                        double sc, dist, speed;
                                        unsigned long t1, t2;
                                        t1 = t2 = 0;
                                        pause = false;
                                        bool ignore = false;

                                        while(point)
                                        {
                                                if(point->time > (lap->start_time + (lap->total_time / 100)))
                                                        break;

                                                QTreeWidgetItem *child = new QTreeWidgetItem(trdetail);
                                                qt = garmin_dtime(point->time);
                                                child->setText(0, kl->formatTime(qt->time(), true));
                                                child->setTextAlignment(0, Qt::AlignRight);
                                                child->setText(8, QString("%1 %2").arg(kl->formatNumber((double)point->heart_rate, 0)).arg(" bpm"));
                                                child->setTextAlignment(8, Qt::AlignRight);

                                                if(point->cadence < 0xff)
                                                {
                                                        child->setText(10, kl->formatNumber((double)point->cadence, 0));
                                                        child->setTextAlignment(10, Qt::AlignRight);
                                                }

                                                if(point->alt < 20000)
                                                {
                                                        double alt = (Units == 0) ? (double)point->alt : (double)point->alt / 0.304;

                                                        child->setText(11, QString("%1 %2").arg(kl->formatNumber(alt, 2)).arg((Units == 0) ? QString(" m") : QString(" ft")));
                                                        child->setTextAlignment(11, Qt::AlignRight);
                                                }

                                                if(!oldPoint)
                                                        oldPoint = point;

                                                if(point->alt > alt_asc && point->alt < 20000)
                                                {
                                                        alt_asc = point->alt;

                                                        if(alt_dsc == 0)
                                                                alt_dsc = point->alt;
                                                }

                                                if(point->alt < alt_dsc)
                                                        alt_dsc = point->alt;

                                                // save the min and max values. We need this information to
                                                // build the graphics.
                                                if(point->heart_rate > max_hr && point->heart_rate < 250)
                                                        max_hr = point->heart_rate;

                                                if((min_hr == 0 && point->heart_rate > 0 && point->heart_rate < 250)
                                                                  || (point->heart_rate > 0 && point->heart_rate < min_hr))
                                                        min_hr = point->heart_rate;

                                                if(point->alt < 20000 && max_height < point->alt)
                                                        max_height = point->alt;

                                                if(point->alt < 20000 && (min_height == 0.0 || min_height > point->alt))
                                                        min_height = point->alt;

                                                // Calculate speed of current track
                                                if(!pause && point->distance > 1.0e10)
                                                {
                                                        t1 = point->time;
                                                        pause = true;
                                                        ignore = true;
                                                }
                                                else if(pause)
                                                {
                                                        t2 = point->time;
                                                        pause = false;
                                                        point = ds.getPoint(point->time + 1);
                                                        continue;
                                                }

                                                if(!ignore && !pause)
                                                {
                                                        sc = point->time - oldPoint->time;
                                                        dist = point->distance - oldPoint->distance;

                                                        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")));
                                                        child->setTextAlignment(1, Qt::AlignRight);

                                                        if(t2 > t1)
                                                                sc -= t2 - t1;

                                                        if(sc > 0.0)
                                                        {
                                                                speed = (dist / sc) * 3.6;

                                                                if(speed > lap->max_speed * 3.6)
                                                                        speed = lap->max_speed * 3.6;
                                                        }
                                                        else
                                                                speed = 0.0;

                                                        if(Units == 1)
                                                                speed /= 1.609344;

                                                        child->setText(5, QString("%1 %2").arg(kl->formatNumber(speed, 2)).arg((Units == 0) ? QString(" Km/h") : QString(" mi/h")));
                                                        child->setTextAlignment(5, Qt::AlignRight);

                                                        if(speed > 0.0 && speed < 400.0 && max_speed < speed)
                                                                max_speed = speed;

                                                        if(speed > 0.0 && (min_speed == 0.0 || min_speed > speed))
                                                                min_speed = speed;

                                                        oldPoint = point;
                                                }

                                                if(!pause && ignore)
                                                        ignore = false;

                                                if(point->heart_rate > 0 && point->heart_rate < 250)
                                                {
                                                        avg_hr += point->heart_rate;
                                                        men++;
                                                }

                                                point = ds.getPoint(point->time + 1);
                                        }

                                        if(old_asc < alt_asc)
                                                sum_asc += (alt_asc - old_asc);

                                        if(old_dsc > alt_dsc)
                                                sum_dsc += (old_dsc - alt_dsc);

                                        old_asc = alt_asc;
                                        old_dsc = alt_dsc;
                                        qs_ascent.sprintf("%.2f %s", (Units == 1) ? (alt_asc / 0.304) : alt_asc, (Units == 1) ? "ft" : "m");
                                        qs_descent.sprintf("%.2f %s", (Units == 1) ? (alt_dsc / 0.304) : alt_dsc, (Units == 1) ? "ft" : "m");
                                }

                                if(lap->avg_cadence != 0xff)
                                        qs_avgcadence.sprintf("%d", lap->avg_cadence);

                                // Add a new detail line to the tab "Summary"
                                K3ListViewItem *edetail = new K3ListViewItem(element, qs_name,
                                                  kl->formatNumber(qs_distance, false),
                                                  qs_etime, qs_avgpace, kl->formatNumber(qs_avgspeed, false),
                                                  kl->formatNumber(qs_maxspeed, false), qs_calories, qs_avghr);
                                edetail->setText(8, qs_maxhr);
                                edetail->setText(9, qs_avgcadence);
                                edetail->setText(10, kl->formatNumber(qs_ascent, false));
                                edetail->setText(11, kl->formatNumber(qs_descent, false));
                                edetail->setPixmap(0, KIcon(QString("history")).pixmap(16));
                                QPixmap qpx = KIcon(QString("other")).pixmap(16);

                                trdetail->setText(0, qs_etime);
                                trdetail->setTextAlignment(0, Qt::AlignRight);
                                trdetail->setText(1, kl->formatNumber(qs_distance));
                                trdetail->setTextAlignment(1, Qt::AlignRight);
                                trdetail->setText(2, kl->formatNumber(qs_totdist));
                                trdetail->setTextAlignment(2, Qt::AlignRight);
                                trdetail->setText(4, qs_avgpace);
                                trdetail->setTextAlignment(4, Qt::AlignRight);
                                trdetail->setText(5, kl->formatNumber(qs_avgspeed, false));
                                trdetail->setTextAlignment(5, Qt::AlignRight);
                                trdetail->setText(6, kl->formatNumber(qs_maxspeed, false));
                                trdetail->setTextAlignment(6, Qt::AlignRight);
                                trdetail->setText(7, qs_calories);
                                trdetail->setTextAlignment(7, Qt::AlignRight);
                                trdetail->setText(8, qs_avghr);
                                trdetail->setTextAlignment(8, Qt::AlignRight);
                                trdetail->setText(9, qs_maxhr);
                                trdetail->setTextAlignment(9, Qt::AlignRight);
                                trdetail->setText(10, qs_avgcadence);
                                trdetail->setTextAlignment(10, Qt::AlignRight);
                                trdetail->setText(11, kl->formatNumber(qs_ascent, false));
                                trdetail->setTextAlignment(11, Qt::AlignRight);

                                switch(rakt->run->sport_type)
                                {
                                        case D1000_running:
                                                edetail->setPixmap(0, KIcon(QString("spw-running")).pixmap(16));
                                                break;

                                        case D1000_biking:
                                                edetail->setPixmap(0, KIcon(QString("bike")).pixmap(16));
                                                break;

                                        case D1000_other:
                                                edetail->setPixmap(0, qpx);
                                                break;

                                        default:
                                                edetail->setPixmap(0, qpx);
                                }

                                ui_sportwatcherWidgetBase.liLaps->clearSelection();
                                element->insertItem(edetail);
                                delete qt;
                                laps++;
                        }

                        qs_ascent.sprintf("%.2f %s", (Units == 1) ? sum_asc / 0.304 : sum_asc, (Units == 1) ? "ft" : "m");
                        qs_descent.sprintf("%.2f %s", (Units == 1) ? sum_dsc / 0.304 : sum_dsc, (Units == 1) ? "ft" : "m");
                        element->setText(10, qs_ascent);
                        element->setText(11, qs_descent);
                        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");
                        ui_sportwatcherWidgetBase.edTotalHeight->clear();
                        ui_sportwatcherWidgetBase.edTotalHeight->insert(qs_ascent);
                        ui_sportwatcherWidgetBase.edLapNumber->setAlignment(Qt::AlignRight);
                        ui_sportwatcherWidgetBase.edLapNumber->insert(kl->formatNumber((double)laps, 0));
                }

                rakt = rakt->next;
        }

        if(men > 0)
                avg_hr /= men;
        else
                min_hr = max_hr = avg_hr = 0;
}

void sportwatcherWidget::showTrack()
{
        showTrack(0, QRect(0, 0, 0, 0), 0);
}

void sportwatcherWidget::showTrack(int zoom)
{
        showTrack(zoom, mapPan, mapLap);
}

void sportwatcherWidget::showTrack(int zoom, const QRect &pan, LAP *lap)
{
        int width, height;
        double x1, y1, x2, y2;
        int a, top, left, panX, panY;
        uint32 i;
        double coordW, coordH, tick;
        double meterW, dist, fact;
        QPainter paint;
        posn_type posNW, posSE, posLXY, posRXY;
        POINT *point;
        bool Fgeo = false;
        bool Data = false;
#if defined HAVE_GDAL
        QString fName = MAP;
//double adfGeoTransform[6];
        GDALDataset *poDataset = 0;
        GDALRasterBand *poBand = 0;
        unsigned char *pafScanline = 0;
        unsigned char *pafScanlineRed = 0;
        unsigned char *pafScanlineGreen = 0;
        unsigned char *pafScanlineBlue = 0;
        unsigned char *pafScanlineAlpha = 0;
        int nXSize, nYSize;
        int xOff, yOff;
        double oriLeftLon, oriLeftLat, oriRightLon, oriRightLat;
#endif

        if(!DIRTY || curTab == 2 || curTab == 3)
                return;

        if(!gmn)
                return;

        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

        if(zoom != zfactor)
                zfactor = zoom;

        if(mapLap != lap)
                mapLap = lap;

        y2 = x2 = 0;
#if defined HAVE_GDAL
        nXSize = nYSize = 0;
        KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
        KConfigGroup wms(&cfg, "WMS");
        bool square = wms.readEntry("Square", false);
        int CorrX = wms.readEntry("CorrX", 0);
        int CorrY = wms.readEntry("CorrY", 0);
        KConfigGroup ic(&cfg, "ImageCoords");
        oriLeftLon = ic.readEntry("LeftLon", 0.0);
        oriLeftLat = ic.readEntry("LeftLat", 0.0);
        oriRightLon = ic.readEntry("RightLon", 0.0);
        oriRightLat = ic.readEntry("RightLat", 0.0);
//      int isrs = ic.readEntry("SRS", 0);
#endif

        if(curTab == 0 && !ActivePrint)
        {
                width = ui_sportwatcherWidgetBase.imgMap->width() - 2;
                height = ui_sportwatcherWidgetBase.imgMap->height();
        }
        else if(ActivePrint)
        {
                width = pmPrMap.width();
                height = pmPrMap.height();
        }
        else
        {
                width = ui_sportwatcherWidgetBase.grMap->width() - 2;
                height = ui_sportwatcherWidgetBase.grMap->height();
        }

#if defined HAVE_GDAL

        if(MapType == MPT_WMS && square)
                pmMap = QPixmap(width / (int)mFactor * (int)mFactor, height / (int)mFactor * (int)mFactor);
        else
                pmMap = QPixmap(width, height);

#else
        pmMap = QPixmap(width, height);
#endif

        if(pmMap.isNull())
                return;

        // Here we begin do draw something
        paint.begin(&pmMap);

        panX = panY = 0;

        if(stateHand && mapPan != pan)
        {
                mapPan = pan;
                panX = mapPan.right() - mapPan.left();
                panY = mapPan.bottom() - mapPan.top();
                oldTransX += (double)panX;
                oldTransY += (double)panY;
        }

        memset(&posNW, 0, sizeof(posn_type));
        memset(&posSE, 0, sizeof(posn_type));

        posSE.lat = 90.0;
        posSE.lon = 180.0;
        posNW.lat = -90.0;
        posNW.lon = -180.0;

        /*
         * Find out the corners of our track (NW, NE, SE, SW)
         */
        if(mapLap)
                i = mapLap->start_time;
        else
                i = 0;

        while((point = ds.getPoint(i)) != 0)
        {
                if(mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
                        break;

                if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
                {
                        i = point->time + 1;
                        continue;
                }

                if(SEMI2DEG(point->posn.lat) > posNW.lat)
                        posNW.lat = SEMI2DEG(point->posn.lat);

                if(SEMI2DEG(point->posn.lat) < posSE.lat)
                        posSE.lat = SEMI2DEG(point->posn.lat);

                if(SEMI2DEG(point->posn.lon) > posNW.lon)
                        posNW.lon = SEMI2DEG(point->posn.lon);

                if(SEMI2DEG(point->posn.lon) < posSE.lon)
                        posSE.lon = SEMI2DEG(point->posn.lon);

                i = point->time + 1;
                Data = true;
        }

        coordW = (posNW.lon > posSE.lon) ? posNW.lon - posSE.lon : posSE.lon - posNW.lon;
        coordH = (posNW.lat > posSE.lat) ? posNW.lat - posSE.lat : posSE.lat - posNW.lat;
        meterW = ds.earth_distance(posNW.lat, posNW.lon, posNW.lat, posSE.lon);

        // define the ticks to translate the GPS coordinates into pixels.
        // The track should be centered and we have to calculate the
        // rectangular within we draw the track.
        if(coordW < coordH)
        {
                tick = (double)width / coordW + (double)zoom;

                if((tick * coordH) > height)
                        tick = (double)height / coordH + (double)zoom;
        }
        else
        {
                tick = (double)height / coordH + (double)zoom;

                if((tick * coordW) > width)
                        tick = (double)width / coordW + (double)zoom;
        }

        left = width - (width - tick * coordW) / 2;
        top = (height - tick * coordH) / 2;

        a = tick * coordW;

        if(Units == 0)
                dist = meterW / a;                      // Meters
        else
                dist = meterW * 1.609344 / a;   // 1/1000 mile (5.28 feet)

#if defined HAVE_GDAL
        geoRect.llat = 0.0;
        geoRect.llon = 0.0;
        geoRect.rlat = 0.0;
        geoRect.rlon = 0.0;
        geoRect.width = width;
        geoRect.height = height;

        /*
         * If we have a map file, we try to read it and if successfull,
         * we should get a map painted.
         *
         * Currently only WMS-Server is supported, allthough GDAL allows
         * several other formats too.
         */
        if(!MAP.isEmpty() && Data)
        {
                bool writeTag = true;
                double mtx, mty;
                double vx, vy;

                xOff = yOff = 0;
                posRXY.lon = posNW.lon + (width - left + oldTransX) / tick;
                posLXY.lat = posNW.lat + (top + oldTransY) / tick;
                posLXY.lon = posSE.lon - (left - a - oldTransX) / tick;
                posRXY.lat = posSE.lat - (height - top - (tick * coordH) - oldTransY) / tick;
                geoRect.llat = posLXY.lat;
                geoRect.llon = posLXY.lon;
                geoRect.rlat = posRXY.lat;
                geoRect.rlon = posRXY.lon;
                // width and height of map in meters
                mtx = ds.earth_distance(posRXY.lat, posRXY.lon, posRXY.lat, posLXY.lon);
                mty = ds.earth_distance(posRXY.lat, posRXY.lon, posLXY.lat, posRXY.lon);

                // factor to correct the map, in case we use a WMS server
                if(MapType == MPT_WMS)
                {
                        vx = (posRXY.lon - posLXY.lon) / mtx * CorrX;
                        vy = (posRXY.lat - posLXY.lat) / mty * CorrY;
                        posRXY.lon += vx;
                        posRXY.lat += vy;
                        posLXY.lon += vx;
                        posLXY.lat += vy;
                }

                /*
                 * Write a control file for GDAL, if we use a WMS server.
                 * Warp an image if we use PNG or BMP or GIF.
                 * Warp a region if we use TIFF
                 */
                if(MapType == MPT_WMS)
                        writeTag = writeWMSTag(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat, width, height);

                if(MapType == MPT_GIF || MapType == MPT_BMP || MapType == MPT_PNG ||
                                  MapType == MPT_SGI || MapType == MPT_TIF)
                        writeTag = warpImage(MAP, &fName);

                if(writeTag)
                {
                        if(MapType != MPT_SHP && (poDataset = (GDALDataset *)GDALOpen(fName.toAscii().constData(), GA_ReadOnly)) != NULL)
                        {
                                QPixmap bild;
                                int nRasterCount = poDataset->GetRasterCount();
                                int nXBlock, nYBlock;
                                GDALColorTable *pCT, *pCTb, *pCTr, *pCTg, *pCTa;

                                int      bGotMin, bGotMax;
                                int              tTypeLen; //, tColorEntrys;
                                GDALDataType tRasterType;
                                double   adfMinMax[2];

                                pCT = pCTb = pCTr = pCTg = pCTa = 0;
                                tTypeLen = 0;
                                pafScanlineRed = pafScanlineGreen = pafScanlineBlue = pafScanlineAlpha = 0;
                                Fgeo = true;

                                /*
                                 * Read every raster band.
                                 *
                                 * If we get 3 raster bands, the image is a 24 bit image.
                                 * If we get 4 raster bands, the image is probably a 24 bit
                                 * image with an alpha channel. Currently the alpha channel
                                 * is ignored!
                                 * If we have 1 raster band, the image is 8 bit monochrom.
                                 * Otherwise the image is undefined and the results are also.
                                 */
                                for(a = 1; a <= nRasterCount; a++)
                                {
                                        if(!Fgeo)
                                                break;

                                        if(!(poBand = poDataset->GetRasterBand(a)))
                                        {
                                                paint.end();
                                                return;
                                        }

                                        poBand->GetBlockSize(&nXBlock, &nYBlock);
                                        nXSize = poBand->GetXSize();
                                        nYSize = poBand->GetYSize();
                                        tRasterType = poBand->GetRasterDataType();
                                        tTypeLen = GDALGetDataTypeSize(tRasterType) / 8;        // We need Bytes not Bits!
//                                      tColor = poBand->GetColorInterpretation();

                                        adfMinMax[0] = poBand->GetMinimum(&bGotMin);
                                        adfMinMax[1] = poBand->GetMaximum(&bGotMax);

                                        if(!(bGotMin && bGotMax))
                                                GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);

//                                      if((pCT = poBand->GetColorTable()) != NULL)
//                                              tColorEntrys = poBand->GetColorTable()->GetColorEntryCount();

                                        switch(a)
                                        {
                                                case 1: pafScanlineRed   = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineRed; pCTr = pCT; break;
                                                case 2: pafScanlineGreen = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineGreen; pCTg = pCT; break;
                                                case 3: pafScanlineBlue  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineBlue; pCTb = pCT; break;
                                                case 4: pafScanlineAlpha  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineAlpha; pCTa = pCT; break;
                                        }

                                        if(!pafScanline)
                                        {
                                                paint.end();
                                                KMessageBox::error(this, i18n("Not enough memory for a raster operation!"));
                                                return;
                                        }

                                        memset(pafScanline, 0, tTypeLen * nXSize * nYSize);

                                        /*
                                         * Get the image (from the server) and put the tiles together.
                                         *
                                         * The function reads only one raster band. This is,
                                         * because the function is called for every raster band and
                                         * every raster band is stored into a separate array.
                                         */
                                        if(poBand->RasterIO(GF_Read, 0, 0, nXSize, nYSize, pafScanline, nXSize, nYSize, tRasterType, 0, 0) == CE_Failure)
                                        {
                                                paint.end();
                                                KMessageBox::error(this, i18n("Error reading a raster band!"));
                                                paint.begin(&pmMap);
                                                Fgeo = false;
                                                break;
                                        }
                                        else
                                                Fgeo = true;
                                }

                                /*
                                 * Only if Fgeo is TRUE, we've read successfully all raster
                                 * bands. Now we have to put the bands together to get
                                 * an image.
                                 */
                                if(Fgeo)
                                {
                                        unsigned char *pCombinedBytes = new unsigned char[(tTypeLen * nXSize * nYSize * nRasterCount)];
                                        unsigned char *ptr_dest, *ptr_src;
                                        int j;

                                        ptr_dest = ptr_src = 0;

                                        /*
                                         * We need two nested loops to set the pixels in the wanted
                                         * order.
                                         */
                                        for(a = 0, j = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount, j++)
                                        {
                                                int k = a;

                                                for(int m = nRasterCount - 1; m >= 0; m--, k++)
                                                {
                                                        unsigned char *pBytes = 0;

                                                        switch(m)
                                                        {
                                                                case 3: pBytes = pafScanlineAlpha; pCT = pCTa; break;
                                                                case 2: pBytes = pafScanlineBlue; pCT = pCTb; break;
                                                                case 1: pBytes = pafScanlineGreen; pCT = pCTg; break;
                                                                default: pBytes = pafScanlineRed; pCT = pCTr;
                                                        }

                                                        ptr_dest = pCombinedBytes + k;
                                                        unsigned char b = pBytes[j];

                                                        /*
                                                         * If we have a color table, the pixels are pointers
                                                         * to the color table. We need to convert them into
                                                         * 24 bit pixels plus an optional alpha channel.
                                                         */
                                                        if(pCT != NULL)
                                                        {
                                                                GDALColorEntry ce;
                                                                unsigned int c = (unsigned int)b;
                                                                c = pCT->GetColorEntryAsRGB(c, &ce);

                                                                if(m == 0) c = ce.c1;

                                                                if(m == 1) c = ce.c2;

                                                                if(m == 2) c = ce.c3;

                                                                if(m == 3) c = ce.c4;

                                                                b = (unsigned char)c;
                                                        }

                                                        ptr_src = &b;
                                                        memcpy(ptr_dest, ptr_src, 1);
                                                }
                                        }

                                        x1 = y1 = 0;

                                        /*
                                         * The following loop is QT specific! It sets the pixels
                                         * of the raw image, pixel by pixel. This may be slow, but
                                         * everything else didn't work :-(
                                         *
                                         * FIXME: We need a more effective routine to put the
                                         *        raw image into QT's "painter" class.
                                         */
                                        for(a = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount)
                                        {
                                                if(x1 < width && y1 < height)
                                                {
                                                        if(nRasterCount == 3)
                                                                paint.setPen(QPen(QColor((int)pCombinedBytes[a + 2], (int)pCombinedBytes[a + 1], (int)pCombinedBytes[a]), Qt::SolidLine));
                                                        else if(nRasterCount > 3)
                                                                paint.setPen(QPen(QColor(qRgba((int)pCombinedBytes[a + 3], (int)pCombinedBytes[a + 2], (int)pCombinedBytes[a + 1], (int)pCombinedBytes[a])), Qt::SolidLine));
                                                        else if(nRasterCount == 2)
                                                                paint.setPen(QPen(QColor((int)pCombinedBytes[a + 1], (int)pCombinedBytes[a], (int)pCombinedBytes[a + 1]), Qt::SolidLine));
                                                        else if(nRasterCount == 1)
                                                                paint.setPen(QPen(QColor((int)pCombinedBytes[a], (int)pCombinedBytes[a], (int)pCombinedBytes[a]), Qt::SolidLine));

                                                        paint.drawPoint(x1, y1);
                                                }

                                                x1++;

                                                if(x1 >= nXSize)
                                                {
                                                        x1 = 0;
                                                        y1++;
                                                }
                                        }

                                        delete pCombinedBytes;
                                        pCombinedBytes = 0;
                                }

                                if(pafScanlineRed)
                                        delete pafScanlineRed;

                                if(pafScanlineGreen)
                                        delete pafScanlineGreen;

                                if(pafScanlineBlue)
                                        delete pafScanlineBlue;

                                if(pafScanlineAlpha)
                                        delete pafScanlineAlpha;

                                GDALClose(poDataset);
                                poDataset = 0;

                                if(MAP != fName)
                                        unlink(fName.toAscii().data());
                        }

#if defined HAVE_MAPNIK
                        else if(MapType == MPT_SHP)
                        {
                                QDir shpd(MAP, QString("*.shp"));

                                if(shpd.count() < 1)
                                {
                                        KMessageBox::error(this, i18n("There is no shape file in directory %1").arg(MAP));
                                        Fgeo = false;
                                }
                                else
                                {
                                        SRender rd;
                                        QColor bg(220, 220, 220);               // background color

                                        if(curTab == 0 && !ActivePrint)
                                                rd.setDrawArea(ui_sportwatcherWidgetBase.imgMap->width(), ui_sportwatcherWidgetBase.imgMap->height());
                                        else if(!ActivePrint)
                                                rd.setDrawArea(ui_sportwatcherWidgetBase.grMap->width(), ui_sportwatcherWidgetBase.grMap->height());
                                        else if(ActivePrint)
                                                rd.setDrawArea(pmPrMap.width(), pmPrMap.height());

                                        rd.setMapType(SRender::MAP_SHAPE);

                                        if(rd.getMap(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat))
                                        {
                                                paint.fillRect(0, 0, width + 2, height + 2, bg);
                                                paint.drawPixmap(0, 0, rd.pixmap());
                                                Fgeo = true;
                                        }
                                        else
                                                Fgeo = false;
                                }
                        }
                        else if(MapType == MPT_OSM)
                        {
                                QFileInfo osmf(MAP);

                                if(!osmf.exists())
                                {
                                        KMessageBox::error(this, i18n("The OSM file %1 does not exist!").arg(MAP));
                                        Fgeo = false;
                                }
                                else
                                {
                                        SRender rd;
                                        QColor bg(220, 220, 220);               // background color

                                        if(curTab == 0 && !ActivePrint)
                                                rd.setDrawArea(ui_sportwatcherWidgetBase.imgMap->width(), ui_sportwatcherWidgetBase.imgMap->height());
                                        else if(!ActivePrint)
                                                rd.setDrawArea(ui_sportwatcherWidgetBase.grMap->width(), ui_sportwatcherWidgetBase.grMap->height());
                                        else if(ActivePrint)
                                                rd.setDrawArea(pmPrMap.width(), pmPrMap.height());

                                        rd.setMapType(SRender::MAP_OSM);

                                        if(rd.getMap(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat))
                                        {
                                                paint.fillRect(0, 0, width + 2, height + 2, bg);
                                                paint.drawPixmap(0, 0, rd.pixmap());
                                                Fgeo = true;
                                        }
                                        else
                                                Fgeo = false;
                                }
                        }

#endif  // HAVE_MAPNIK
                        else
                        {
                                KMessageBox::error(this, i18n("Error opening map file!"));
                                Fgeo = false;
                        }
                }
        }

#endif  // HAVE_GDAL
        /*
         * Here we come to draw the track. It will be drawn over the previous
         * created map image.
         */
        // Colors and fonts
        QColor background(220, 220, 220);               // background color
        QColor red(255, 0, 0);                          // mile marker
        QColor black(0, 0, 0);                          // Text, center of track
//      QColor yellow(255, 255, 0);
        QColor yellow(0x00cf, 0x00ff, 0x0000);          // color of track
        QFont fntNormal("Helvetica");
        fntNormal.setPixelSize(10);
        fntNormal.setStyleHint(QFont::Helvetica);
        QPen dot(red, 4, Qt::SolidLine);
        QPen line(black, 2, Qt::SolidLine);
        QPen yline(yellow, 4, Qt::SolidLine);

        // Fill background with background colors, if there is no map.
        if(!Fgeo)
                paint.fillRect(0, 0, width + 2, height + 2, background);

        if(Units == 0)
                fact = 1000.0;
        else
                fact = 1609.344;

        paint.setPen(line);
        paint.drawLine(10, height - 9, 10, height - 4);
        paint.drawLine(10, height - 4, 10 + (fact / dist), height - 4);
        paint.drawLine(10 + (fact / dist), height - 9, 10 + (fact / dist), height - 4);
        paint.setFont(fntNormal);

        if(Units == 0)
                paint.drawText(10, height - 10, QString("1000 m"));
        else
                paint.drawText(10, height - 10, QString("5280 ft"));

        // Draw track
        if(mapLap)
                i = mapLap->start_time;
        else
                i = 0;

        x1 = y1 = 0.0;
        bool wStart = false;

        while((point = ds.getPoint(i)) != 0)
        {
                if(mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
                        break;

                if(point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
                {
                        i = point->time + 1;
                        continue;
                }

                x2 = (left + ((posNW.lon - SEMI2DEG(point->posn.lon)) * tick * -1)) + oldTransX;
                y2 = (top + ((posNW.lat - SEMI2DEG(point->posn.lat)) * tick)) + oldTransY;

                if(!wStart && x1 != 0.0 && y1 != 0.0)
                {
                        // Load the start symbol
                        QPixmap qpx(KIcon(QString("wstart")).pixmap(16));
                        // Find the angle of the track and turn the symbol accordingly
                        // we use Pythagoras to calculate the triangle
                        double xl = (x1 < x2) ? x2 - x1 : x1 - x2;
                        double yl = (y1 < y2) ? y2 - y1 : y1 - y2;
                        double da = fmin(xl, yl);
                        double db = fmax(xl, yl);
                        double zl = sqrt(pow(da, 2) + pow(db, 2));
                        double angle = (asin(da / zl) / M_PIl) * 180.0;

                        angle = (angle > 45.0) ? 90.0 - angle : angle;

// cout << "Winkel: " << angle << " ---- X: " << xl << ", Y: " << yl << ", Z: " << zl << ", Point (x1,y1,x2,y2): " << x1 << ", " << y1 << ", " << x2 << ", " << y2 << endl;
                        if(x1 < x2 && y1 < y2)          // right, down
                                angle = 90.0 + angle;
                        else if(x1 > x2 && y1 < y2)     // left, down
                                angle = 270.0 - angle;
                        else if(x1 > x2 && y1 > y2)     // left, up
                                angle = 270.0 + angle;
                        else                            // right, up
                                angle = 90.0 - angle;

// cout << "Realer Winkel: " << angle << endl;
                        // Set the center of the symbol
                        paint.save();
                        paint.translate(x1, y1);
                        // rotate the symbol
                        paint.rotate(angle);
                        paint.drawPixmap(-8, -8, qpx);
                        paint.restore();
                        wStart = true;
                }

                if(x1 == 0.0 && y1 == 0.0)
                {
                        x1 = x2;
                        y1 = y2;
                }

                paint.setPen(yline);
                paint.drawLine(x1, y1, x2, y2);

                if((point->distance - dist) >= fact)    // a dot at every 1000 meters or at 1 mile
                {
                        paint.setPen(dot);
                        paint.drawEllipse(x2 - 2, y2 - 2, 3, 3);
                        dist = (int)(point->distance / fact) * fact;
                }

                paint.setPen(line);
                paint.drawLine(x1, y1, x2, y2);
                x1 = x2;
                y1 = y2;
                i = point->time + 1;
        }

        bool lastLap = false;

        if(mapLap)
                if(ds.getRunNode()->run->last_lap_index == mapLap->index)
                        lastLap = true;

        if((!mapLap || lastLap) && wStart)
        {
                // load the end symbol
                QPixmap qpx(KIcon(QString("wtarget")).pixmap(16));
                paint.drawPixmap(x2, y2 - 16, qpx);
        }

        paint.end();

        if(curTab == 0 && !ActivePrint)
                ui_sportwatcherWidgetBase.imgMap->setPixmap(pmMap);
        else if(ActivePrint)
                pmPrMap = pmMap;
        else
                ui_sportwatcherWidgetBase.grMap->setPixmap(pmMap);

        QApplication::restoreOverrideCursor();
}

void sportwatcherWidget::kcbCurveSlot(int)
{
        DIRTY = true;
        showCurves();
        DIRTY = false;
}

void sportwatcherWidget::tabViewSlot(int tab)
{
        curTab = tab;

        if(tab == 0 && tabDirt0)
        {
                DIRTY = true;
                showLaps();
                showTrack();
                showCurves();
                DIRTY = false;
                tabDirt0 = false;
        }
        else if(tab == 1 && tabDirt1)
        {
                DIRTY = true;

                if(tabDirt0)
                        showLaps();

                showTrack();
                DIRTY = false;
                tabDirt1 = false;
        }
        else if(tab == 2 && tabDirt2)
        {
                DIRTY = true;

                if(tabDirt0)
                        showLaps();

                setMouseTracking(true);
                ui_sportwatcherWidgetBase.tabView->setMouseTracking(true);
                ui_sportwatcherWidgetBase.grHR->setMouseTracking(true);
                ui_sportwatcherWidgetBase.grElevation->setMouseTracking(true);
                ui_sportwatcherWidgetBase.grSpeed->setMouseTracking(true);
                showThreeCurve();
                tabDirt2 = false;
                DIRTY = false;
        }
}

void sportwatcherWidget::showCurves()
{
        showCurves(mapLap);
}

void sportwatcherWidget::showCurves(LAP *lap)
{
        QPainter paint;
        int width, height;
        int i, secs, cuType;
        int lineHeight, margin_left, margin_right, margin_bottom;
        int x1, y1, x2, y2;             // Coordinates
        bool meter;
        double maxHeight, minHeight, maxSpeed, minSpeed;
        int maxHr, minHr, rh;
        POINT *point;
        RUN_NODE *rn;
        LAP *lp;
        double w_tick, h_tick;          // Number of pixels one "tick" has;

        // This depends on the width and height
        // of the image.
        // First we draw a grid based on the min and max
        // values detected in the function showLap(). In case
        // all values are 0, we exit here.
        if(min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
                return;

        if(!DIRTY || curTab != 0)
                return;

        // Look up, what curves we should draw
        cuType = ui_sportwatcherWidgetBase.kcbCurveTypes->currentIndex();
        // Get the dimensions of the available draw area
        width = ui_sportwatcherWidgetBase.imgProfile->width() - 2;
        height = ui_sportwatcherWidgetBase.imgProfile->height();
        pmProfile = QPixmap(width, height);
        paint.begin(&pmProfile);

        // we need a somewhat bigger area to draw our curves than
        // we have with the real min and max values.
        if(max_height > 0.0)
        {
                double add = (max_height - min_height) / 100.0 * 5.0;   // Percent

                maxHeight = max_height + add;
                minHeight = min_height - add;

                if(minHeight < 0.0)             // make sure, we are not too deep
                        minHeight = 0.0;
        }
        else
                maxHeight = minHeight = 0.0;

        if(max_speed > 0.0)
        {
                double add = (max_speed - min_speed) / 100.0 * 5.0;     // Percent

                maxSpeed = max_speed + add;
                minSpeed = min_speed - add;

                if(minSpeed < 0.0)              // make sure, we are not too deep
                        minSpeed = 0.0;
        }
        else
                maxSpeed = minSpeed = 0.0;

        if(max_hr > 0)
        {
                maxHr = max_hr + 10;
                minHr = min_hr - 10;

                if(minHr < 0)
                        minHr = 0;
        }
        else
                maxHr = minHr = 0;

        // Define colors
        QColor background(220, 220, 220);       // Background of graphic
        QColor mark(255, 255, 255);             // Lines inside curve area
        QColor hlight(180, 180, 180);           // area of current lap
//      hlight.setAlpha(128);                   // 50% transparent
        QColor frame(0, 0, 0);                  // Text and borders
        QColor barcol(151, 190, 13);            // heart rate
        QColor barcol2(190, 151, 13);           // height over NN
        QColor red(220, 128, 128);              // speed
        QColor blue(0, 0, 240);
        QFont fntNormal("Helvetica");
//      QFont fntBold("Helvetica", 10, QFont::Bold);
        fntNormal.setPixelSize(10);
        fntNormal.setStyleHint(QFont::Helvetica);
//      fntBold.setPixelSize(10);
//      fntBold.setStyleHint(QFont::Helvetica);
        // Calculate ticks
        margin_left = 52;
        margin_right = 40;
        margin_bottom = 12;
        lineHeight = 10;
        rh = height - margin_bottom - 1;

        w_tick = (double)(width - (margin_left + margin_right)) / (max_time + ds.getPauseTime());       // 1 tick = 1 second

        if(cuType == 1) // Speed and heart rate?
        {
                if((maxSpeed - minSpeed) > (double)(maxHr - minHr))
                {
                        h_tick = (double)rh / (maxSpeed - minSpeed);            // 1 tick = 1 km/h
                        meter = true;
                }
                else
                {
                        h_tick = (double)rh / ((double)maxHr - (double)minHr);  // 1 tick = 1 bpm
                        meter = false;
                }
        }
        else if(cuType == 2)    // Elevation and speed?
        {
                if((maxHeight - minHeight) > (double)(maxHr - minHr))
                {
                        h_tick = (double)rh / (maxHeight - minHeight);          // 1 tick = 1 meter
                        meter = true;
                }
                else
                {
                        h_tick = (double)rh / (maxSpeed - minSpeed);            // 1 tick = 1 km/h
                        meter = false;
                }
        }
        else                    // Elevation and heart rate
        {
                if((maxHeight - minHeight) > (double)(maxHr - minHr))
                {
                        h_tick = (double)rh / (maxHeight - minHeight);          // 1 tick = 1 meter
                        meter = true;
                }
                else
                {
                        h_tick = (double)rh / ((double)maxHr - (double)minHr);  // 1 tick = 1 bpm
                        meter = false;
                }
        }

        // Fill background with background colors
        paint.fillRect(0, 0, width + 4, height + 4, background);
        // Draw a grid with markers at every 10 minutes
        paint.setPen(QPen(frame, 1, Qt::SolidLine));
        // Bottom border line
        x1 = margin_left;
        y1 = height - margin_bottom;
        x2 = width - margin_right;
        y2 = y1;
        paint.drawLine(x1, y1, x2, y2);
        // Left border line
        x1 = x2 = margin_left;
        y1 = 2;
        y2 = height - margin_bottom;
        paint.drawLine(x1, y1, x2, y2);
        // right border line
        x1 = x2 = width - margin_right;
        paint.drawLine(x1, y1, x2, y2);

        // Draw some darker lines to show the laps, if we have one
        // and, in case we have a given lap, we fill the area.
        QDateTime *qt;
        QTime zeit = StartTime.time();
        rn = ds.getRunNode();
        paint.setPen(QPen(hlight, 1, Qt::SolidLine));

        for(i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
        {
                if((lp = ds.getLap(i)) == NULL)
                        continue;

                qt = garmin_dtime(lp->start_time);
                secs = zeit.secsTo(qt->time());
                delete qt;
                x1 = secs * w_tick + margin_left + 1;

                if(lap && lp->start_time == lap->start_time)
                        paint.fillRect(x1, 2, (int)((double)lap->total_time / 100.0 * w_tick), height - margin_bottom - 2, hlight);
                else
                        paint.drawLine(x1, 2, x1, height - margin_bottom);
        }

        // Grid vertical
        paint.setPen(QPen(frame, 1, Qt::SolidLine));
        paint.setFont(fntNormal);
        paint.drawText(margin_left - 20, height - lineHeight, 40, lineHeight, Qt::AlignCenter, QString("00:00"));
        paint.save();
        paint.rotate(270);

        if(cuType == 1)
                paint.setPen(QPen(red, 1, Qt::SolidLine));
        else
                paint.setPen(QPen(barcol, 1, Qt::SolidLine));

        // Information on left side
        if(cuType == 0)
                paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n("Elevation (%1)").arg((Units == 1) ? "ft" : "m"));
        else if(cuType == 1)
                paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n("Speed (%1)").arg((Units == 1) ? "mph" : "km/h"));
        else
                paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n("Elevation (%1)").arg((Units == 1) ? "ft" : "m"));

        if(cuType == 2)
                paint.setPen(QPen(red, 1, Qt::SolidLine));
        else
                paint.setPen(QPen(blue, 1, Qt::SolidLine));

        // Information on right side
        if(cuType < 2)
                paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
        else
                paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Speed (%1)").arg((Units == 1) ? "mph" : "km/h"));

        paint.restore();
        paint.setPen(QPen(mark, 1, Qt::SolidLine));

        // Draw the time scale on the bottom of the graphic
        for(i = 0; (unsigned int)i < (max_time + ds.getPauseTime()); i++)
        {
                if(i > 0 && !(i % 600)) // every 10 minutes
                {
                        x1 = x2 = margin_left + w_tick * i;

                        if(x1 == (width - margin_right))
                                continue;

                        y1 = 2;
                        y2 = height - margin_bottom;
                        paint.drawLine(x1, y1, x2, y2);
                        QTime tm(0, 0, 0);
                        tm = tm.addSecs(i);
                        paint.setPen(QPen(frame, 1, Qt::SolidLine));
//            paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((i >= 3600) ? "hh:mm:ss" : "mm:ss"));
                        paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
                        paint.setPen(QPen(mark, 1, Qt::SolidLine));
                }
        }

        // This is the total time, with pauses included, at the lower right
        // corner of the graphic.
        QTime tm(0, 0, 0);
        QString qs;
        tm = tm.addSecs(max_time + ds.getPauseTime());
        paint.setPen(QPen(frame, 1, Qt::SolidLine));
//      paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((max_time >= 3600) ? "hh:mm:ss" : "mm:ss"));
        paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));

        // Draw the minimal elevation, speed and/or heart rate
        if(max_height > 0.0 || max_speed > 0.0)
        {
                // left side
                if(cuType == 1)
                {
                        paint.setPen(QPen(red, 1, Qt::SolidLine));
                        paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minSpeed));
                }
                else
                {
                        paint.setPen(QPen(barcol, 1, Qt::SolidLine));
                        paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? minHeight / 0.304 : minHeight));
                }
        }

        if(max_hr > 0 || max_speed > 0.0)
        {
                // right side
                if(cuType == 2)
                {
                        paint.setPen(QPen(red, 1, Qt::SolidLine));
                        paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));
                }
                else
                {
                        paint.setPen(QPen(blue, 1, Qt::SolidLine));
                        paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
                }
        }

        paint.setPen(QPen(mark, 1, Qt::SolidLine));

        // Grid horizontal
        int factor = 0;
        int target = 0;

        if(cuType == 0) // Elevation and heart rate
        {
                factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxHr - minHr) / (rh / 12);
                target = (meter) ? (int)(maxHeight - minHeight) : (maxHr - minHr);
        }
        else if(cuType == 1)    // Speed and heart rate
        {
                factor = (meter) ? (maxSpeed - minSpeed) / (rh / 12) : (maxHr - minHr) / (rh / 12);
                target = (meter) ? (int)(maxSpeed - minSpeed) : (maxHr - minHr);
        }
        else                    // Elevation and speed
        {
                factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxSpeed - minSpeed) / (rh / 12);
                target = (meter) ? (int)(maxHeight - minHeight) : (int)(maxSpeed - minSpeed);
        }

        // To prevent a division by zero error, we check the <factor>
        if(factor == 0)
                factor = 1;

        // Beside the horizontal part of the grid, we draw the scale on the
        // left and the right side.
        int oldy = height;

        for(i = 0; i < target; i++)
        {
                if(i > 0 && !(i % factor))
                {
                        x1 = margin_left + 1;
                        x2 = width - margin_right - 1;
                        y1 = y2 = rh - h_tick * i;

                        if(y1 < 12)
                                break;

                        paint.drawLine(x1, y1, x2, y2);

                        if(y1 < (oldy - lineHeight))
                        {
                                if(meter)
                                {
                                        paint.setPen(QPen(barcol, 1, Qt::SolidLine));

                                        // left side
                                        if(cuType == 1)
                                        {
                                                paint.setPen(QPen(red, 1, Qt::SolidLine));
                                                paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + i));
                                        }
                                        else
                                                paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));

                                        // right side
                                        if(maxHr > 0 && cuType != 2)
                                        {
                                                double hrscale = (double)(maxHr - minHr) / (double)target;
                                                paint.setPen(QPen(blue, 1, Qt::SolidLine));
                                                paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", (int)((double)minHr + hrscale * (double)i)));
                                        }
                                        else
                                        {
                                                double spscale = (maxSpeed - minSpeed) / (double)target;

                                                if(cuType == 2)
                                                        paint.setPen(QPen(red, 1, Qt::SolidLine));
                                                else
                                                        paint.setPen(QPen(blue, 1, Qt::SolidLine));

                                                paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", (minSpeed + spscale * (double)i)));
                                        }
                                }
                                else
                                {
                                        // right side
                                        if(cuType == 2)
                                        {
                                                paint.setPen(QPen(red, 1, Qt::SolidLine));
                                                paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
                                        }
                                        else
                                        {
                                                paint.setPen(QPen(blue, 1, Qt::SolidLine));
                                                paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
                                        }

                                        // left side
                                        if((cuType == 0 || cuType == 2) && max_height > 0)
                                        {
                                                double hrscale = (maxHeight - minHeight) / (double)target;
                                                paint.setPen(QPen(barcol, 1, Qt::SolidLine));
                                                paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minHeight + hrscale * (double)i));
                                        }
                                        else if(max_speed > 0 && cuType == 1)
                                        {
                                                double hrscale = (maxSpeed - minSpeed) / (double)target;
                                                paint.setPen(QPen(red, 1, Qt::SolidLine));
                                                paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + hrscale * (double)i));
                                        }
                                }

                                paint.setPen(QPen(mark, 1, Qt::SolidLine));
                                oldy = y1;
                        }
                }
        }

        // To make our graphics more beautiful, we draw lines for the
        // heart rate limits and the average heart rate.
        if(max_hr > 0 && cuType != 2)
        {
                int ay1, ay2, ay3, ay4, ay5;

                x1 = margin_left + 1;
                x2 = width - margin_right - 1;

                if(meter)
                {
                        double hrscale = rh / (double)(maxHr - minHr);
                        ay1 = (double)rh - (double)(lower1 - minHr) * hrscale;
                        ay2 = (double)rh - (double)(lower2 - minHr) * hrscale;
                        ay3 = (double)rh - (double)(lower3 - minHr) * hrscale;
                        ay4 = (double)rh - (double)(upper3 - minHr) * hrscale;
                        ay5 = (double)rh - (double)(avg_hr - minHr) * hrscale;
                }
                else
                {
                        ay1 = (double)rh - (double)(lower1 - minHr) * h_tick;
                        ay2 = (double)rh - (double)(lower2 - minHr) * h_tick;
                        ay3 = (double)rh - (double)(lower3 - minHr) * h_tick;
                        ay4 = (double)rh - (double)(upper3 - minHr) * h_tick;
                        ay5 = (double)rh - (double)(avg_hr - minHr) * h_tick;
                }

                paint.setPen(QPen(barcol2, 1, Qt::DashLine));   // color for limits

                if(lower1 > minHr && lower1 < maxHr)
                        paint.drawLine(x1, ay1, x2, ay1);

                if(lower2 > minHr && lower2 < maxHr)
                        paint.drawLine(x1, ay2, x2, ay2);

                if(lower3 > minHr && lower3 < maxHr)
                        paint.drawLine(x1, ay3, x2, ay3);

                if(upper3 > minHr && upper3 < maxHr)
                        paint.drawLine(x1, ay4, x2, ay4);

                paint.setPen(QPen(red, 1, Qt::DashDotLine));    // color for average heart rate

                if(avg_hr > minHr && avg_hr < maxHr)
                        paint.drawLine(x1, ay5, x2, ay5);
        }

        // Now we have a grid and we've done the scaling.
        // This is the point where we draw the curves itself.
        // We use different colors to draw the lines:
        //
        // Green: Elevation
        // Red:   Speed
        // Blue   Heart Rate
        //
        x1 = x2 = y1 = y2 = 0;
        int hy1, hy2, hx1, hx2;
        int sy1, sy2, sx1, sx2;
        hy1 = hy2 = hx1 = hx2 = 0;
        sy1 = sy2 = sx1 = sx2 = 0;
        int hEc = 0;
        i = 0;
        AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
        avgHfirst = avgHlast = 0;

        // To even the surface lines, we store every altitude in the
        // memory, by building a chain. Then, if the user has set in the
        // settings (Contour == true), we will even the line by calculating
        // the average of 10 messure points and setting every value to the
        // average, who is up or down more than 2 meters from the average.
        while((point = ds.getPoint(i)) != 0)
        {
                if(point->alt > 20000.0 || point->alt < -1000.0)
                {
                        i++;
                        continue;
                }

                if(!avgHeight)
                {
                        avgHeight = new AVGHEIGHT;
                        avgHeight->alt = point->alt;
                        avgHeight->pos = hEc;
                        avgHeight->prev = 0;
                        avgHeight->next = 0;
                        avgHakt = avgHeight;
                        avgHfirst = avgHeight;
                }
                else
                {
                        avgHakt = new AVGHEIGHT;
                        avgHakt->alt = point->alt;
                        avgHakt->pos = hEc;
                        avgHakt->next = 0;
                        avgHakt->prev = avgHeight;
                        avgHeight->next = avgHakt;
                        avgHeight = avgHakt;
                }

                // FIXME: Currently we can not draw below 0 meters, because the
                // base line is always 0!
                if(avgHakt->alt < minHeight)
                        avgHakt->alt = minHeight;

                hEc++;
                i++;
        }

        avgHlast = avgHeight;

        // If wanted, even the lines
        if(Contour && hEc > 0 && cuType != 0)
        {
                double alt[100], avg, avg1, avg2, avg3, avg4;
                int a, pos;

                for(i = 0; i < (hEc + 100); i += 100)
                {
                        avg = avg1 = avg2 = avg3 = avg4 = 0.0;
                        pos = 0;

                        for(a = 0; a < 100; a++)
                        {
                                alt[a] = getAvgAlt(avgHfirst, i + a);
                                avg += alt[a];

                                if(a < 25)
                                        avg1 += alt[a];
                                else if(a < 50)
                                        avg2 += alt[a];
                                else if(a < 75)
                                        avg3 += alt[a];
                                else
                                        avg4 += alt[a];
                        }

                        if((i + 100) >= hEc)
                                avg /= (double)(hEc - i) + 1.0;
                        else
                                avg /= 100.0;

                        for(a = 0; a < 100; a++)
                        {
                                if((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
                                {
                                        if((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
                                                avgHakt->alt = avg;
                                }
                        }
                }
        }

        // plot the elevation, speed and/or heart rate. Depends on <cuType>)
        i = 0;
        int j = 0;
        POINT *oldPoint = 0;
        double speed = 0.0;     // calculated speed
        bool pause = false;     // filter pause out of speed
        unsigned long t1, t2;
        t1 = t2 = 0;

        while((point = ds.getPoint(i)) != 0)
        {
                if(!oldPoint)
                        oldPoint = point;

                // calculate the y position based on the time
                qt = garmin_dtime(point->time);
                secs = zeit.secsTo(qt->time());
                delete qt;
                x2 = secs * w_tick + margin_left + 1;
                hx2 = x2;
                sx2 = x2;

                if(x1 == 0)
                        x1 = x2;

                if(hx1 == 0)
                        hx1 = hx2;

                if(sx1 == 0)
                        sx1 = sx2;

                // The speed is not very exact, because smallest time is
                // one second. This allows a maximum error of 99 hundredths
                // of a second, what is very close to one second. Because of
                // this, speed seems to hop for every messure point. This
                // looks ugly, but currently I don't know how to make it
                // better.
                if(cuType == 1 || cuType == 2)  // Draw speed?
                {
                        double dist;
                        double sc;

                        if(!pause && point->distance > 1.0e10)
                        {
                                pause = true;
                                t1 = point->time;
                        }
                        else if(pause)
                        {
                                pause = false;
                                t2 = point->time;
                                i += 2;
                                continue;
                        }

                        if(point->distance >= 0.1 && point->distance < 1.0e10)
                        {
                                dist = point->distance - oldPoint->distance;
                                sc = point->time - oldPoint->time;
                                LAP *runde = ds.getLapT(point->time);

                                if(t2 > t1)
                                {
                                        sc -= t2 - t1;

                                        if(sc <= 0.0)
                                                sc = 1.0;               // at least 1 second!
                                }

                                speed = (dist / sc) * 3.6;

                                if(runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
                                        speed = runde->max_speed * 3.6;

                                if(Units == 1)
                                        speed /= 1.609344;

                                if(speed < minSpeed || speed > 400.0)
                                        speed = minSpeed;

                                if((meter && cuType == 1) || (!meter && cuType == 2))
                                        y2 = (double)rh - (speed - minSpeed) * h_tick;
                                else
                                {
                                        double hrscale = rh / (maxSpeed - minSpeed);
                                        y2 = (double)rh - (speed - minSpeed) * hrscale;
                                }

                                if(y1 == 0)
                                        y1 = y2;

                                paint.setPen(QPen(red, 1, Qt::SolidLine));
                                paint.drawLine(x1, y1, x2, y2);
                                y1 = y2;
                                x1 = x2;
                                t1 = t2 = 0;
                                oldPoint = point;
                        }
                }

                if(cuType == 0 || cuType == 2)          // Draw elevation?
                {
                        if(point->alt < 20000.0 && point->alt > -1000.0)
                        {
                                double alt = getAvgAlt(avgHfirst, j);

                                j++;

                                if(meter)
                                        sy2 = (double)rh - (alt - minHeight) * h_tick;
                                else
                                {
                                        double hrscale = rh / (maxHeight - minHeight);
                                        sy2 = (double)rh - (alt - minHeight) * hrscale;
                                }

                                if(sy1 == 0)
                                        sy1 = sy2;

                                paint.setPen(QPen(barcol, 1, Qt::SolidLine));
                                paint.drawLine(sx1, sy1, sx2, sy2);
                                sy1 = sy2;
                                sx1 = sx2;
                        }
                }

                if(point->heart_rate > 0 && cuType < 2) // Draw heart rate?
                {
                        if(meter)
                        {
                                double hrscale = rh / (double)(maxHr - minHr);
                                hy2 = (double)rh - (double)(point->heart_rate - minHr) * hrscale;
                        }
                        else
                                hy2 = (double)rh - (double)(point->heart_rate - minHr) * h_tick;

                        if(hy1 == 0)
                                hy1 = hy2;

                        paint.setPen(QPen(blue, 1, Qt::SolidLine));
                        paint.drawLine(hx1, hy1, hx2, hy2);
                        hy1 = hy2;
                        hx1 = hx2;
                }

                i++;
        }

        paint.end();
        ui_sportwatcherWidgetBase.imgProfile->setPixmap(pmProfile);

        // free the chain of altitudes
        avgHakt = avgHfirst;

        while(avgHakt)
        {
                avgHeight = avgHakt->next;
                delete avgHakt;
                avgHakt = avgHeight;
        }

        DIRTY = false;
}

void sportwatcherWidget::showThreeCurve(int pw, int ph)
{
        QPainter ptHR, ptElevation, ptSpeed;
        int width, height, wdHR, htHR, wdElev, htElev, wdSpeed, htSpeed;
        int i, secs;
        int lineHeight, margin_left, margin_right, margin_bottom;
        int x1, y1, x2, y2;             // Coordinates
        double maxHeight, minHeight, maxSpeed, minSpeed;
        int maxHr, minHr, rh, rhHR, rhElev, rhSpeed;
        POINT *point;
        RUN_NODE *rn;
        LAP *lp;
        double wtiHR, htiHR, wtiElev, htiElev, wtiSpeed, htiSpeed;
        double w_tick, h_tick;          // Number of pixels one "tick" has;

        // This depends on the width and height
        // of the image.
        // First we draw a grid based on the min and max
        // values detected in the function showLap(). In case
        // all values are 0, we exit here.
        if(min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
                return;

        if(!ActivePrint && (!DIRTY || curTab != 2))
                return;

        w_tick = h_tick = 0.0;
        rh = 0;
        width = height = 0;

        // Get the dimensions of the available draw area
        // First for heart rate
        if(!ActivePrint)
        {
                wdHR = ui_sportwatcherWidgetBase.grHR->width() - 2;
                htHR = ui_sportwatcherWidgetBase.grHR->height();
                pmHR = QPixmap(wdHR, htHR);
                // Then for elevation
                wdElev = ui_sportwatcherWidgetBase.grElevation->width() - 2;
                htElev = ui_sportwatcherWidgetBase.grElevation->height();
                pmElevation = QPixmap(wdElev, htElev);
                // And at last for speed
                wdSpeed = ui_sportwatcherWidgetBase.grSpeed->width() - 2;
                htSpeed = ui_sportwatcherWidgetBase.grSpeed->height();
                pmSpeed = QPixmap(wdSpeed, htSpeed);
                // Initialize QPainter
                ptHR.begin(&pmHR);
                ptElevation.begin(&pmElevation);
                ptSpeed.begin(&pmSpeed);
        }
        else if(ActivePrint && pw > 0 && ph > 0)
        {
                wdHR = wdElev = wdSpeed = pw;
                htHR = htElev = htSpeed = ph;
                prHR = prElevation = prSpeed = QPixmap(pw, ph);
                ptHR.begin(&prHR);
                ptElevation.begin(&prElevation);
                ptSpeed.begin(&prSpeed);
        }
        else
                return;

        // we need a somewhat bigger area to draw our curves than
        // we have with the real min and max values.
        if(max_height > 0.0)
        {
                double add = (max_height - min_height) / 100.0 * 5.0;   // Percent

                maxHeight = max_height + add;
                minHeight = min_height - add;

                if(minHeight < 0.0)             // make sure, we are not too deep
                        minHeight = 0.0;
        }
        else
                maxHeight = minHeight = 0.0;

        if(max_speed > 0.0)
        {
                double add = (max_speed - min_speed) / 100.0 * 5.0;     // Percent

                maxSpeed = max_speed + add;
                minSpeed = min_speed - add;

                if(minSpeed < 0.0)              // make sure, we are not too deep
                        minSpeed = 0.0;
        }
        else
                maxSpeed = minSpeed = 0.0;

        if(max_hr > 0)
        {
                maxHr = max_hr + 10;
                minHr = min_hr - 10;

                if(minHr < 0)
                        minHr = 0;
        }
        else
                maxHr = minHr = 0;

        // Define colors
        QColor background(220, 220, 220);       // Background of graphic
        QColor mark(255, 255, 255);             // Lines inside curve area
        QColor hlight(180, 180, 180);           // area of current lap
        hlight.setAlpha(128);                   // 50% transparent
        QColor frame(0, 0, 0);                  // Text and borders
        QColor barcol(151, 190, 13);            // heart rate
        QColor barcol2(190, 151, 13);           // height over NN
        QColor red(220, 128, 128);              // speed
        QColor blue(0, 0, 240);
        QFont fntNormal("Helvetica");
//      QFont fntBold("Helvetica", 10, QFont::Bold);
        fntNormal.setPixelSize(10);
        fntNormal.setStyleHint(QFont::Helvetica);
//      fntBold.setPixelSize(10);
//      fntBold.setStyleHint(QFont::Helvetica);
        // Calculate ticks
        margin_left = 1;
        margin_right = 40;
        margin_bottom = 12;
        lineHeight = 10;
//      rh = height - margin_bottom - 1;

        // Calculate the ticks for width and height for every draw area
        for(i = 0; i < 3; i++)
        {
                if(i == 2)      // Speed?
                {
                        rhSpeed = htSpeed - margin_bottom - 1;
                        wtiSpeed = (double)(wdSpeed - (margin_left + margin_right)) / (max_time + ds.getPauseTime());   // 1 tick = 1 second
                        htiSpeed = (double)rhSpeed / (maxSpeed - minSpeed);             // 1 tick = 1 km/h
                }
                else if(i == 1) // Elevation?
                {
                        rhElev = htElev - margin_bottom - 1;
                        wtiElev = (double)(wdElev - (margin_left + margin_right)) / (max_time + ds.getPauseTime());     // 1 tick = 1 second
                        htiElev = (double)rhElev / (maxHeight - minHeight);             // 1 tick = 1 meter
                }
                else                    // heart rate
                {
                        rhHR = htHR - margin_bottom - 1;
                        wtiHR = (double)(wdHR - (margin_left + margin_right)) / (max_time + ds.getPauseTime()); // 1 tick = 1 second
                        htiHR = (double)rhHR / ((double)maxHr - (double)minHr); // 1 tick = 1 bpm
                }
        }

        // Fill background with background colors
        ptHR.fillRect(0, 0, wdHR + 4, htHR + 4, background);
        ptElevation.fillRect(0, 0, wdElev + 4, htElev + 4, background);
        ptSpeed.fillRect(0, 0, wdSpeed + 4, htSpeed + 4, background);
        // Draw a grid with markers at every 10 minutes
        ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
        ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
        ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
        // Bottom border line
        x1 = margin_left;

        y1 = htHR - margin_bottom;
        x2 = wdHR - margin_right;
        y2 = y1;
        ptHR.drawLine(x1, y1, x2, y2);

        y1 = htElev - margin_bottom;
        x2 = wdElev - margin_right;
        y2 = y1;
        ptElevation.drawLine(x1, y1, x2, y2);

        y1 = htSpeed - margin_bottom;
        x2 = wdSpeed - margin_right;
        y2 = y1;
        ptSpeed.drawLine(x1, y1, x2, y2);

        // Left border line
        x1 = x2 = margin_left;
        y1 = 2;
        y2 = htHR - margin_bottom;
        ptHR.drawLine(x1, y1, x2, y2);

        y2 = htElev - margin_bottom;
        ptElevation.drawLine(x1, y1, x2, y2);

        y2 = htSpeed - margin_bottom;
        ptSpeed.drawLine(x1, y1, x2, y2);

        // right border line
        x1 = x2 = wdHR - margin_right;
        ptHR.drawLine(x1, y1, x2, y2);

        x1 = x2 = wdElev - margin_right;
        ptElevation.drawLine(x1, y1, x2, y2);

        x1 = x2 = wdSpeed - margin_right;
        ptSpeed.drawLine(x1, y1, x2, y2);

        // Draw some darker lines to show the laps, if we have one
        QDateTime *qt;
        QTime zeit = StartTime.time();
        rn = ds.getRunNode();
        ptHR.setPen(QPen(hlight, 1, Qt::SolidLine));
        ptElevation.setPen(QPen(hlight, 1, Qt::SolidLine));
        ptSpeed.setPen(QPen(hlight, 1, Qt::SolidLine));

        for(i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
        {
                if((lp = ds.getLap(i)) == NULL)
                        continue;

                qt = garmin_dtime(lp->start_time);
                secs = zeit.secsTo(qt->time());
                delete qt;
                // heart rate
                x1 = secs * wtiHR + margin_left + 1;
                ptHR.drawLine(x1, 2, x1, htHR - margin_bottom);
                // Elevation
                x1 = secs * wtiElev + margin_left + 1;
                ptElevation.drawLine(x1, 2, x1, htElev - margin_bottom);
                // Speed
                x1 = secs * wtiSpeed + margin_left + 1;
                ptSpeed.drawLine(x1, 2, x1, htSpeed - margin_bottom);
        }

        // Grid vertical
        ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
        ptHR.setFont(fntNormal);
        ptHR.drawText(margin_left, htHR - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));

        ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
        ptElevation.setFont(fntNormal);
        ptElevation.drawText(margin_left, htElev - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));

        ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
        ptSpeed.setFont(fntNormal);
        ptSpeed.drawText(margin_left, htSpeed - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));

        ptHR.save();
        ptHR.rotate(270);
        ptHR.setPen(QPen(blue, 1, Qt::SolidLine));

        ptElevation.save();
        ptElevation.rotate(270);
        ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));

        ptSpeed.save();
        ptSpeed.rotate(270);
        ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));

        // Information on right side
        ptHR.drawText((htHR + 4) * -1, wdHR - 1 - lineHeight, htHR - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
        ptElevation.drawText((htElev + 4) * -1, wdElev - 1 - lineHeight, htElev - 2, lineHeight, Qt::AlignCenter, i18n("Elevation (%1)").arg((Units == 1) ? "ft" : "m"));
        ptSpeed.drawText((htSpeed + 4) * -1, wdSpeed - 1 - lineHeight, htSpeed - 2, lineHeight, Qt::AlignCenter, i18n("Speed (%1)").arg((Units == 1) ? "mph" : "km/h"));

        // restore to normal
        ptHR.restore();
        ptHR.setPen(QPen(mark, 1, Qt::SolidLine));

        ptElevation.restore();
        ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));

        ptSpeed.restore();
        ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));

        // Draw the time scale on the bottom of the graphic
        for(i = 0; (unsigned int)i < (max_time + ds.getPauseTime()); i++)
        {
                bool loop = false;

                if(i > 0 && !(i % 600)) // every 10 minutes
                {
                        for(int j = 0; j < 3; j++)
                        {
                                switch(j)
                                {
                                        case 0: w_tick = wtiHR; width = wdHR; height = htHR; break;
                                        case 1: w_tick = wtiElev; width = wdElev; height = htElev; break;
                                        case 2: w_tick = wtiSpeed; width = wdSpeed; height = htSpeed; break;
                                }

                                x1 = x2 = margin_left + w_tick * i;

                                if(x1 == (width - margin_right - 25))
                                {
                                        loop = true;
                                        break;
                                }

                                y1 = 2;
                                y2 = height - margin_bottom;
                                QTime tm(0, 0, 0);
                                tm = tm.addSecs(i);

                                if(j == 0)
                                {
                                        ptHR.drawLine(x1, y1, x2, y2);
                                        ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
                                        ptHR.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
                                        ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
                                }
                                else if(j == 1)
                                {
                                        ptElevation.drawLine(x1, y1, x2, y2);
                                        ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
                                        ptElevation.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
                                        ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
                                }
                                else
                                {
                                        ptSpeed.drawLine(x1, y1, x2, y2);
                                        ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
                                        ptSpeed.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (i >= 3600) ? true : false));
                                        ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
                                }
                        }

                        if(loop)
                        {
                                loop = false;
                                continue;
                        }
                }
        }

        // This is the total time, with pauses included, at the lower right
        // corner of the graphic.
        QTime tm(0, 0, 0);
        QString qs;
        tm = tm.addSecs(max_time + ds.getPauseTime());
        ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
        ptHR.drawText(wdHR - margin_right - 25, htHR - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));

        ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
        ptElevation.drawText(wdElev - margin_right - 25, htElev - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));

        ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
        ptSpeed.drawText(wdSpeed - margin_right - 25, htSpeed - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));

        // Draw the minimal elevation, speed and heart rate
        // Heart rate
        ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
        ptHR.drawText(wdHR - margin_right + 2, htHR - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
        // Elevation
        ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
        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));
        // Speed
        ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
        ptSpeed.drawText(wdSpeed - margin_right + 2, htSpeed - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));

        ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
        ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
        ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));

        // Grid horizontal
        int factor = 0;
        int target = 0;

        for(int j = 0; j < 3; j++)
        {
                switch(j)
                {
                        case 0: width = wdHR; height = htHR; w_tick = wtiHR; h_tick = htiHR; rh = rhHR;
                                factor = (maxHr - minHr) / (rhHR / 12);
                                target = (maxHr - minHr);
                                break;

                        case 1: width = wdElev; height = htElev; w_tick = wtiElev; h_tick = htiElev; rh = rhElev;
                                factor = (maxHeight - minHeight) / (rhElev / 12);
                                target = (int)(maxHeight - minHeight);
                                break;

                        case 2: width = wdSpeed; height = htSpeed; w_tick = wtiSpeed; h_tick = htiSpeed; rh = rhSpeed;
                                factor = (maxSpeed - minSpeed) / (rhSpeed / 12);
                                target = (int)(maxSpeed - minSpeed);
                                break;
                }

                // To prevent a division by zero error, we check the <factor>
                if(factor == 0)
                        factor = 1;

                // Beside the horizontal part of the grid, we draw the scale on the
                // the right side too.
                int oldy = height;

                for(i = 0; i < target; i++)
                {
                        if(i > 0 && !(i % factor))
                        {
                                x1 = margin_left + 1;
                                x2 = width - margin_right - 1;
                                y1 = y2 = rh - h_tick * i;

                                if(y1 < 12)
                                        break;

                                switch(j)
                                {
                                        case 0:
                                                ptHR.drawLine(x1, y1, x2, y2);
                                                ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
                                                ptHR.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
                                                ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
                                                break;

                                        case 1:
                                                ptElevation.drawLine(x1, y1, x2, y2);
                                                ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
                                                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));
                                                ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
                                                break;

                                        case 2:
                                                ptSpeed.drawLine(x1, y1, x2, y2);
                                                ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
                                                ptSpeed.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
                                                ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
                                                break;
                                }

                                oldy = y1;
                        }
                }
        }

        // To make our graphics more beautiful, we draw lines for the
        // heart rate limits and the average heart rate.
        if(max_hr > 0)
        {
                int ay1, ay2, ay3, ay4, ay5;

                x1 = margin_left + 1;
                x2 = wdHR - margin_right - 1;

                ay1 = (double)rh - (double)(lower1 - minHr) * htiHR;
                ay2 = (double)rh - (double)(lower2 - minHr) * htiHR;
                ay3 = (double)rh - (double)(lower3 - minHr) * htiHR;
                ay4 = (double)rh - (double)(upper3 - minHr) * htiHR;
                ay5 = (double)rh - (double)(avg_hr - minHr) * htiHR;

                ptHR.setPen(QPen(barcol2, 1, Qt::DashLine));    // color for limits

                if(lower1 > minHr && lower1 < maxHr)
                        ptHR.drawLine(x1, ay1, x2, ay1);

                if(lower2 > minHr && lower2 < maxHr)
                        ptHR.drawLine(x1, ay2, x2, ay2);

                if(lower3 > minHr && lower3 < maxHr)
                        ptHR.drawLine(x1, ay3, x2, ay3);

                if(upper3 > minHr && upper3 < maxHr)
                        ptHR.drawLine(x1, ay4, x2, ay4);

                ptHR.setPen(QPen(red, 1, Qt::DashDotLine));     // color for average heart rate

                if(avg_hr > minHr && avg_hr < maxHr)
                        ptHR.drawLine(x1, ay5, x2, ay5);
        }

        // Now we have a grid and we've done the scaling.
        // This is the point where we draw the curves itself.
        // We use different colors to draw the lines:
        //
        // Green: Elevation
        // Red:   Speed
        // Blue   Heart Rate
        //
        x1 = x2 = y1 = y2 = 0;
        int hy1, hy2, hx1, hx2;
        int sy1, sy2, sx1, sx2;
        hy1 = hy2 = hx1 = hx2 = 0;
        sy1 = sy2 = sx1 = sx2 = 0;
        int hEc = 0;
        i = 0;
        AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
        avgHfirst = avgHlast = 0;

        // To even the surface lines, we store every altitude in the
        // memory, by building a chain. Then, if the user has set in the
        // settings (Contour == true), we will even the line by calculating
        // the average of 10 messure points and setting every value to the
        // average, who is up or down more than 2 meters from the average.
        while((point = ds.getPoint(i)) != 0)
        {
                if(point->alt > 20000.0 || point->alt < -1000.0)
                {
                        i++;
                        continue;
                }

                if(!avgHeight)
                {
                        avgHeight = new AVGHEIGHT;
                        avgHeight->alt = point->alt;
                        avgHeight->pos = hEc;
                        avgHeight->prev = 0;
                        avgHeight->next = 0;
                        avgHakt = avgHeight;
                        avgHfirst = avgHeight;
                }
                else
                {
                        avgHakt = new AVGHEIGHT;
                        avgHakt->alt = point->alt;
                        avgHakt->pos = hEc;
                        avgHakt->next = 0;
                        avgHakt->prev = avgHeight;
                        avgHeight->next = avgHakt;
                        avgHeight = avgHakt;
                }

                // FIXME: Currently we can not draw below 0 meters, because the
                // base line is always 0!
                if(avgHakt->alt < minHeight)
                        avgHakt->alt = minHeight;

                hEc++;
                i++;
        }

        avgHlast = avgHeight;

        // If wanted, even the lines
        if(Contour && hEc > 0)
        {
                double alt[100], avg, avg1, avg2, avg3, avg4;
                int a, pos;

                for(i = 0; i < (hEc + 100); i += 100)
                {
                        avg = avg1 = avg2 = avg3 = avg4 = 0.0;
                        pos = 0;

                        for(a = 0; a < 100; a++)
                        {
                                alt[a] = getAvgAlt(avgHfirst, i + a);
                                avg += alt[a];

                                if(a < 25)
                                        avg1 += alt[a];
                                else if(a < 50)
                                        avg2 += alt[a];
                                else if(a < 75)
                                        avg3 += alt[a];
                                else
                                        avg4 += alt[a];
                        }

                        if((i + 100) >= hEc)
                                avg /= (double)(hEc - i) + 1.0;
                        else
                                avg /= 100.0;

                        for(a = 0; a < 100; a++)
                        {
                                if((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
                                {
                                        if((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
                                                avgHakt->alt = avg;
                                }
                        }
                }
        }

        // plot the elevation, speed and/or heart rate. Depends on <cuType>)
        i = 0;
        int j = 0;
        POINT *oldPoint = 0;
        double speed = 0.0;     // calculated speed
        bool pause = false;     // filter pause out of speed
        unsigned long t1, t2;
        t1 = t2 = 0;

        while((point = ds.getPoint(i)) != 0)
        {
                bool loop = false;

                if(!oldPoint)
                        oldPoint = point;

                // calculate the y position based on the time
                qt = garmin_dtime(point->time);
                secs = zeit.secsTo(qt->time());
                delete qt;

                for(int c = 0; c < 3; c++)
                {
                        if(c == 0)
                        {
                                x2 = secs * wtiHR + margin_left + 1;
                                hx2 = x2;
                                sx2 = x2;

                                if(x1 == 0)
                                        x1 = x2;

                                if(hx1 == 0)
                                        hx1 = hx2;

                                if(sx1 == 0)
                                        sx1 = sx2;
                        }
                        else if(c == 1)
                        {
                                x2 = secs * wtiElev + margin_left + 1;
                                hx2 = x2;
                                sx2 = x2;

                                if(x1 == 0)
                                        x1 = x2;

                                if(hx1 == 0)
                                        hx1 = hx2;

                                if(sx1 == 0)
                                        sx1 = sx2;
                        }
                        else
                        {
                                x2 = secs * wtiSpeed + margin_left + 1;
                                hx2 = x2;
                                sx2 = x2;

                                if(x1 == 0)
                                        x1 = x2;

                                if(hx1 == 0)
                                        hx1 = hx2;

                                if(sx1 == 0)
                                        sx1 = sx2;
                        }

                        // The speed is not very exact, because smallest time is
                        // one second. This allows a maximum error of 99 hundredths
                        // of a second, what is very close to one second. Because of
                        // this, speed seems to hop for every messure point. This
                        // looks ugly, but currently I don't know how to make it
                        // better.
                        if(c == 2)      // Draw speed?
                        {
                                double dist;
                                double sc;

                                if(!pause && point->distance > 1.0e10)
                                {
                                        pause = true;
                                        t1 = point->time;
                                }
                                else if(pause)
                                {
                                        pause = false;
                                        t2 = point->time;
                                        i += 2;
                                        loop = true;
                                }

                                if(point->distance >= 0.1 && point->distance < 1.0e10)
                                {
                                        dist = point->distance - oldPoint->distance;
                                        sc = point->time - oldPoint->time;
                                        LAP *runde = ds.getLapT(point->time);

                                        if(t2 > t1)
                                        {
                                                sc -= t2 - t1;

                                                if(sc <= 0.0)
                                                        sc = 1.0;               // at least 1 second!
                                        }

                                        speed = (dist / sc) * 3.6;

                                        if(runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
                                                speed = runde->max_speed * 3.6;

                                        if(Units == 1)
                                                speed /= 1.609344;

                                        if(speed < minSpeed || speed > 400.0)
                                                speed = minSpeed;

                                        y2 = (double)rh - (speed - minSpeed) * htiSpeed;

                                        if(y1 == 0)
                                                y1 = y2;

                                        ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
                                        ptSpeed.drawLine(x1, y1, x2, y2);
                                        y1 = y2;
                                        x1 = x2;
                                        t1 = t2 = 0;
                                        oldPoint = point;
                                }
                        }

                        if(c == 1)              // Draw elevation?
                        {
                                if(point->alt < 20000.0 && point->alt > -1000.0)
                                {
                                        double alt = getAvgAlt(avgHfirst, j);

                                        j++;

                                        sy2 = (double)rh - (alt - minHeight) * htiElev;

                                        if(sy1 == 0)
                                                sy1 = sy2;

                                        ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
                                        ptElevation.drawLine(sx1, sy1, sx2, sy2);
                                        sy1 = sy2;
                                        sx1 = sx2;
                                }
                        }

                        if(point->heart_rate > 0 && c == 0)     // Draw heart rate?
                        {
                                hy2 = (double)rh - (double)(point->heart_rate - minHr) * htiHR;

                                if(hy1 == 0)
                                        hy1 = hy2;

                                ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
                                ptHR.drawLine(hx1, hy1, hx2, hy2);
                                hy1 = hy2;
                                hx1 = hx2;
                        }
                }

                if(loop)
                {
                        loop = false;
                        continue;
                }

                i++;
        }

        ptHR.end();
        ptElevation.end();
        ptSpeed.end();

        if(!ActivePrint)
        {
                ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
                ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
                ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
        }

        // free the chain of altitudes
        avgHakt = avgHfirst;

        while(avgHakt)
        {
                avgHeight = avgHakt->next;
                delete avgHakt;
                avgHakt = avgHeight;
        }

        DIRTY = false;
}

double sportwatcherWidget::getAvgAlt(AVGHEIGHT *avgHeight, int pos)
{
        AVGHEIGHT *akt;

        if(!avgHeight)
                return 0.0;

        akt = avgHeight;

        while(akt)
        {
                if(akt->pos == pos)
                        return akt->alt;

                akt = akt->next;
        }

        return 0.0;
}

AVGHEIGHT *sportwatcherWidget::getAvgPtr(AVGHEIGHT *avgHeight, int pos)
{
        AVGHEIGHT *akt;

        akt = avgHeight;

        while(akt)
        {
                if(akt->pos == pos)
                        return akt;

                akt = akt->next;
        }

        return 0;
}

void sportwatcherWidget::resizeEvent(QResizeEvent *e)
{
        if(e->size() != e->oldSize())
                DIRTY = true;

        showTrack(zfactor);
        showCurves();
        tabDirt2 = true;

        if(curTab == 2)
        {
                showThreeCurve();
                tabDirt2 = false;
        }

        DIRTY = false;
}

void sportwatcherWidget::mouseMoveEvent(QMouseEvent *e)
{
        QPoint pos(0, 0);
        QPoint ev = ui_sportwatcherWidgetBase.imgMap->mapFrom(this, e->pos());
        static QRect coord;

        DIRTY = true;

        if(curTab == 0)
        {
                if(!stateHand)
                        return;

                if(ev.x() >= pos.x() &&
                                  ev.y() >= pos.y() &&
                                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.imgMap->geometry().width()) &&
                                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.imgMap->geometry().height()))
                {
                        if(lmbPressed == 1)
                        {
                                coord.setCoords(ev.x(), ev.y(), 0, 0);
                                lmbPressed = 0;
                        }
                        else
                        {
                                coord.setRight(ev.x());
                                coord.setBottom(ev.y());
                        }

                        if(lmbPressed == 2)
                        {
                                showTrack(zfactor, coord, mapLap);
                                lmbPressed = 0;
                        }
                }
        }

        if(curTab == 2)
        {
                // look in which of the three QLabels the mouse is, if it is in
                // one of them.
                ev = ui_sportwatcherWidgetBase.grHR->mapFrom(this, e->pos());

                if(ev.x() >= pos.x() &&
                                  ev.y() >= pos.y() &&
                                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grHR->geometry().width()) &&
                                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grHR->geometry().height()))
                {
                        drawGrHR(ev.x(), ev.y());
                        drawGrElev(ev.x(), -1);
                        drawGrSpeed(ev.x(), -1);
                }

                ev = ui_sportwatcherWidgetBase.grElevation->mapFrom(this, e->pos());

                if(ev.x() >= pos.x() &&
                                  ev.y() >= pos.y() &&
                                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grElevation->geometry().width()) &&
                                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grElevation->geometry().height()))
                {
                        drawGrHR(ev.x(), -1);
                        drawGrElev(ev.x(), ev.y());
                        drawGrSpeed(ev.x(), -1);
                }

                ev = ui_sportwatcherWidgetBase.grSpeed->mapFrom(this, e->pos());

                if(ev.x() >= pos.x() &&
                                  ev.y() >= pos.y() &&
                                  ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grSpeed->geometry().width()) &&
                                  ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grSpeed->geometry().height()))
                {
                        drawGrHR(ev.x(), -1);
                        drawGrElev(ev.x(), -1);
                        drawGrSpeed(ev.x(), ev.y());
                }
        }

        DIRTY = false;
}

void sportwatcherWidget::mousePressEvent(QMouseEvent *e)
{
        if(stateHand && e->button() == Qt::LeftButton)
                lmbPressed = 1; // Left Mouse Button is pressed
        else if(stateHand)
                lmbPressed = 0; // Wrong button is pressed

        if(stateGlas)
        {
                if(e->button() == Qt::LeftButton)
                        btGlasPlusSlot();
                else if(e->button() == Qt::RightButton)
                        btGlasMinusSlot();
        }
}

void sportwatcherWidget::mouseReleaseEvent(QMouseEvent *e)
{
        if(stateHand && e->button() == Qt::LeftButton)
        {
                lmbPressed = 2; // Left Mouse Button was released
                mouseMoveEvent(e);
        }
}

/*
 * Private functions to draw cross and/or a bar to reflect the mouse
 * pointer on tab 2.
 */
void sportwatcherWidget::drawGrHR(int x, int y)
{
        int width, height;
        QPixmap pm = pmHR.copy(pmHR.rect());
        QPainter paint;

        width = ui_sportwatcherWidgetBase.grHR->width();
        height = ui_sportwatcherWidgetBase.grHR->height();
        ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);

        if(x > (width - 40) || y > (height - 12) || x < 1)
        {
                ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
                ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
                return;
        }

        if(tabDirt2)
        {
                DIRTY = true;
                showThreeCurve();
                tabDirt2 = false;
                DIRTY = false;
        }

        paint.begin(&pm);
        QColor black(0, 0, 0);
        black.setAlpha(128);
        paint.setPen(QPen(black, 1, Qt::SolidLine));

        // horizontal line, if y != -1
        if(y >= 0)
                paint.drawLine(2, y, width - 41, y);

        // vertical line
        paint.drawLine(x, 1, x, height - 13);
        paint.end();
        ui_sportwatcherWidgetBase.grHR->setPixmap(pm);
}

void sportwatcherWidget::drawGrElev(int x, int y)
{
        int width, height;
        QPixmap pm = pmElevation.copy(pmElevation.rect());
        QPainter paint;

        width = ui_sportwatcherWidgetBase.grElevation->width();
        height = ui_sportwatcherWidgetBase.grElevation->height();
        ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);

        if(x > (width - 40) || y > (height - 12) || x < 1)
        {
                ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
                ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
                return;
        }

        if(tabDirt2)
        {
                DIRTY = true;
                showThreeCurve();
                tabDirt2 = false;
                DIRTY = false;
        }

        paint.begin(&pm);
        QColor black(0, 0, 0);
        black.setAlpha(128);
        paint.setPen(QPen(black, 1, Qt::SolidLine));

        // horizontal line, if y != -1
        if(y >= 0)
                paint.drawLine(2, y, width - 41, y);

        // vertical line
        paint.drawLine(x, 1, x, height - 13);
        paint.end();
        ui_sportwatcherWidgetBase.grElevation->setPixmap(pm);
}

void sportwatcherWidget::drawGrSpeed(int x, int y)
{
        int width, height;
        QPixmap pm = pmSpeed.copy(pmSpeed.rect());
        QPainter paint;

        width = ui_sportwatcherWidgetBase.grSpeed->width();
        height = ui_sportwatcherWidgetBase.grSpeed->height();
        ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);

        if(x > (width - 40) || y > (height - 12) || x < 1)
        {
                ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
                ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
                return;
        }

        if(tabDirt2)
        {
                DIRTY = true;
                showThreeCurve();
                tabDirt2 = false;
                DIRTY = false;
        }

        paint.begin(&pm);
        QColor black(0, 0, 0);
        black.setAlpha(128);
        paint.setPen(QPen(black, 1, Qt::SolidLine));

        // horizontal line, if y != -1
        if(y >= 0)
                paint.drawLine(2, y, width - 41, y);

        // vertical line
        paint.drawLine(x, 1, x, height - 13);
        paint.end();
        ui_sportwatcherWidgetBase.grSpeed->setPixmap(pm);
}

/*
 * Private functions to help decode the data
 */
QDateTime *sportwatcherWidget::garmin_dtime(uint32 t)
{
        time_t     tval;
        struct tm  tmval;
        QTime ti;
        QDate dt;
        QDateTime *qt;

        if(t == 0)
                return new QDateTime(QDate(1900, 1, 1), QTime(0, 0, 0, 0));

        tval = t + TIME_OFFSET;
        localtime_r(&tval, &tmval);
        qt = new QDateTime();
        qt->setDate(QDate(tmval.tm_year + 1900, tmval.tm_mon + 1, tmval.tm_mday));
        qt->setTime(QTime(tmval.tm_hour, tmval.tm_min, tmval.tm_sec, 0));
        /* OK.  Done. */
        return qt;
}

bool sportwatcherWidget::writeTag(const QFile &fn, const QString &str, int indent)
{
        QString qs;
        char *p;
//QCString qcs;
        int i;

        if(indent > 0)
                qs.fill(' ', indent * 3);

        qs.append(str);
//      qcs = qs.utf8();
//      qstrcpy(p, qcs);
        p = strdup(qs.toUtf8().data());
        i = strlen(p);

        if(write(fn.handle(), p, i) != i)
        {
                free(p);
                return false;
        }

        free(p);
        return true;
}

#if defined HAVE_GDAL
bool sportwatcherWidget::writeWMSTag(double llat, double llon, double rlat, double rlon, int width, int height)
{
        QFile fl(MAP);
        QString xml, s, srs, crs, styles, bSize, ext;
        QDir dir = QDir::home();
        QString path = dir.absolutePath();
        int item, isrs;
        double _llat, _llon, _rlat, _rlon;
        bool offline, square;

        if(!fl.open(QIODevice::ReadWrite | QIODevice::Truncate))
        {
                KMessageBox::error(this, i18n("Error opening or creating the WMS tag file!\nPlease check file name and/or permissions."));
                return false;
        }

        KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
        KConfigGroup wms(&cfg, "WMS");
        square = wms.readEntry("Square", false);
        styles = wms.readEntry("Styles", QString(""));

        xml = "<GDAL_WMS>\n";
        xml += "   <Service name=\"WMS\">\n";
        xml += "      <Version>1.1.1</Version>\n";
        xml += "      <ServerURL>" + wms.readEntry("ServerURL", "http://onearth.jpl.nasa.gov/wms.cgi") + "?</serverURL>\n";
        isrs = wms.readEntry("SRS", 0);
        _llon = llon;
        _llat = llat;
        _rlon = rlon;
        _rlat = rlat;
        offline = false;

        switch(isrs)
        {
                case 0: srs = QString("EPSG:4326"); break;

                case 1:
                        srs = QString("EPSG:31257");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31257, width, height, square);
                        break;

                case 2:
                        srs = QString("EPSG:31258");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31258, width, height, square);
                        break;

                case 3:
                        srs = QString("EPSG:31259");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31259, width, height, square);
                        break;

                case 4:
                        srs = QString("EPSG:31286");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31286, width, height, square);
                        break;

                case 5:
                        srs = QString("EPSG:31287");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31287, width, height, square);
                        break;

                case 6:
                        srs = QString("EPSG:31288");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31288, width, height, square);
                        break;

                case 7:
                        srs = QString("EPSG:900913");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 900913, width, height, square);
                        break;

                case 8:
                        srs = QString("EPSG:3395");
                        offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 3395, width, height, square);
                        break;

                default: srs = QString("EPSG:4326");
        }

        xml += "      <SRS>" + srs + "</SRS>\n";
        item = wms.readEntry("CRS", 0);

        switch(item)
        {
                case 0: crs = QString("CRS:83"); break;
                case 1: crs = QString("CRS:84"); break;
                case 2: crs = QString("EPSG:4326"); break;
                case 3: crs = QString("EPSG:31259"); break;
                case 4: crs = QString("EPSG:31287"); break;
                case 5: crs = QString("EPSG:900913"); break;
                case 6: crs = QString("EPSG:3395"); break;
                default: crs = QString("CRS:84"); break;
        }

        xml += "      <CRS>" + crs + "</CRS>\n";
        item = wms.readEntry("Image", 2);
        xml += "      <ImageFormat>image/";

        switch(item)
        {
                case 0: xml += "gif"; ext = QString(".gif"); break;
                case 1: xml += "jpeg"; ext = QString(".jpg"); break;
                case 2: xml += "png"; ext = QString(".png"); break;
                case 3: xml += "tiff"; ext = QString(".tif"); break;
                default: xml += "png"; ext = QString(".png");
        }

        xml += "</ImageFormat>\n";

        xml += "      <Layers>" + wms.readEntry("Layer", QString("")) + "</Layers>\n";

        if(!styles.isEmpty())
                xml += "      <Styles>" + styles + "</Styles>\n";

        xml += "      <BBoxOrder>xyXY</BBoxOrder>\n";
        xml += "   </Service>\n";
        xml += "   <DataWindow>\n";
        s.sprintf("%f", _llat);
        xml += "      <UpperLeftX>" + s + "</UpperLeftX>\n";
        s.sprintf("%f", _llon);
        xml += "      <UpperLeftY>" + s + "</UpperLeftY>\n";
        s.sprintf("%f", _rlat);
        xml += "      <LowerRightX>" + s + "</LowerRightX>\n";
        s.sprintf("%f", _rlon);
        xml += "      <LowerRightY>" + s + "</LowerRightY>\n";
        s.sprintf("%d", width);
        xml += "      <SizeX>" + s + "</SizeX>\n";
        s.sprintf("%d", height);
        xml += "      <SizeY>" + s + "</SizeY>\n";
        xml += "   </DataWindow>\n";

        /*      switch (isrs)
                {
                   case 0: srs = QString("EPSG:4326"); break;
                   case 1: srs = QString("EPSG:31259"); break;
                   case 2: srs = QString("EPSG:31286"); break;
                   case 3: srs = QString("EPSG:31287"); break;
                   case 4: srs = QString("EPSG:31288"); break;
                   default: srs = QString("EPSG:4326");
                }
        */
//      srs = QString("EPSG:4326");
        xml += "   <Projection>" + crs + "</Projection>\n";
        xml += "   <BandsCount>" + wms.readEntry("Bands", QString("3")) + "</BandsCount>\n";
        item = wms.readEntry("Tile", 2);

        switch(item)
        {
                case 0: bSize = QString("64"); break;
                case 1: bSize = QString("128"); break;
                case 2: bSize = QString("256"); break;
                case 3: bSize = QString("512"); break;
                case 4: bSize = QString("1024"); break;
                default: bSize = QString("256");
        }

        xml += "   <BlockSizeX>" + bSize + "</BlockSizeX>\n";
        xml += "   <BlockSizeY>" + bSize + "</BlockSizeY>\n";
        xml += "   <OverviewCount>" + wms.readEntry("Overview", QString("10")) + "</OverviewCount>\n";
        xml += "   <Cache>\n";
        xml += "      <Path>" + path + "/.gdalwmscache" + "</Path>\n";
        xml += "      <Depth>" + wms.readEntry("Depth", QString("2")) + "</Depth>\n";
        xml += "      <Extension>" + ext + "</Extension>\n";
        xml += "   </Cache>\n";
        QString off((wms.readEntry("Offline", false)) ? "true" : "false");
        QString adv((wms.readEntry("Advice", false)) ? "true" : "false");
        QString ver((wms.readEntry("Verify", true)) ? "true" : "false");

        if(offline)
                xml += "   <OfflineMode>true</OfflineMode>\n";
        else
                xml += "   <OfflineMode>" + off + "</OfflineMode>\n";

        xml += "   <AdviseRead>" + adv + "</AdviseRead>\n";
        xml += "   <VerifyAdviseRead>" + ver + "</VerifyAdviseRead>\n";
        xml += "</GDAL_WMS>\n";

        write(fl.handle(), xml.toAscii().data(), strlen(xml.toAscii().data()));
        fl.close();
        return true;
}

bool sportwatcherWidget::transCoords(double *x1, double *y1, double *x2, double *y2, int code, int width, int height, bool square)
{
        OGRSpatialReference oSourceSRS, oTargetSRS;
        OGRCoordinateTransformation *poCT;

        oSourceSRS.SetWellKnownGeogCS("WGS84");
        oTargetSRS.importFromEPSG(code);
        poCT = OGRCreateCoordinateTransformation(&oSourceSRS, &oTargetSRS);

        if(poCT == NULL || !poCT->Transform(1, x1, y1))
        {
                KMessageBox::error(this, i18n("Translation between coordinate systems failed!"));

                if(poCT != NULL)
                        delete poCT;

                return true;
        }

        if(poCT != NULL)
        {
                poCT->Transform(1, x2, y2);
                delete poCT;
        }

        if(square)
        {
                double wdiff = (double)((long)(*x1 - *x2) / (width / 2 * 2) * (width / 2 * 2));
                double hdiff = (double)((long)(*y2 - *y1) / (height / 2 * 2) * (height / 2 * 2));

                *x2 = *x1 - wdiff; // * (double)mFactor;
                *y2 = *y1 + hdiff; // * (double)mFactor;
//         *x2 = *x1 - (double)((long)(wdiff / mFactor * mFactor));
//         *y2 = *y1 - (double)((long)(hdiff / mFactor * mFactor));
                /*         wdiff = wdiff - (*x1 - *x2);
                           hdiff = hdiff - (*y2 - *y1);
                           *x1 -= wdiff / 2.0;
                           *x2 -= wdiff / 2.0;
                           *y1 += hdiff / 2.0;
                           *y2 += hdiff / 2.0; */
        }

        return false;
}

QString *sportwatcherWidget::getProjection(int isrs, QString *srs)
{
        switch(isrs)
        {
                case 0: *srs = QString("EPSG:4326"); break;
                case 1: *srs = QString("EPSG:31257"); break;
                case 2: *srs = QString("EPSG:31258"); break;
                case 3: *srs = QString("EPSG:31259"); break;
                case 4: *srs = QString("EPSG:31286"); break;
                case 5: *srs = QString("EPSG:31287"); break;
                case 6: *srs = QString("EPSG:31288"); break;
                default: *srs = QString("EPSG:4326");
        }

        return srs;
}

bool sportwatcherWidget::warpImage(QString fn, QString *fName)
{
        GDALDatasetH  hSrcDS, hDstDS;
        GDALDataset *inSet, *outSet;
        GDALDataType eDT;
        GDALRasterBand *poBand;
        GDALDriverH hDriver;
        char hv0[256];
        int nXSize, nYSize;
        double adfGeoTransform[6];
        double oriLeftLon, oriRightLon, oriLeftLat, oriRightLat;


        // Loading the user set geo coords of our source image and
        // load the projection used for that image
        KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
        KConfigGroup ic(&cfg, "ImageCoords");
        oriLeftLon = ic.readEntry("LeftLon", 0.0);
        oriLeftLat = ic.readEntry("LeftLat", 0.0);
        oriRightLon = ic.readEntry("RightLon", 0.0);
        oriRightLat = ic.readEntry("RightLat", 0.0);
        int isrs = ic.readEntry("SRS", 0);

        // Create a temporary file name for our output file
        strcpy(hv0, "/tmp/SportWatcherTIFFXXXXXX");
        mkdtemp(&hv0[0]);
        *fName = QString(hv0) + ".tif";

        // Open input and output files.
        if((hSrcDS = GDALOpen(fn.toAscii().data(), GA_ReadOnly)) == NULL)
        {
                KMessageBox::error(this, i18n("Error opening an image file!"));
                return false;
        }

        inSet = (GDALDataset *)hSrcDS;
        // Create output with same datatype as first input band.
        poBand = inSet->GetRasterBand(1);
        eDT = poBand->GetRasterDataType();

        if((hDriver = GDALGetDriverByName("GTiff")) == NULL)
        {
                KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
                GDALClose(hSrcDS);
                return false;
        }

        // Get dimensions of image and set transform data
        int nRasterCount = inSet->GetRasterCount();
        nXSize = inSet->GetRasterXSize();
        nYSize = inSet->GetRasterYSize();

        // cut the wanted region out of image
        transform *tf = new transform(oriLeftLat, oriLeftLon, oriRightLat, oriRightLon);
        tf->setDimensions(nXSize, nYSize);

        if(!tf->cutImage(geoRect.llat, geoRect.llon, geoRect.rlat, geoRect.rlon, fn))
        {
                GDALClose(hSrcDS);
                return false;
        }

        GDALClose(hSrcDS);
        QString nfn = fn + "_tmp.png";

        // repeat the part above and open the now cutted part of the image.
        // Open input and output files.
        if((hSrcDS = GDALOpen(nfn.toAscii().data(), GA_ReadOnly)) == NULL)
        {
                KMessageBox::error(this, i18n("Error opening an image file!"));
                return false;
        }

        inSet = (GDALDataset *)hSrcDS;
        // Create output with same datatype as first input band.
        poBand = inSet->GetRasterBand(1);
        eDT = poBand->GetRasterDataType();

        if((hDriver = GDALGetDriverByName("GTiff")) == NULL)
        {
                KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
                GDALClose(hSrcDS);
                return false;
        }

        // Get dimensions of image and set transform data
        nRasterCount = inSet->GetRasterCount();
        nXSize = inSet->GetRasterXSize();
        nYSize = inSet->GetRasterYSize();

        // Set the values needed to transform the image
        OGRSpatialReference iSRS;
        const char *iWKT;

        switch(isrs)
        {
                case 0: iSRS.importFromEPSG(4326); break;
                case 1: iSRS.importFromEPSG(31257); break;
                case 2: iSRS.importFromEPSG(31258); break;
                case 3: iSRS.importFromEPSG(31259); break;
                case 4: iSRS.importFromEPSG(31286); break;
                case 5: iSRS.importFromEPSG(31287); break;
                case 6: iSRS.importFromEPSG(31288); break;
                default: iSRS.importFromEPSG(4326);
        }

        iSRS.exportToWkt((char **)&iWKT);

        if(inSet->SetProjection(iWKT) != CE_None)
        {
                KMessageBox::error(this, i18n("Error setting projection on source!"));
                GDALClose(hSrcDS);
                return false;
        }

        adfGeoTransform[0] = geoRect.llon;
        adfGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)nXSize;
        adfGeoTransform[2] = 0.0;
        adfGeoTransform[3] = geoRect.llat;
        adfGeoTransform[4] = 0.0;
        adfGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)nYSize);

        if(inSet->SetGeoTransform(&adfGeoTransform[0]) != CE_None)
        {
                KMessageBox::error(this, i18n("Error setting geo transform data to source!"));
                GDALClose(hSrcDS);
                return false;
        }

        // Get Source coordinate system.
        const char *pszSrcWKT, *pszDstWKT = NULL;

        if((pszSrcWKT = GDALGetProjectionRef(hSrcDS)) == NULL)
        {
                KMessageBox::error(this, i18n("Error getting the projection reference"));
                GDALClose(hSrcDS);
                return false;
        }

        // Setup output coordinate system that is UTM ? WGS84.
        OGRSpatialReference oSRS;

//      oSRS.SetUTM( 0, TRUE );
        oSRS.SetWellKnownGeogCS("WGS84");
        oSRS.exportToWkt((char **)&pszDstWKT);

        // Create the output file.
        double adfDstGeoTransform[6];
        adfDstGeoTransform[0] = geoRect.llon;
        adfDstGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)geoRect.width;
        adfDstGeoTransform[2] = 0.0;
        adfDstGeoTransform[3] = geoRect.llat;
        adfDstGeoTransform[4] = 0.0;
        adfDstGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)geoRect.height);

        if((hDstDS = GDALCreate(hDriver, fName->toAscii().data(), geoRect.width, geoRect.height,
                                nRasterCount, eDT, NULL)) == NULL)
        {
                KMessageBox::error(this, i18n("Error creating a temporary image file! (%1)").arg(*fName));
                GDALClose(hSrcDS);
                return false;
        }

        outSet = (GDALDataset *)hDstDS;

        for(int i = 0; i < nRasterCount; i++)
        {
                poBand = outSet->GetRasterBand(i + 1);
                poBand->Fill(0.0);
        }

        if(outSet->SetProjection(pszDstWKT) != CE_None)
        {
                KMessageBox::error(this, i18n("Error setting projection on destination!"));
                GDALClose(hDstDS);
                GDALClose(hSrcDS);
                unlink(fName->toAscii().data());
                return false;
        }

        if(outSet->SetGeoTransform(&adfDstGeoTransform[0]) != CE_None)
        {
                KMessageBox::error(this, i18n("Error setting geo transform data to destination!"));
                GDALClose(hDstDS);
                GDALClose(hSrcDS);
                unlink(fName->toAscii().data());
                return false;
        }

        // Copy the color table, if required.
        GDALColorTableH hCT;

        for(int i = 0; i < nRasterCount; i++)
        {
                hCT = GDALGetRasterColorTable(inSet->GetRasterBand(i + 1));

                if(hCT != NULL)
                        GDALSetRasterColorTable(outSet->GetRasterBand(i + 1), hCT);
        }

        // Setup warp options.
        GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();

        psWarpOptions->hSrcDS = hSrcDS;
        psWarpOptions->hDstDS = hDstDS;

        psWarpOptions->nBandCount = nRasterCount;
        psWarpOptions->panSrcBands =
                 (int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount);
        psWarpOptions->panDstBands =
                 (int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount);

        for(int i = 0; i < nRasterCount; i++)
        {
                psWarpOptions->panSrcBands[i] = i + 1;
                psWarpOptions->panDstBands[i] = i + 1;
        }

//      psWarpOptions->pfnProgress = GDALTermProgress;

        // Establish reprojection transformer.
        psWarpOptions->pTransformerArg =
                 GDALCreateGenImgProjTransformer(hSrcDS,
                                   GDALGetProjectionRef(hSrcDS),
                                   hDstDS,
                                   GDALGetProjectionRef(hDstDS),
                                   FALSE, 0.0, 1);

        psWarpOptions->pfnTransformer = GDALGenImgProjTransform;

        // Initialize and execute the warp operation.
        GDALWarpOperation oOperation;

        if(oOperation.Initialize(psWarpOptions) != CE_None)
        {
                KMessageBox::error(this, i18n("Error initializing warp operation!"));
                GDALClose(hDstDS);
                GDALClose(hSrcDS);
                unlink(fName->toAscii().data());
                return false;
        }

        oOperation.ChunkAndWarpMulti(0, 0, geoRect.width, geoRect.height);
        GDALDestroyGenImgProjTransformer(psWarpOptions->pTransformerArg);
        GDALDestroyWarpOptions(psWarpOptions);

        GDALClose(hDstDS);
        GDALClose(hSrcDS);
        unlink(nfn.toAscii().data());
        return true;
}

#endif

#ifdef HAVE_GDAL
void spwErrorHandler(CPLErr err, int num, const char *msg)
{
        ERRMSG *akt;
        char et[32], hv0[4096];

        if(err == CE_None || !msg)
                return;

        if(err == CE_Fatal)
                std::cerr << "ERROR " << num << ": " << msg << endl;

        if(!firstError)
        {
                firstError = new ERRMSG;
                memset(firstError, 0, sizeof(ERRMSG));
                akt = firstError;
        }
        else
        {
                akt = firstError;

                while(akt)
                {
                        if(!akt->next)
                                break;

                        akt = akt->next;
                }

                akt->next = new ERRMSG;
                akt = akt->next;
                memset(akt, 0, sizeof(ERRMSG));
        }

        switch(err)
        {
                case CE_None: strcpy(et, "None"); break;
                case CE_Debug: strcpy(et, "DEBUG"); break;
                case CE_Warning: strcpy(et, "Warning"); break;
                case CE_Failure: strcpy(et, "Failure"); break;
                case CE_Fatal: strcpy(et, "Fatal"); break;
        }

        memset(hv0, 0, sizeof(hv0));
        strncpy(hv0, msg, 4000);
        sprintf(akt->msg, "ERROR TYPE %s - %d: %s", et, num, hv0);
}

void destroyErrors()
{
        ERRMSG *akt;

        if(!firstError)
                return;

        akt = firstError;

        while(akt)
        {
                firstError = akt->next;
                delete akt;
                akt = firstError;
        }

        firstError = 0;
}

QString catGDALError()
{
        QString err;
        ERRMSG *akt = firstError;

        while(akt)
        {
                err += QString(akt->msg) + "\n";
                akt = akt->next;
        }

        destroyErrors();
        return err;
}
#endif

#include "sportwatcherwidget.moc"