/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2007-12-08
 * Description : a widget to display date and time statistics of pictures
 *
 * Copyright (C) 2007-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * 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;
 * either version 2, or (at your option)
 * any later version.
 * 
 * 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.
 * 
 * ============================================================ */

// C++ includes.

#include <cmath>

// TQt includes.

#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqpen.h>

// KDE includes.

#include <kcursor.h>
#include <klocale.h>
#include <kglobal.h>
#include <kcalendarsystem.h>
#include <kglobalsettings.h>

// Local includes.

#include "ddebug.h"
#include "themeengine.h"
#include "timelinewidget.h"
#include "timelinewidget.moc"

namespace Digikam
{

class TimeLineWidgetPriv
{

public :

    typedef TQPair<int, int> YearRefPair;                         // Year + a reference association (Month or week or day)
    typedef TQPair<int, TimeLineWidget::SelectionMode> StatPair;  // Statistic value + selection status.

public:

    TimeLineWidgetPriv()
    {
        validMouseEvent = false;
        selMouseEvent   = false;
        maxCountByDay   = 1;
        maxCountByWeek  = 1;
        maxCountByMonth = 1;
        maxCountByYear  = 1;
        topMargin       = 3;
        bottomMargin    = 20;
        barWidth        = 20;
        startPos        = 96;
        nbItems         = 10;
        timeUnit        = TimeLineWidget::Month;
        scaleMode       = TimeLineWidget::LinScale;
        calendar        = KGlobal::locale()->calendar();
    }

    bool                         validMouseEvent;   // Current mouse enter event is valid to set cursor position or selection.
    bool                         selMouseEvent;     // Current mouse enter event is about to make a selection.

    int                          maxCountByDay;
    int                          maxCountByWeek;
    int                          maxCountByMonth;
    int                          maxCountByYear;
    int                          topMargin; 
    int                          bottomMargin; 
    int                          barWidth; 
    int                          nbItems;
    int                          startPos;

    TQDateTime                    refDateTime;       // Reference date-time used to draw histogram from middle of widget.
    TQDateTime                    cursorDateTime;    // Current date-time used to draw focus cursor.
    TQDateTime                    minDateTime;       // Higher date on histogram.
    TQDateTime                    maxDateTime;       // Lower date on histogram.
    TQDateTime                    selStartDateTime;
    TQDateTime                    selMinDateTime;    // Lower date available on histogram.
    TQDateTime                    selMaxDateTime;    // Higher date available on histogram.

    TQPixmap                      pixmap;            // Used for widget double buffering.

    TQMap<YearRefPair, StatPair>  dayStatMap;        // Store Days count statistics.
    TQMap<YearRefPair, StatPair>  weekStatMap;       // Store Weeks count statistics.
    TQMap<YearRefPair, StatPair>  monthStatMap;      // Store Month count statistics.
    TQMap<int,         StatPair>  yearStatMap;       // Store Years count statistics.

    const KCalendarSystem       *calendar;

    TimeLineWidget::TimeUnit     timeUnit;
    TimeLineWidget::ScaleMode    scaleMode;
};

TimeLineWidget::TimeLineWidget(TQWidget *parent)
              : TQWidget(parent, 0, TQt::WDestructiveClose)
{
    d = new TimeLineWidgetPriv;
    setBackgroundMode(TQt::NoBackground);
    setMouseTracking(true);
    setMinimumWidth(256);
    setMinimumHeight(192);

    TQDateTime ref = TQDateTime::currentDateTime();   
    setCursorDateTime(ref);   
    setRefDateTime(ref);

    connect(ThemeEngine::instance(), TQT_SIGNAL(signalThemeChanged()),
            this, TQT_SLOT(slotThemeChanged()));
}

TimeLineWidget::~TimeLineWidget()
{
    delete d;
}

void TimeLineWidget::setTimeUnit(TimeUnit timeUnit)
{
    d->timeUnit = timeUnit;
    setCursorDateTime(cursorDateTime());
    setRefDateTime(cursorDateTime());
}

TimeLineWidget::TimeUnit TimeLineWidget::timeUnit() const
{
    return d->timeUnit;
}

void TimeLineWidget::setScaleMode(ScaleMode scaleMode)
{
    d->scaleMode = scaleMode;
    updatePixmap();
    update();
}

TimeLineWidget::ScaleMode TimeLineWidget::scaleMode() const
{
    return d->scaleMode;
}

int TimeLineWidget::totalIndex()
{
    if (d->minDateTime.isNull() || d->maxDateTime.isNull())
        return 0;

    int        i = 0;
    TQDateTime dt = d->minDateTime;

    do
    {
        dt = nextDateTime(dt);
        i++;
    }
    while(dt < d->maxDateTime);

    return i;
}

int TimeLineWidget::indexForDateTime(const TQDateTime& date)
{
    if (d->minDateTime.isNull() || d->maxDateTime.isNull() || date.isNull())
        return 0;

    int        i = 0;
    TQDateTime dt = d->minDateTime;

    do
    {
        dt = nextDateTime(dt);
        i++;
    }
    while(dt < date);

    return i;
}

int TimeLineWidget::indexForRefDateTime()
{
    return (indexForDateTime(d->refDateTime));
}

int TimeLineWidget::indexForCursorDateTime()
{
    return (indexForDateTime(d->cursorDateTime));
}

void TimeLineWidget::setCurrentIndex(int index)
{
    if (d->minDateTime.isNull() || d->maxDateTime.isNull())
        return;

    int        i = 0;
    TQDateTime dt = d->minDateTime;

    do
    {
        dt = nextDateTime(dt);
        i++;
    }
    while(i <= index);

    setRefDateTime(dt);
}

void TimeLineWidget::setCursorDateTime(const TQDateTime& dateTime)
{
    TQDateTime dt = dateTime;
    dt.setTime(TQTime(0, 0, 0, 0));

    switch(d->timeUnit)
    {
        case Week:
        {
            // Go to the first day of week.
            int weekYear = 0;
            int weekNb   = d->calendar->weekNumber(dt.date(), &weekYear);
            dt           = firstDayOfWeek(weekYear, weekNb);
            break;
        }
        case Month:
        {
            // Go to the first day of month.
            dt.setDate(TQDate(dt.date().year(), dt.date().month(), 1));
            break;
        }
        case Year:
        {
            // Go to the first day of year.
            dt.setDate(TQDate(dt.date().year(), 1, 1));
            break;
        }
        default:
            break;
    }

    if (d->cursorDateTime == dt)
        return;

    d->cursorDateTime = dt;

    emit signalCursorPositionChanged();
}

TQDateTime TimeLineWidget::cursorDateTime() const
{
    return d->cursorDateTime;
}

int TimeLineWidget::cursorInfo(TQString& infoDate)
{
    SelectionMode selected;
    TQDateTime dt = cursorDateTime();

    switch(d->timeUnit)
    {
        case Day:
        {
            infoDate = KGlobal::locale()->formatDate(dt.date());
            break;
        }
        case Week:
        {
            infoDate = i18n("Week #%1 - %2 %3")
                       .arg(d->calendar->weekNumber(dt.date()))
                       .arg(d->calendar->monthName(dt.date()))
                       .arg(d->calendar->yearString(dt.date(), false));
            break;
        }
        case Month:
        {
            infoDate = TQString("%1 %2")
                       .arg(d->calendar->monthName(dt.date()))
                       .arg(d->calendar->yearString(dt.date(), false));
            break;
        }
        case Year:
        {
            infoDate = d->calendar->yearString(dt.date(), false);
            break;
        }
    }

    return statForDateTime(dt, selected);
}

void TimeLineWidget::setRefDateTime(const TQDateTime& dateTime)
{
    TQDateTime dt = dateTime;
    dt.setTime(TQTime(0, 0, 0, 0));

    switch(d->timeUnit)
    {
        case Week:
        {
            // Go to the first day of week.
            int dayWeekOffset = (-1) * (d->calendar->dayOfWeek(dt.date()) - 1);
            dt = dt.addDays(dayWeekOffset);
            break;
        }
        case Month:
        {
            // Go to the first day of month.
            dt.setDate(TQDate(dt.date().year(), dt.date().month(), 1));
            break;
        }
        case Year:
        {
            // Go to the first day of year.
            dt.setDate(TQDate(dt.date().year(), 1, 1));
            break;
        }
        default:
            break;
    }

    d->refDateTime = dt;
    updatePixmap();
    update();
    emit signalRefDateTimeChanged();
}

void TimeLineWidget::slotResetSelection()
{
    resetSelection();
    updatePixmap();
    update();
}

void TimeLineWidget::resetSelection()
{
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it;

    for (it = d->dayStatMap.begin() ; it != d->dayStatMap.end(); ++it)
        it.data().second = Unselected;

    for (it = d->weekStatMap.begin() ; it != d->weekStatMap.end(); ++it)
        it.data().second = Unselected;

    for (it = d->monthStatMap.begin() ; it != d->monthStatMap.end(); ++it)
        it.data().second = Unselected;

    TQMap<int, TimeLineWidgetPriv::StatPair>::iterator it2;

    for (it2 = d->yearStatMap.begin() ; it2 != d->yearStatMap.end(); ++it2)
        it2.data().second = Unselected;
}

void TimeLineWidget::setSelectedDateRange(const DateRangeList& list)
{
    if (list.isEmpty())
        return;

    resetSelection();

    TQDateTime start, end, dt;
    DateRangeList::const_iterator it;

    for (it = list.begin() ; it != list.end(); ++it)
    {
        start = (*it).first;
        end   = (*it).second;
        if (end > start)
        {
            dt = start;
            do
            {
                setDateTimeSelected(dt, Selected);
                dt = dt.addDays(1);
            }
            while (dt < end);
        }
    }

    updatePixmap();
    update();
}

DateRangeList TimeLineWidget::selectedDateRange(int& totalCount)
{
    // We will parse all selections done on Days stats map.

    DateRangeList list;
    totalCount = 0;
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it3;
    TQDateTime sdt, edt;
    TQDate     date;

    for (it3 = d->dayStatMap.begin() ; it3 != d->dayStatMap.end(); ++it3)
    {
        if (it3.data().second == Selected)
        {
            date = TQDate(it3.key().first, 1, 1);
            date = date.addDays(it3.key().second-1);
            sdt  = TQDateTime(date);
            edt  = sdt.addDays(1); 
            list.append(DateRange(sdt, edt));
            totalCount += it3.data().first;
        }
    }

    DateRangeList::iterator it, it2;

    /*
    for (it = list.begin() ; it != list.end(); ++it)
        DDebug() << (*it).first.date().toString(Qt::ISODate) << " :: " 
                 << (*it).second.date().toString(Qt::ISODate) << endl;

    DDebug() << "Total Count of Items = " << totalCount << endl;
    */

    // Group contiguous date ranges to optimize query on database.

    DateRangeList list2;
    TQDateTime     first, second, first2, second2;

    for (it = list.begin() ; it != list.end(); ++it)
    { 
        first  = (*it).first;
        second = (*it).second;
        it2 = it;
        do
        {
            ++it2;
            if (it2 != list.end())
            {
                first2  = (*it2).first;
                second2 = (*it2).second;
                
                if (first2 == second)
                {
                    second = second2;
                    ++it;
                }
                else 
                    break;
            }
        }
        while(it2 != list.end());

        list2.append(DateRange(first, second));
    }

    /*
    for (it = list2.begin() ; it != list2.end(); ++it)
        DDebug() << (*it).first.date().toString(Qt::ISODate) << " :: " 
                 << (*it).second.date().toString(Qt::ISODate) << endl;
    */

    return list2;
}

void TimeLineWidget::slotDatesMap(const TQMap<TQDateTime, int>& datesStatMap)
{
    // Clear all counts in all stats maps before to update it. Do not clear selections.

    TQMap<int, TimeLineWidgetPriv::StatPair>::iterator it_iP;
    for ( it_iP = d->yearStatMap.begin() ; it_iP != d->yearStatMap.end(); ++it_iP )
        it_iP.data().first = 0;

    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it_YP;
    for ( it_YP = d->monthStatMap.begin() ; it_YP != d->monthStatMap.end(); ++it_YP )
        it_YP.data().first = 0;

    for ( it_YP = d->weekStatMap.begin() ; it_YP != d->weekStatMap.end(); ++it_YP )
        it_YP.data().first = 0;

    for ( it_YP = d->dayStatMap.begin() ; it_YP != d->dayStatMap.end(); ++it_YP )
        it_YP.data().first = 0;

    // Parse all new Date stamp and store histogram stats relevant in maps.

    int count;
    TQMap<TQDateTime, int>::const_iterator it;
    if (datesStatMap.isEmpty())
    {
        d->minDateTime = TQDateTime();
        d->maxDateTime = TQDateTime();
    }
    else
    {
        d->minDateTime = datesStatMap.begin().key();
        d->maxDateTime = datesStatMap.begin().key();
    }

    for ( it = datesStatMap.begin(); it != datesStatMap.end(); ++it )
    {
        if (it.key() > d->maxDateTime)
            d->maxDateTime = it.key();

        if (it.key() < d->minDateTime)
            d->minDateTime = it.key();

        int year        = it.key().date().year();
        int month       = it.key().date().month();
        int day         = d->calendar->dayOfYear(it.key().date());
        int yearForWeek = year;  // Used with week shared between 2 years decade (Dec/Jan).
        int week        = d->calendar->weekNumber(it.key().date(), &yearForWeek);

        // Stats Years values.

        it_iP = d->yearStatMap.find(year);
        if ( it_iP == d->yearStatMap.end() )
        {
            count = it.data();
            d->yearStatMap.insert( year, TimeLineWidgetPriv::StatPair(count, Unselected) );
        }
        else
        {
            count = it_iP.data().first + it.data();
            d->yearStatMap.replace( year, TimeLineWidgetPriv::StatPair(count, it_iP.data().second) );
        }

        if (d->maxCountByYear < count) 
            d->maxCountByYear = count;

        // Stats Months values.

        it_YP = d->monthStatMap.find(TimeLineWidgetPriv::YearRefPair(year, month));
        if ( it_YP == d->monthStatMap.end() )
        {
            count = it.data();
            d->monthStatMap.insert( TimeLineWidgetPriv::YearRefPair(year, month), 
                                    TimeLineWidgetPriv::StatPair(count, Unselected) );
        }
        else
        {
            count = it_YP.data().first + it.data();
            d->monthStatMap.replace( TimeLineWidgetPriv::YearRefPair(year, month), 
                                     TimeLineWidgetPriv::StatPair(count, it_YP.data().second) );
        }

        if (d->maxCountByMonth < count) 
            d->maxCountByMonth = count;

        // Stats Weeks values.

        it_YP = d->weekStatMap.find(TimeLineWidgetPriv::YearRefPair(yearForWeek, week));
        if ( it_YP == d->weekStatMap.end() )
        {
            count = it.data();
            d->weekStatMap.insert( TimeLineWidgetPriv::YearRefPair(yearForWeek, week), 
                                   TimeLineWidgetPriv::StatPair(count, Unselected) );
        }
        else
        {
            count = it_YP.data().first + it.data();
            d->weekStatMap.replace( TimeLineWidgetPriv::YearRefPair(yearForWeek, week), 
                                    TimeLineWidgetPriv::StatPair(count, it_YP.data().second) );
        }

        if (d->maxCountByWeek < count) 
            d->maxCountByWeek = count;

        // Stats Days values.

        it_YP = d->dayStatMap.find(TimeLineWidgetPriv::YearRefPair(year, day));
        if ( it_YP == d->dayStatMap.end() )
        {
            count = it.data();
            d->dayStatMap.insert( TimeLineWidgetPriv::YearRefPair(year, day), 
                                  TimeLineWidgetPriv::StatPair(count, Unselected) );
        }
        else
        {
            count = it_YP.data().first + it.data();
            d->dayStatMap.replace( TimeLineWidgetPriv::YearRefPair(year, day), 
                                   TimeLineWidgetPriv::StatPair(count, it_YP.data().second) );
        }

        if (d->maxCountByDay < count) 
            d->maxCountByDay = count;
    }

    if (!datesStatMap.isEmpty())
    {
        d->maxDateTime.setTime(TQTime(0, 0, 0, 0));
        d->minDateTime.setTime(TQTime(0, 0, 0, 0));
    }
    else
    {
        d->maxDateTime = d->refDateTime;
        d->minDateTime = d->refDateTime;
    }

    updatePixmap();
    update();
    emit signalDateMapChanged();
}

void TimeLineWidget::updatePixmap()
{
    // Drawing background and image.
    d->pixmap = TQPixmap(size());
    d->pixmap.fill(palette().active().background());

    TQPainter p(&d->pixmap);

    d->bottomMargin = (int)(p.fontMetrics().height()*1.5); 
    d->barWidth     = p.fontMetrics().width("00"); 
    d->nbItems      = (int)((width() / 2.0) / (float)d->barWidth);
    d->startPos     = (int)((width() / 2.0) - ((float)(d->barWidth) / 2.0));
    int dim         = height() - d->bottomMargin - d->topMargin;
    TQDateTime ref   = d->refDateTime;
    ref.setTime(TQTime(0, 0, 0, 0));
    double        max, logVal;
    int           val, top;
    SelectionMode sel;
    TQRect         focusRect, selRect, barRect;
    TQBrush        selBrush;
    TQColor        dateColor, subDateColor;

    // Date histogram drawing is divided in 2 parts. The current date-time 
    // is placed on the center of the view and all dates on right are computed,
    // and in second time, all dates on the left.

    // Draw all dates on the right of ref. date-time.

    for (int i = 0 ; i < d->nbItems ; i++)
    {
        val = statForDateTime(ref, sel);
        max = (double)maxCount();

        if (d->scaleMode == TimeLineWidget::LogScale)
        {
            if (max > 0.0) max = log(max);
            else           max = 1.0;

            if (val <= 0) logVal = 0;
            else          logVal = log(val);

            top = lround(dim + d->topMargin - ((logVal * dim) / max));

            if (top < 0) val = 0;
        }
        else
        {
            top = lround(dim + d->topMargin - ((val * dim) / max));
        }

        barRect.setTop(top);
        barRect.setLeft(d->startPos + i*d->barWidth);
        barRect.setBottom(height() - d->bottomMargin);
        barRect.setRight(d->startPos + (i+1)*d->barWidth);

        if (ref == d->cursorDateTime)
            focusRect = barRect;

        if (ref > d->maxDateTime)
            dateColor = palette().active().mid();
        else 
            dateColor = palette().active().foreground(); 

        p.setPen(palette().active().foreground());
        p.fillRect(barRect, TQBrush(ThemeEngine::instance()->textSpecialRegColor()));
        p.drawRect(barRect);
        p.drawLine(barRect.right(), barRect.bottom(), barRect.right(), barRect.bottom()+3);
        p.drawLine(barRect.left(),  barRect.bottom(), barRect.left(),  barRect.bottom()+3);

        if (val) 
        {
            if (sel)
                subDateColor = palette().active().highlightedText();
            else
                subDateColor = palette().active().foreground();
        }
        else 
            subDateColor = palette().active().mid();

        if (sel == Selected || sel == FuzzySelection)
        {
            selBrush.setColor(ThemeEngine::instance()->thumbSelColor());
            selBrush.setStyle(TQBrush::SolidPattern);
            if (sel == FuzzySelection)
                selBrush.setStyle(TQBrush::Dense4Pattern);

            selRect.setTop(height() - d->bottomMargin + 1);
            selRect.setLeft(d->startPos + i*d->barWidth);
            selRect.setBottom(height() - d->bottomMargin/2);
            selRect.setRight(d->startPos + (i+1)*d->barWidth);
            p.fillRect(selRect, selBrush);
        }

        switch(d->timeUnit)
        {
            case Day:
            {
                {
                    p.save();
                    TQFont fnt = p.font();
                    fnt.setPointSize(fnt.pointSize()-4);
                    p.setFont(fnt);
                    p.setPen(subDateColor);
                    TQString txt = TQString(d->calendar->weekDayName(ref.date(), true)[0]);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left() + ((barRect.width()-br.width())/2),
                               barRect.bottom()+br.height(), txt);
                    p.restore();
                }

                if (d->calendar->dayOfWeek(ref.date()) == 1)
                {
                    p.setPen(dateColor);
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = KGlobal::locale()->formatDate(ref.date(), true);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                break;
            }
            case Week:
            {
                int week = d->calendar->weekNumber(ref.date());
                {
                    p.save();
                    TQFont fnt = p.font();
                    fnt.setPointSize(fnt.pointSize()-4);
                    p.setFont(fnt);
                    p.setPen(subDateColor);
                    TQString txt = TQString::number(week);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left() + ((barRect.width()-br.width())/2),
                               barRect.bottom()+br.height(), txt);
                    p.restore();
                }

                p.setPen(dateColor);
                if (week == 1 || week == 10 || week == 20 || week == 30 || week == 40 || week == 50)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = KGlobal::locale()->formatDate(ref.date(), true);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    if (week != 50)
                        p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                else if (week == 6 || week == 16 || week == 26 || week == 36 || week == 46)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/4);
                }
                break;
            }
            case Month:
            {
                {
                    p.save();
                    TQFont fnt = p.font();
                    fnt.setPointSize(fnt.pointSize()-4);
                    p.setFont(fnt);
                    p.setPen(subDateColor) ;
                    TQString txt = TQString(d->calendar->monthName(ref.date(), true)[0]);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left() + ((barRect.width()-br.width())/2),
                               barRect.bottom()+br.height(), txt);
                    p.restore();
                }

                p.setPen(dateColor);
                if (ref.date().month() == 1)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = TQString::number(ref.date().year());
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                else if (ref.date().month() == 7)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/4);
                }
                break;
            }
            case Year:
            {
                p.setPen(dateColor);
                if (ref.date().year() % 10 == 0)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = TQString::number(ref.date().year());
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                else if (ref.date().year() % 5 == 0)
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/4);
                break;
            }
        }

        ref = nextDateTime(ref);
    }

    // Draw all dates on the left of ref. date-time.

    ref = d->refDateTime;
    ref.setTime(TQTime(0, 0, 0, 0));
    ref = prevDateTime(ref);

    for (int i = 0 ; i < d->nbItems-1 ; i++)
    {
        val = statForDateTime(ref, sel);
        max = (double)maxCount();

        if (d->scaleMode == TimeLineWidget::LogScale)
        {
            if (max > 0.0) max = log(max);
            else           max = 1.0;

            if (val <= 0) logVal = 0;
            else          logVal = log(val);

            top = lround(dim + d->topMargin - ((logVal * dim) / max));

            if (top < 0) val = 0;
        }
        else
        {
            top = lround(dim + d->topMargin - ((val * dim) / max));
        }

        barRect.setTop(top);
        barRect.setRight(d->startPos - i*d->barWidth);
        barRect.setBottom(height() - d->bottomMargin);
        barRect.setLeft(d->startPos - (i+1)*d->barWidth);

        if (ref == d->cursorDateTime)
            focusRect = barRect;

        if (ref < d->minDateTime)
            dateColor = palette().active().mid();
        else 
            dateColor = palette().active().foreground(); 

        p.setPen(palette().active().foreground());
        p.fillRect(barRect, TQBrush(ThemeEngine::instance()->textSpecialRegColor()));
        p.drawRect(barRect);
        p.drawLine(barRect.right(), barRect.bottom(), barRect.right(), barRect.bottom()+3);
        p.drawLine(barRect.left(),  barRect.bottom(), barRect.left(),  barRect.bottom()+3);

        if (val) 
        {
            if (sel)
                subDateColor = palette().active().highlightedText();
            else
                subDateColor = palette().active().foreground();
        }
        else 
            subDateColor = palette().active().mid();

        if (sel == Selected || sel == FuzzySelection)
        {
            selBrush.setColor(ThemeEngine::instance()->thumbSelColor());
            selBrush.setStyle(TQBrush::SolidPattern);
            if (sel == FuzzySelection)
                selBrush.setStyle(TQBrush::Dense4Pattern);

            selRect.setTop(height() - d->bottomMargin + 1);
            selRect.setLeft(d->startPos - (i+1)*d->barWidth);
            selRect.setBottom(height() - d->bottomMargin/2);
            selRect.setRight(d->startPos - i*d->barWidth);
            p.fillRect(selRect, selBrush);
        }

        switch(d->timeUnit)
        {
            case Day:
            {
                {
                    p.save();
                    TQFont fnt = p.font();
                    fnt.setPointSize(fnt.pointSize()-4);
                    p.setFont(fnt);
                    p.setPen(subDateColor) ;
                    TQString txt = TQString(d->calendar->weekDayName(ref.date(), true)[0]);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left() + ((barRect.width()-br.width())/2),
                               barRect.bottom()+br.height(), txt);
                    p.restore();
                }

                if (d->calendar->dayOfWeek(ref.date()) == 1)
                {
                    p.setPen(dateColor);
                    p.drawLine(barRect.left(), barRect.bottom(),
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = KGlobal::locale()->formatDate(ref.date(), true);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                break;
            }
            case Week:
            {
                int week = d->calendar->weekNumber(ref.date());
                {
                    p.save();
                    TQFont fnt = p.font();
                    fnt.setPointSize(fnt.pointSize()-4);
                    p.setFont(fnt);
                    p.setPen(subDateColor) ;
                    TQString txt = TQString::number(week);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left() + ((barRect.width()-br.width())/2),
                               barRect.bottom()+br.height(), txt);
                    p.restore();
                }

                p.setPen(dateColor);
                if (week == 1 || week == 10 || week == 20 || week == 30 || week == 40 || week == 50)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = KGlobal::locale()->formatDate(ref.date(), true);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    if (week != 50)
                        p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                else if (week == 6 || week == 16 || week == 26 || week == 36 || week == 46)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/4);
                }
                break;
            }
            case Month:
            {
                {
                    p.save();
                    TQFont fnt = p.font();
                    fnt.setPointSize(fnt.pointSize()-4);
                    p.setFont(fnt);
                    p.setPen(subDateColor) ;
                    TQString txt = TQString(d->calendar->monthName(ref.date(), true)[0]);
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left() + ((barRect.width()-br.width())/2),
                               barRect.bottom()+br.height(), txt);
                    p.restore();
                }

                p.setPen(dateColor);
                if (ref.date().month() == 1)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = TQString::number(ref.date().year());
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                else if (ref.date().month() == 7)
                {
                    p.drawLine(barRect.right(), barRect.bottom(), 
                               barRect.right(), barRect.bottom()+d->bottomMargin/4);
                }
                break;
            }
            case Year:
            {
                p.setPen(dateColor);
                if (ref.date().year() % 10 == 0)
                {
                    p.drawLine(barRect.left(), barRect.bottom(), 
                               barRect.left(), barRect.bottom()+d->bottomMargin/2);
                    TQString txt = TQString::number(ref.date().year());
                    TQRect br    = p.fontMetrics().boundingRect(0, 0, width(), height(), 0, txt); 
                    p.drawText(barRect.left()-br.width()/2, barRect.bottom() + d->bottomMargin, txt);
                }
                else if (ref.date().year() % 5 == 0)
                    p.drawLine(barRect.right(), barRect.bottom(), 
                               barRect.right(), barRect.bottom()+d->bottomMargin/4);
                break;
            }
        }

        ref = prevDateTime(ref);
    }

    // Draw cursor rectangle over current date-time.
    if (focusRect.isValid())
    {
        focusRect.setTop(d->topMargin);
        TQPoint p1(focusRect.left(), height() - d->bottomMargin);
        TQPoint p2(focusRect.right(), height() - d->bottomMargin);
        focusRect.setBottom(focusRect.bottom() + d->bottomMargin/2);

        p.setPen(palette().active().shadow());
        p.drawLine(p1.x(), p1.y()+1, p2.x(), p2.y()+1);
        p.drawRect(focusRect);

        focusRect.addCoords(-1,-1, 1, 1);
        p.setPen(ThemeEngine::instance()->textSelColor());
        p.drawRect(focusRect);
        p.drawLine(p1.x()-1, p1.y(), p2.x()+1, p2.y());

        focusRect.addCoords(-1,-1, 1, 1);
        p.drawRect(focusRect);
        p.drawLine(p1.x()-1, p1.y()-1, p2.x()+1, p2.y()-1);

        focusRect.addCoords(-1,-1, 1, 1);
        p.setPen(palette().active().shadow());
        p.drawRect(focusRect);
        p.drawLine(p1.x(), p1.y()-2, p2.x(), p2.y()-2);
    }
    p.end();
}

TQDateTime TimeLineWidget::prevDateTime(const TQDateTime& dt)
{
    TQDateTime prev;
    switch(d->timeUnit)
    {
        case Day:
        {
            prev = dt.addDays(-1);
            break;
        }
        case Week:
        {
            prev = dt.addDays(-7);
            break;
        }
        case Month:
        {
            prev = dt.addMonths(-1);
            break;
        }
        case Year:
        {
            prev = dt.addYears(-1);
            break;
        }
    }
    return prev;
}

TQDateTime TimeLineWidget::nextDateTime(const TQDateTime& dt)
{
    TQDateTime next;
    switch(d->timeUnit)
    {
        case Day:
        {
            next = dt.addDays(1);
            break;
        }
        case Week:
        {
            next = dt.addDays(7);
            break;
        }
        case Month:
        {
            next = dt.addMonths(1);
            break;
        }
        case Year:
        {
            next = dt.addYears(1);
            break;
        }
    }
    return next;
}

int TimeLineWidget::maxCount()
{
    int max = 1;
    switch(d->timeUnit)
    {
        case Day:
        {
            max = d->maxCountByDay;
            break;
        }
        case Week:
        {
            max = d->maxCountByWeek;
            break;
        }
        case Month:
        {
            max = d->maxCountByMonth;
            break;
        }
        case Year:
        {
            max = d->maxCountByYear;
            break;
        }
    }
    return max;
}

int TimeLineWidget::statForDateTime(const TQDateTime& dt, SelectionMode& selected)
{
    int count = 0;
    int year  = dt.date().year();
    int month = dt.date().month();
    int day   = d->calendar->dayOfYear(dt.date());
    int yearForWeek;  // Used with week shared between 2 years decade (Dec/Jan).
    int week  = d->calendar->weekNumber(dt.date(), &yearForWeek);
    selected  = Unselected;

    switch(d->timeUnit)
    {
        case Day:
        {
            TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it =
                d->dayStatMap.find(TimeLineWidgetPriv::YearRefPair(year, day));
            if ( it != d->dayStatMap.end() )
            {
                count    = it.data().first;
                selected = it.data().second;
            }
            break;
        }
        case Week:
        {
            TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it =
                d->weekStatMap.find(TimeLineWidgetPriv::YearRefPair(yearForWeek, week));
            if ( it != d->weekStatMap.end() )
            {
                count    = it.data().first;
                selected = it.data().second;
            }
            break;
        }
        case Month:
        {
            TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it =
                d->monthStatMap.find(TimeLineWidgetPriv::YearRefPair(year, month));
            if ( it != d->monthStatMap.end() )
            {
                count    = it.data().first;
                selected = it.data().second;
            }
            break;
        }
        case Year:
        {
            TQMap<int, TimeLineWidgetPriv::StatPair>::iterator it = d->yearStatMap.find(year);
            if ( it != d->yearStatMap.end() )
            {
                count    = it.data().first;
                selected = it.data().second;
            }
            break;
        }
    }

    return count;
}

void TimeLineWidget::setDateTimeSelected(const TQDateTime& dt, SelectionMode selected)
{
    int year  = dt.date().year();
    int month = dt.date().month();
    int yearForWeek;  // Used with week shared between 2 years decade (Dec/Jan).
    int week  = d->calendar->weekNumber(dt.date(), &yearForWeek);

    TQDateTime dts, dte;

    switch(d->timeUnit)
    {
        case Day:
        {
            dts = dt;
            dte = dts.addDays(1);
            setDaysRangeSelection(dts, dte, selected);
            break;
        }
        case Week:
        {
            dts = firstDayOfWeek(yearForWeek, week);
            dte = dts.addDays(7);
            setDaysRangeSelection(dts, dte, selected);
            updateWeekSelection(dts, dte);
            break;
        }
        case Month:
        {
            dts = TQDateTime(TQDate(year, month, 1));
            dte = dts.addDays(d->calendar->daysInMonth(dts.date()));
            setDaysRangeSelection(dts, dte, selected);
            updateMonthSelection(dts, dte);
            break;
        }
        case Year:
        {
            dts = TQDateTime(TQDate(year, 1, 1));
            dte = dts.addDays(d->calendar->daysInYear(dts.date()));
            setDaysRangeSelection(dts, dte, selected);
            updateYearSelection(dts, dte);
            break;
        }
    }
}

void TimeLineWidget::updateWeekSelection(const TQDateTime dts, const TQDateTime dte)
{
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it;
    TQDateTime dtsWeek, dteWeek, dt;
    int week;
    int yearForWeek;  // Used with week shared between 2 years decade (Dec/Jan).
    dt = dts;
    do
    {
        yearForWeek = dt.date().year();
        week = d->calendar->weekNumber(dt.date(), &yearForWeek);

        dtsWeek = firstDayOfWeek(yearForWeek, week);
        dteWeek = dtsWeek.addDays(7);
        it  = d->weekStatMap.find(TimeLineWidgetPriv::YearRefPair(yearForWeek, week));
        if ( it != d->weekStatMap.end() )
            it.data().second = checkSelectionForDaysRange(dtsWeek, dteWeek);

        dt = dt.addDays(7);
    }
    while (dt <= dte);
}

void TimeLineWidget::updateMonthSelection(const TQDateTime dts, const TQDateTime dte)
{
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it;
    TQDateTime dtsMonth, dteMonth, dt;
    int       year, month;
    dt = dts;
    do
    {
        year  = dt.date().year();
        month = dt.date().month();

        dtsMonth = TQDateTime(TQDate(year, month, 1));
        dteMonth = dtsMonth.addDays(d->calendar->daysInMonth(dtsMonth.date()));
        it  = d->monthStatMap.find(TimeLineWidgetPriv::YearRefPair(year, month));
        if ( it != d->monthStatMap.end() )
            it.data().second = checkSelectionForDaysRange(dtsMonth, dteMonth);

        dt = dteMonth;
    }
    while (dt <= dte);
}

void TimeLineWidget::updateYearSelection(const TQDateTime dts, const TQDateTime dte)
{
    TQMap<int, TimeLineWidgetPriv::StatPair>::iterator it;
    TQDateTime dtsYear, dteYear, dt;
    int       year;
    dt = dts;
    do
    {
        year = dt.date().year();

        dtsYear = TQDateTime(TQDate(year, 1, 1));
        dteYear = dtsYear.addDays(d->calendar->daysInYear(dtsYear.date()));
        it = d->yearStatMap.find(year);
        if ( it != d->yearStatMap.end() )
            it.data().second = checkSelectionForDaysRange(dtsYear, dteYear);

        dt = dteYear;
    }
    while (dt <= dte);
}

void TimeLineWidget::updateAllSelection()
{
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it;
    TQDateTime dts, dte;
    TQDate     date;

    for (it = d->dayStatMap.begin() ; it != d->dayStatMap.end(); ++it)
    {
        if (it.data().second == Selected)
        {
            date = TQDate(it.key().first, 1, 1);
            date = date.addDays(it.key().second-1);
            dts  = TQDateTime(date);
            dte  = dts.addDays(1); 
            updateWeekSelection(dts, dte);
            updateMonthSelection(dts, dte);
            updateYearSelection(dts, dte);
        }
    }
}

void TimeLineWidget::setDaysRangeSelection(const TQDateTime dts, const TQDateTime dte, SelectionMode selected)
{
    int year, day;
    TQDateTime dt = dts;
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it;

    do
    {
        year = dt.date().year();
        day  = d->calendar->dayOfYear(dt.date());
        it = d->dayStatMap.find(TimeLineWidgetPriv::YearRefPair(year, day));
        if ( it != d->dayStatMap.end() )
            it.data().second = selected;

        dt = dt.addDays(1);
    }
    while(dt < dte);
}

TimeLineWidget::SelectionMode TimeLineWidget::checkSelectionForDaysRange(const TQDateTime dts, const TQDateTime dte)
{
    int year, day;
    int items         = 0;
    int itemsFuz      = 0;
    int itemsSel      = 0;
    TQDateTime dt      = dts;
    TQMap<TimeLineWidgetPriv::YearRefPair, TimeLineWidgetPriv::StatPair>::iterator it;

    do
    {
        year = dt.date().year();
        day  = d->calendar->dayOfYear(dt.date());

        it = d->dayStatMap.find(TimeLineWidgetPriv::YearRefPair(year, day));
        if ( it != d->dayStatMap.end() )
        {
            items++;

            if (it.data().second != Unselected)
            {
                if (it.data().second == FuzzySelection)
                    itemsFuz++;
                else
                    itemsSel++;
            }
        }
        dt = dt.addDays(1);
    }
    while (dt < dte);

    if (items == 0)
        return Unselected;

    if (itemsFuz == 0 && itemsSel == 0)
        return Unselected;

    if (itemsFuz > 0)
        return FuzzySelection;

    if (items > itemsSel)
        return FuzzySelection;

    return Selected;
}

void TimeLineWidget::paintEvent(TQPaintEvent*)
{
    bitBlt(this, 0, 0, &d->pixmap);
}

void TimeLineWidget::resizeEvent(TQResizeEvent*)
{
    updatePixmap();
}

void TimeLineWidget::slotBackward()
{
    TQDateTime ref = d->refDateTime;

    switch(d->timeUnit)
    {
        case Day:
        {
            for (int i = 0; i < 7; i++)
                ref = prevDateTime(ref);
            break;
        }
        case Week:
        {
            for (int i = 0; i < 4; i++)
                ref = prevDateTime(ref);
            break;
        }
        case Month:
        {
            for (int i = 0; i < 12; i++)
                ref = prevDateTime(ref);
            break;
        }
        case Year:
        {
            for (int i = 0; i < 5; i++)
                ref = prevDateTime(ref);
            break;
        }
    }

    if (ref < d->minDateTime)
        ref = d->minDateTime;

    setRefDateTime(ref);
}

void TimeLineWidget::slotPrevious()
{
    if (d->refDateTime <= d->minDateTime)
        return;
    TQDateTime ref = prevDateTime(d->refDateTime);
    setRefDateTime(ref);
}

void TimeLineWidget::slotNext()
{
    if (d->refDateTime >= d->maxDateTime)
        return;
    TQDateTime ref = nextDateTime(d->refDateTime);
    setRefDateTime(ref);
}

void TimeLineWidget::slotForward()
{
    TQDateTime ref = d->refDateTime;

    switch(d->timeUnit)
    {
        case Day:
        {
            for (int i = 0; i < 7; i++)
                ref = nextDateTime(ref);
            break;
        }
        case Week:
        {
            for (int i = 0; i < 4; i++)
                ref = nextDateTime(ref);
            break;
        }
        case Month:
        {
            for (int i = 0; i < 12; i++)
                ref = nextDateTime(ref);
            break;
        }
        case Year:
        {
            for (int i = 0; i < 5; i++)
                ref = nextDateTime(ref);
            break;
        }
    }

    if (ref > d->maxDateTime)
        ref = d->maxDateTime;

    setRefDateTime(ref);
}

void TimeLineWidget::wheelEvent(TQWheelEvent* e)
{
    if (e->delta() < 0)
    {
        if (e->state() & TQt::ShiftButton)
            slotForward();
        else
            slotNext();
    }

    if (e->delta() > 0)
    {
        if (e->state() & TQt::ShiftButton)
            slotBackward();
        else
            slotPrevious();
    }
}

void TimeLineWidget::mousePressEvent(TQMouseEvent *e)
{
    if (e->button() == Qt::LeftButton)
    {
        TQPoint pt(e->x(), e->y());

        bool ctrlPressed    = e->state() & TQt::ControlButton;
        TQDateTime ref       = dateTimeForPoint(pt, d->selMouseEvent);
        d->selStartDateTime = TQDateTime();
        if (d->selMouseEvent) 
        {
            if (!ctrlPressed)
                resetSelection();

            d->selStartDateTime = ref;
            d->selMinDateTime   = ref;
            d->selMaxDateTime   = ref;
            setDateTimeSelected(ref, Selected);
        }

        if (!ref.isNull())
            setCursorDateTime(ref);

        d->validMouseEvent = true;
        updatePixmap();
        update();
    }
}

void TimeLineWidget::mouseMoveEvent(TQMouseEvent *e)
{
    if (d->validMouseEvent == true)
    {
        TQPoint pt(e->x(), e->y());

        bool sel;
        TQDateTime selEndDateTime = dateTimeForPoint(pt, sel);
        setCursorDateTime(selEndDateTime);

        // Clamp start and end date-time of current contiguous selection.

        if (!selEndDateTime.isNull() && !d->selStartDateTime.isNull())
        {
            if (selEndDateTime > d->selStartDateTime && 
                selEndDateTime > d->selMaxDateTime)
            {
                d->selMaxDateTime = selEndDateTime;
            }
            else if (selEndDateTime < d->selStartDateTime && 
                     selEndDateTime < d->selMinDateTime)
            {
                d->selMinDateTime = selEndDateTime;
            }

            TQDateTime dt = d->selMinDateTime;
            do
            {
                setDateTimeSelected(dt, Unselected);
                dt = nextDateTime(dt);
            }
            while(dt <= d->selMaxDateTime);
        }

        // Now perform selections on Date Maps.

        if (d->selMouseEvent)
        {
            if (!d->selStartDateTime.isNull() && !selEndDateTime.isNull())
            {
                TQDateTime dt = d->selStartDateTime;
                if (selEndDateTime > d->selStartDateTime)
                {
                    do
                    {
                        setDateTimeSelected(dt, Selected);
                        dt = nextDateTime(dt);
                    }
                    while(dt <= selEndDateTime);
                }
                else
                {
                    do
                    {
                        setDateTimeSelected(dt, Selected);
                        dt = prevDateTime(dt);
                    }
                    while(dt >= selEndDateTime);
                }
            }
        }

        updatePixmap();
        update();
    }
}

void TimeLineWidget::mouseReleaseEvent(TQMouseEvent*)
{
    d->validMouseEvent = false;

    // Only dispatch changes about selection when user release mouse selection
    // to prevent multiple queries on database.
    if (d->selMouseEvent)
    {
        updateAllSelection();
        emit signalSelectionChanged();
    }

    d->selMouseEvent = false;
}

TQDateTime TimeLineWidget::dateTimeForPoint(const TQPoint& pt, bool &isOnSelectionArea)
{
    TQRect barRect, selRect;
    isOnSelectionArea = false;

    // Check on the right of reference date.

    TQDateTime ref = d->refDateTime;
    ref.setTime(TQTime(0, 0, 0, 0));

    TQRect deskRect = KGlobalSettings::desktopGeometry(this);
    int items = deskRect.width() / d->barWidth;

    for (int i = 0 ; i < items ; i++)
    {
        barRect.setTop(0);
        barRect.setLeft(d->startPos + i*d->barWidth);
        barRect.setBottom(height() - d->bottomMargin + 1);
        barRect.setRight(d->startPos + (i+1)*d->barWidth);

        selRect.setTop(height() - d->bottomMargin + 1);
        selRect.setLeft(d->startPos + i*d->barWidth);
        selRect.setBottom(height());
        selRect.setRight(d->startPos + (i+1)*d->barWidth);

        if (selRect.contains(pt))
            isOnSelectionArea = true;

        if (barRect.contains(pt) || selRect.contains(pt))
        {
            if (i >= d->nbItems)
            {
                // Point is outside visible widget area. We scrolling widget contents.
                slotNext();
            }

            return ref;
        }

        ref = nextDateTime(ref);
    }

    // Check on the left of reference date.

    ref = d->refDateTime;
    ref.setTime(TQTime(0, 0, 0, 0));
    ref = prevDateTime(ref);

    for (int i = 0 ; i < items ; i++)
    {
        barRect.setTop(0);
        barRect.setRight(d->startPos - i*d->barWidth);
        barRect.setBottom(height() - d->bottomMargin + 1);
        barRect.setLeft(d->startPos - (i+1)*d->barWidth);

        selRect.setTop(height() - d->bottomMargin + 1);
        selRect.setLeft(d->startPos - (i+1)*d->barWidth);
        selRect.setBottom(height());
        selRect.setRight(d->startPos - i*d->barWidth);

        if (selRect.contains(pt))
            isOnSelectionArea = true;

        if (barRect.contains(pt) || selRect.contains(pt))
        {
            if (i >= d->nbItems-1)
            {
                // Point is outside visible widget area. We scrolling widget contents.
                slotPrevious();
            }

            return ref;
        }

        ref = prevDateTime(ref);
    }

    return TQDateTime();
}

TQDateTime TimeLineWidget::firstDayOfWeek(int year, int weekNumber)
{
    // Search the first day of first week of year.
    // We start to scan from 1st december of year-1 because 
    // first week of year OR last week of year-1 can be shared 
    // between year-1 and year.
    TQDateTime d1(TQDate(year-1, 12, 1));
    TQDateTime dt = d1;
    int weekYear = 0;
    int weekNum  = 0;

    do
    {
        dt      = dt.addDays(1);
        weekNum = d->calendar->weekNumber(dt.date(), &weekYear);
    }
    while(weekNum != 1 && weekYear != year);

    dt = dt.addDays((weekNumber-1)*7);

/*
    DDebug() << "Year= " << year << " Week= " << weekNumber 
             << " 1st day= " << dt << endl;
*/

    return dt;
}

void TimeLineWidget::slotThemeChanged()
{
    updatePixmap();
    update();
}

}  // NameSpace Digikam
