kdganttdatetimegrid.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2011 Klaralvdalens Datakonsult AB.  All rights reserved.
00003 **
00004 ** This file is part of the KD Chart library.
00005 **
00006 ** Licensees holding valid commercial KD Chart licenses may use this file in
00007 ** accordance with the KD Chart Commercial License Agreement provided with
00008 ** the Software.
00009 **
00010 **
00011 ** This file may be distributed and/or modified under the terms of the
00012 ** GNU General Public License version 2 and version 3 as published by the
00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
00014 **
00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017 **
00018 ** Contact info@kdab.com if any conditions of this licensing are not
00019 ** clear to you.
00020 **
00021 **********************************************************************/
00022 
00023 #include "kdganttdatetimegrid.h"
00024 #include "kdganttdatetimegrid_p.h"
00025 
00026 #include "kdganttabstractrowcontroller.h"
00027 
00028 #include <QApplication>
00029 #include <QDateTime>
00030 #include <QPainter>
00031 #include <QStyle>
00032 #include <QStyleOptionHeader>
00033 #include <QWidget>
00034 #include <QString>
00035 #include <QDebug>
00036 #include <QList>
00037 
00038 #include <cassert>
00039 
00040 using namespace KDGantt;
00041 
00042 QDebug operator<<( QDebug dbg, KDGantt::DateTimeScaleFormatter::Range range )
00043 {
00044     switch( range ) {
00045     case KDGantt::DateTimeScaleFormatter::Second: dbg << "KDGantt::DateTimeScaleFormatter::Second"; break;
00046     case KDGantt::DateTimeScaleFormatter::Minute: dbg << "KDGantt::DateTimeScaleFormatter::Minute"; break;
00047     case KDGantt::DateTimeScaleFormatter::Hour:   dbg << "KDGantt::DateTimeScaleFormatter::Hour"; break;
00048     case KDGantt::DateTimeScaleFormatter::Day:    dbg << "KDGantt::DateTimeScaleFormatter::Day"; break;
00049     case KDGantt::DateTimeScaleFormatter::Week:   dbg << "KDGantt::DateTimeScaleFormatter::Week"; break;
00050     case KDGantt::DateTimeScaleFormatter::Month:  dbg << "KDGantt::DateTimeScaleFormatter::Month"; break;
00051     case KDGantt::DateTimeScaleFormatter::Year:   dbg << "KDGantt::DateTimeScaleFormatter::Year"; break;
00052     }
00053     return dbg;
00054 }
00055 
00056 
00064 // TODO: I think maybe this class should be responsible
00065 // for unit-transformation of the scene...
00066 
00067 qreal DateTimeGrid::Private::dateTimeToChartX( const QDateTime& dt ) const
00068 {
00069     assert( startDateTime.isValid() );
00070     qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
00071     result += startDateTime.time().msecsTo(dt.time())/1000.;
00072     result *= dayWidth/( 24.*60.*60. );
00073 
00074     return result;
00075 }
00076 
00077 QDateTime DateTimeGrid::Private::chartXtoDateTime( qreal x ) const
00078 {
00079     assert( startDateTime.isValid() );
00080     int days = static_cast<int>( x/dayWidth );
00081     qreal secs = x*( 24.*60.*60. )/dayWidth;
00082     QDateTime dt = startDateTime;
00083     QDateTime result = dt.addDays( days )
00084                        .addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) )
00085                        .addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
00086     return result;
00087 }
00088 
00089 #define d d_func()
00090 
00118 DateTimeScaleFormatter::DateTimeScaleFormatter( Range range, const QString& format,
00119                                                 const QString& templ, Qt::Alignment alignment )
00120     : _d( new Private( range, format, templ, alignment ) )
00121 {
00122 }
00123 
00124 DateTimeScaleFormatter::DateTimeScaleFormatter( Range range, const QString& format, Qt::Alignment alignment )
00125     : _d( new Private( range, format, QString::fromLatin1( "%1" ), alignment ) )
00126 {
00127 }
00128 
00129 DateTimeScaleFormatter::DateTimeScaleFormatter( const DateTimeScaleFormatter& other )
00130     : _d( new Private( other.range(), other.format(), other.d->templ, other.alignment() ) )
00131 {
00132 }
00133 
00134 DateTimeScaleFormatter::~DateTimeScaleFormatter()
00135 {
00136     delete _d;
00137 }
00138 
00139 DateTimeScaleFormatter& DateTimeScaleFormatter::operator=( const DateTimeScaleFormatter& other )
00140 {
00141     delete _d;
00142     _d = new Private( other.range(), other.format(), other.d->templ, other.alignment() );
00143     return *this;
00144 }
00145 
00148 QString DateTimeScaleFormatter::format() const
00149 {
00150     return d->format;
00151 }
00152 
00155 QString DateTimeScaleFormatter::format( const QDateTime& datetime ) const
00156 {
00157     QString result = d->format;
00158     // additional feature: Weeknumber
00159     const QString shortWeekNumber = QString::number( datetime.date().weekNumber()) + QLatin1String("/")
00160                                                                                      + QString::number( datetime.date().year());
00161     const QString longWeekNumber = ( shortWeekNumber.length() == 1 ? QString::fromLatin1( "0" ) : QString() ) + shortWeekNumber;
00162     result.replace( QString::fromLatin1( "ww" ), longWeekNumber );
00163     result.replace( QString::fromLatin1( "w" ), shortWeekNumber );
00164     result = datetime.toLocalTime().toString( result );
00165     return result;
00166 }
00167 
00168 QString DateTimeScaleFormatter::text( const QDateTime& datetime ) const
00169 {
00170     return d->templ.arg( format( datetime ) );
00171 }
00172 
00175 DateTimeScaleFormatter::Range DateTimeScaleFormatter::range() const
00176 {
00177     return d->range;
00178 }
00179 
00180 Qt::Alignment DateTimeScaleFormatter::alignment() const
00181 {
00182     return d->alignment;
00183 }
00184 
00188 QDateTime DateTimeScaleFormatter::nextRangeBegin( const QDateTime& datetime ) const
00189 {
00190     QDateTime result = datetime;
00191     switch( d->range )
00192     {
00193     case Second:
00194         result = result.addSecs( 60 );
00195         break;
00196     case Minute:
00197         // set it to the begin of the next minute
00198         result.setTime( QTime( result.time().hour(), result.time().minute() ) );
00199         result = result.addSecs( 60 );
00200         break;
00201     case Hour:
00202         // set it to the begin of the next hour
00203         result.setTime( QTime( result.time().hour(), 0 ) );
00204         result = result.addSecs( 60 * 60 );
00205         break;
00206     case Day:
00207         // set it to midnight the next day
00208         result.setTime( QTime( 0, 0 ) );
00209         result = result.addDays( 1 );
00210         break;
00211     case Week:
00212         // set it to midnight
00213         result.setTime( QTime( 0, 0 ) );
00214         // iterate day-wise, until weekNumber changes
00215         {
00216             const int weekNumber = result.date().weekNumber();
00217             while( weekNumber == result.date().weekNumber() )
00218                 result = result.addDays( 1 );
00219         }
00220         break;
00221     case Month:
00222         // set it to midnight
00223         result.setTime( QTime( 0, 0 ) );
00224         // set it to the first of the next month
00225         result.setDate( QDate( result.date().year(), result.date().month(), 1 ).addMonths( 1 ) );
00226         break;
00227     case Year:
00228         // set it to midnight
00229         result.setTime( QTime( 0, 0 ) );
00230         // set it to the first of the next year
00231         result.setDate( QDate( result.date().year(), 1, 1 ).addYears( 1 ) );
00232         break;
00233     }
00234     //result = result.toLocalTime();
00235     assert(  result != datetime );
00236     //qDebug() << "DateTimeScaleFormatter::nextRangeBegin("<<datetime<<")="<<d->range<<result;
00237     return result;
00238 }
00239 
00243 QDateTime DateTimeScaleFormatter::currentRangeBegin( const QDateTime& datetime ) const
00244 {
00245     QDateTime result = datetime;
00246     switch( d->range )
00247     {
00248     case Second:
00249         break; // nothing
00250     case Minute:
00251         // set it to the begin of the current minute
00252         result.setTime( QTime( result.time().hour(), result.time().minute() ) );
00253         break;
00254     case Hour:
00255         // set it to the begin of the current hour
00256         result.setTime( QTime( result.time().hour(), 0 ) );
00257         break;
00258     case Day:
00259         // set it to midnight the current day
00260         result.setTime( QTime( 0, 0 ) );
00261         break;
00262     case Week:
00263         // set it to midnight
00264         result.setTime( QTime( 0, 0 ) );
00265         // iterate day-wise, as long weekNumber is the same
00266         {
00267             const int weekNumber = result.date().weekNumber();
00268             while( weekNumber == result.date().addDays( -1 ).weekNumber() )
00269                 result = result.addDays( -1 );
00270         }
00271         break;
00272     case Month:
00273         // set it to midnight
00274         result.setTime( QTime( 0, 0 ) );
00275         // set it to the first of the current month
00276         result.setDate( QDate( result.date().year(), result.date().month(), 1 ) );
00277         break;
00278     case Year:
00279         // set it to midnight
00280         result.setTime( QTime( 0, 0 ) );
00281         // set it to the first of the current year
00282         result.setDate( QDate( result.date().year(), 1, 1 ) );
00283         break;
00284     }
00285     return result;
00286 }
00287 
00288 DateTimeGrid::DateTimeGrid() : AbstractGrid( new Private )
00289 {
00290 }
00291 
00292 DateTimeGrid::~DateTimeGrid()
00293 {
00294 }
00295 
00300 QDateTime DateTimeGrid::startDateTime() const
00301 {
00302     return d->startDateTime;
00303 }
00304 
00310 void DateTimeGrid::setStartDateTime( const QDateTime& dt )
00311 {
00312     d->startDateTime = dt;
00313     emit gridChanged();
00314 }
00315 
00320 qreal DateTimeGrid::dayWidth() const
00321 {
00322     return d->dayWidth;
00323 }
00324 
00327 qreal DateTimeGrid::mapFromDateTime( const QDateTime& dt) const
00328 {
00329     return d->dateTimeToChartX( dt );
00330 }
00331 
00334 QDateTime DateTimeGrid::mapToDateTime( qreal x ) const
00335 {
00336     return d->chartXtoDateTime( x );
00337 }
00338 
00343 void DateTimeGrid::setDayWidth( qreal w )
00344 {
00345     assert( w>0 );
00346     d->dayWidth = w;
00347     emit gridChanged();
00348 }
00349 
00355 void DateTimeGrid::setScale( Scale s )
00356 {
00357     d->scale = s;
00358     emit gridChanged();
00359 }
00360 
00367 DateTimeGrid::Scale DateTimeGrid::scale() const
00368 {
00369     return d->scale;
00370 }
00371 
00379 void DateTimeGrid::setUserDefinedLowerScale( DateTimeScaleFormatter* lower )
00380 {
00381     delete d->lower;
00382     d->lower = lower;
00383     emit gridChanged();
00384 }
00385 
00393 void DateTimeGrid::setUserDefinedUpperScale( DateTimeScaleFormatter* upper )
00394 {
00395     delete d->upper;
00396     d->upper = upper;
00397     emit gridChanged();
00398 }
00399 
00402 DateTimeScaleFormatter* DateTimeGrid::userDefinedLowerScale() const
00403 {
00404     return d->lower;
00405 }
00406 
00409 DateTimeScaleFormatter* DateTimeGrid::userDefinedUpperScale() const
00410 {
00411     return d->upper;
00412 }
00413 
00419 void DateTimeGrid::setWeekStart( Qt::DayOfWeek ws )
00420 {
00421     d->weekStart = ws;
00422     emit gridChanged();
00423 }
00424 
00426 Qt::DayOfWeek DateTimeGrid::weekStart() const
00427 {
00428     return d->weekStart;
00429 }
00430 
00437 void DateTimeGrid::setFreeDays( const QSet<Qt::DayOfWeek>& fd )
00438 {
00439     d->freeDays = fd;
00440     emit gridChanged();
00441 }
00442 
00444 QSet<Qt::DayOfWeek> DateTimeGrid::freeDays() const
00445 {
00446     return d->freeDays;
00447 }
00448 
00451 void DateTimeGrid::setFreeDaysBrush(const QBrush brush)
00452 {
00453     d->freeDaysBrush = brush;
00454 }
00455 
00459 QBrush DateTimeGrid::freeDaysBrush() const
00460 {
00461     return d->freeDaysBrush;
00462 }
00463 
00465 bool DateTimeGrid::rowSeparators() const
00466 {
00467     return d->rowSeparators;
00468 }
00470 void DateTimeGrid::setRowSeparators( bool enable )
00471 {
00472     d->rowSeparators = enable;
00473 }
00474 
00479 void DateTimeGrid::setNoInformationBrush( const QBrush& brush )
00480 {
00481     d->noInformationBrush = brush;
00482     emit gridChanged();
00483 }
00484 
00487 QBrush DateTimeGrid::noInformationBrush() const
00488 {
00489     return d->noInformationBrush;
00490 }
00491 
00496 qreal DateTimeGrid::mapToChart( const QVariant& value ) const
00497 {
00498     if ( ! qVariantCanConvert<QDateTime>( value ) ||
00499          ( value.type() == QVariant::String && qVariantValue<QString>(value).isEmpty() ) )
00500     {
00501         return -1.0;
00502     }
00503     return d->dateTimeToChartX( value.toDateTime() );
00504 }
00505 
00510 QVariant DateTimeGrid::mapFromChart( qreal x ) const
00511 {
00512     return d->chartXtoDateTime( x );
00513 }
00514 
00518 Span DateTimeGrid::mapToChart( const QModelIndex& idx ) const
00519 {
00520     assert( model() );
00521     if ( !idx.isValid() ) return Span();
00522     assert( idx.model()==model() );
00523     const QVariant sv = model()->data( idx, StartTimeRole );
00524     const QVariant ev = model()->data( idx, EndTimeRole );
00525     if( qVariantCanConvert<QDateTime>(sv) &&
00526     qVariantCanConvert<QDateTime>(ev) &&
00527     !(sv.type() == QVariant::String && qVariantValue<QString>(sv).isEmpty()) &&
00528     !(ev.type() == QVariant::String && qVariantValue<QString>(ev).isEmpty())
00529     ) {
00530       QDateTime st = sv.toDateTime();
00531       QDateTime et = ev.toDateTime();
00532       if ( et.isValid() && st.isValid() ) {
00533         qreal sx = d->dateTimeToChartX( st );
00534         qreal ex = d->dateTimeToChartX( et )-sx;
00535         //qDebug() << "DateTimeGrid::mapToChart("<<st<<et<<") => "<< Span( sx, ex );
00536         return Span( sx, ex);
00537       }
00538     }
00539     // Special case for Events with only a start date
00540     if( qVariantCanConvert<QDateTime>(sv) && !(sv.type() == QVariant::String && qVariantValue<QString>(sv).isEmpty()) ) {
00541       QDateTime st = sv.toDateTime();
00542       if ( st.isValid() ) {
00543         qreal sx = d->dateTimeToChartX( st );
00544         return Span( sx, 0 );
00545       }
00546     }
00547     return Span();
00548 }
00549 
00550 #if 0
00551 static void debug_print_idx( const QModelIndex& idx )
00552 {
00553     if ( !idx.isValid() ) {
00554         qDebug() << "[Invalid]";
00555         return;
00556     }
00557     QDateTime st = idx.data( StartTimeRole ).toDateTime();
00558     QDateTime et = idx.data( EndTimeRole ).toDateTime();
00559     qDebug() << idx << "["<<st<<et<<"]";
00560 }
00561 #endif
00562 
00577 bool DateTimeGrid::mapFromChart( const Span& span, const QModelIndex& idx,
00578     const QList<Constraint>& constraints ) const
00579 {
00580     assert( model() );
00581     if ( !idx.isValid() ) return false;
00582     assert( idx.model()==model() );
00583 
00584     QDateTime st = d->chartXtoDateTime(span.start());
00585     QDateTime et = d->chartXtoDateTime(span.start()+span.length());
00586     //qDebug() << "DateTimeGrid::mapFromChart("<<span<<") => "<< st << et;
00587     Q_FOREACH( const Constraint& c, constraints ) {
00588         if ( c.type() != Constraint::TypeHard || !isSatisfiedConstraint( c )) continue;
00589         if ( c.startIndex() == idx ) {
00590             QDateTime tmpst = model()->data( c.endIndex(), StartTimeRole ).toDateTime();
00591             //qDebug() << tmpst << "<" << et <<"?";
00592             if ( tmpst<et ) return false;
00593         } else if ( c.endIndex() == idx ) {
00594             QDateTime tmpet = model()->data( c.startIndex(), EndTimeRole ).toDateTime();
00595             //qDebug() << tmpet << ">" << st <<"?";
00596             if ( tmpet>st ) return false;
00597         }
00598     }
00599 
00600     return model()->setData( idx, qVariantFromValue(st), StartTimeRole )
00601         && model()->setData( idx, qVariantFromValue(et), EndTimeRole );
00602 }
00603 
00604 Qt::PenStyle DateTimeGrid::Private::gridLinePenStyle( QDateTime dt, Private::HeaderType headerType ) const
00605 {
00606     switch ( headerType ) {
00607         case Private::HeaderHour:
00608             // Midnight
00609             if ( dt.time().hour() == 0 )
00610                 return Qt::SolidLine;
00611             return Qt::DashLine;
00612         case Private::HeaderDay:
00613             // First day of the week
00614             if ( dt.date().dayOfWeek() == weekStart )
00615                 return Qt::SolidLine;
00616             return Qt::DashLine;
00617         case Private::HeaderWeek:
00618             // First day of the month
00619             if ( dt.date().day() == 1 )
00620                 return Qt::SolidLine;
00621             // First day of the week
00622             if ( dt.date().dayOfWeek() == weekStart )
00623                 return Qt::DashLine;
00624             return Qt::NoPen;
00625         case Private::HeaderMonth:
00626             // First day of the year
00627             if ( dt.date().dayOfYear() == 1 )
00628                 return Qt::SolidLine;
00629             // First day of the month
00630             if ( dt.date().day() == 1 )
00631                 return Qt::DashLine;
00632             return Qt::NoPen;
00633         default:
00634             // Nothing to do here
00635             break;
00636    }
00637 
00638     // Default
00639     return Qt::NoPen;
00640 }
00641 
00642 QDateTime DateTimeGrid::Private::adjustDateTimeForHeader( QDateTime dt, Private::HeaderType headerType ) const
00643 {
00644     // In any case, set time to 00:00:00:00
00645     dt.setTime( QTime( 0, 0, 0, 0 ) );
00646 
00647     switch ( headerType ) {
00648         case Private::HeaderWeek:
00649             // Set day to beginning of the week
00650             while ( dt.date().dayOfWeek() != weekStart )
00651                 dt = dt.addDays( -1 );
00652             break;
00653         case Private::HeaderMonth:
00654             // Set day to beginning of the month
00655             dt = dt.addDays( 1 - dt.date().day() );
00656             break;
00657         case Private::HeaderYear:
00658             // Set day to first day of the year
00659             dt = dt.addDays( 1 - dt.date().dayOfYear() );
00660             break;
00661         default:
00662             // In any other case, we don't need to adjust the date time
00663             break;
00664     }
00665 
00666     return dt;
00667 }
00668 
00669 void DateTimeGrid::Private::paintVerticalLines( QPainter* painter,
00670                                                 const QRectF& sceneRect,
00671                                                 const QRectF& exposedRect,
00672                                                 QWidget* widget,
00673                                                 Private::HeaderType headerType )
00674 {
00675         QDateTime dt = chartXtoDateTime( exposedRect.left() );
00676         dt = adjustDateTimeForHeader( dt, headerType );
00677 
00678         int offsetSeconds = 0;
00679         int offsetDays = 0;
00680         // Determine the time step per grid line
00681         if ( headerType == Private::HeaderHour )
00682             offsetSeconds = 60*60;
00683         else
00684             offsetDays = 1;
00685 
00686         for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
00687               dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), x = dateTimeToChartX( dt ) ) {
00688             if ( x >= exposedRect.left() ) {
00689                 QPen pen = painter->pen();
00690                 pen.setBrush( QApplication::palette().dark() );
00691                 pen.setStyle( gridLinePenStyle( dt, headerType ) );
00692                 painter->setPen( pen );
00693                 if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
00694                     if(freeDaysBrush.style() == Qt::NoBrush)
00695                         painter->setBrush( widget?widget->palette().midlight()
00696                                            :QApplication::palette().midlight() );
00697                     else
00698                         painter->setBrush(freeDaysBrush);
00699 
00700                     painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
00701                 }
00702                 painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
00703             }
00704         }
00705 }
00706 
00707 void DateTimeGrid::Private::paintVerticalUserDefinedLines( QPainter* painter,
00708                                                            const QRectF& sceneRect,
00709                                                            const QRectF& exposedRect,
00710                                                            const DateTimeScaleFormatter* formatter,
00711                                                            QWidget* widget )
00712 {
00713     Q_UNUSED( widget );
00714     QDateTime dt = chartXtoDateTime( exposedRect.left() );
00715     dt = formatter->currentRangeBegin( dt );
00716     QPen pen = painter->pen();
00717     pen.setBrush( QApplication::palette().dark() );
00718     pen.setStyle( Qt::DashLine );
00719     painter->setPen( pen );
00720     for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
00721           dt = formatter->nextRangeBegin( dt ),x=dateTimeToChartX( dt ) ) {
00722         if ( x >= exposedRect.left() ) {
00723             // FIXME: Also fill area between this and the next vertical line to indicate free days? (Johannes)
00724             painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
00725         }
00726     }
00727 }
00728 
00729 DateTimeGrid::Private::HeaderType DateTimeGrid::Private::headerTypeForScale( DateTimeGrid::Scale scale )
00730 {
00731     switch ( scale ) {
00732         case ScaleHour:
00733             return Private::HeaderHour;
00734         case ScaleDay:
00735             return Private::HeaderDay;
00736         case ScaleWeek:
00737             return Private::HeaderWeek;
00738         case ScaleMonth:
00739             return Private::HeaderMonth;
00740         default:
00741             // There are no specific header types for any other scale!
00742             assert( false );
00743             break;
00744     }
00745 }
00746 
00747 void DateTimeGrid::paintGrid( QPainter* painter,
00748                               const QRectF& sceneRect,
00749                               const QRectF& exposedRect,
00750                               AbstractRowController* rowController,
00751                               QWidget* widget )
00752 {
00753     // TODO: Support hours and weeks
00754     switch( scale() ) {
00755     case ScaleHour:
00756     case ScaleDay:
00757     case ScaleWeek:
00758     case ScaleMonth:
00759         d->paintVerticalLines( painter, sceneRect, exposedRect, widget, d->headerTypeForScale( scale() ) );
00760         break;
00761     case ScaleAuto: {
00762         const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
00763         const qreal dayw = dayWidth();
00764         if ( dayw > 24*60*60*tabw ) {
00765 
00766             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->minute_lower, widget );
00767         } else if ( dayw > 24*60*tabw ) {
00768             d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderHour );
00769         } else if ( dayw > 24*tabw ) {
00770         d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderDay );
00771         } else if ( dayw > tabw ) {
00772             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->week_lower, widget );
00773         } else if ( 4*dayw > tabw ) {
00774             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->month_lower, widget );
00775         } else {
00776             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->year_lower, widget );
00777         }
00778         break;
00779     }
00780     case ScaleUserDefined:
00781         d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, d->lower, widget );
00782         break;
00783     }
00784     if ( rowController ) {
00785         // First draw the rows
00786         QPen pen = painter->pen();
00787         pen.setBrush( QApplication::palette().dark() );
00788         pen.setStyle( Qt::DashLine );
00789         painter->setPen( pen );
00790         QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
00791         if ( rowController->indexAbove( idx ).isValid() ) idx = rowController->indexAbove( idx );
00792         qreal y = 0;
00793         while ( y < exposedRect.bottom() && idx.isValid() ) {
00794             const Span s = rowController->rowGeometry( idx );
00795             y = s.start()+s.length();
00796             if ( d->rowSeparators ) {
00797                 painter->drawLine( QPointF( sceneRect.left(), y ),
00798                                    QPointF( sceneRect.right(), y ) );
00799             }
00800             if ( !idx.data( ItemTypeRole ).isValid() && d->noInformationBrush.style() != Qt::NoBrush ) {
00801                 painter->fillRect( QRectF( exposedRect.left(), s.start(), exposedRect.width(), s.length() ), d->noInformationBrush );
00802             }
00803             // Is alternating background better?
00804             //if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
00805             idx =  rowController->indexBelow( idx );
00806         }
00807     }
00808 }
00809 
00810 int DateTimeGrid::Private::tabHeight( const QString& txt, QWidget* widget ) const
00811 {
00812     QStyleOptionHeader opt;
00813     if ( widget ) opt.initFrom( widget );
00814     opt.text = txt;
00815     QStyle* style;
00816     if ( widget ) style = widget->style();
00817     else style = QApplication::style();
00818     QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
00819     return s.height();
00820 }
00821 
00822 void DateTimeGrid::Private::getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
00823 {
00824     const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
00825     const qreal dayw = dayWidth;
00826     if ( dayw > 24*60*60*tabw ) {
00827         *lower = &minute_lower;
00828         *upper = &minute_upper;
00829     } else if ( dayw > 24*60*tabw ) {
00830         *lower = &hour_lower;
00831         *upper = &hour_upper;
00832     } else if ( dayw > 24*tabw ) {
00833         *lower = &day_lower;
00834         *upper = &day_upper;
00835     } else if ( dayw > tabw ) {
00836         *lower = &week_lower;
00837         *upper = &week_upper;
00838     } else if ( 4*dayw > tabw ) {
00839         *lower = &month_lower;
00840         *upper = &month_upper;
00841     } else {
00842         *lower = &year_lower;
00843         *upper = &year_upper;
00844     }
00845 }
00846 
00847 
00848 void DateTimeGrid::paintHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00849                                 qreal offset, QWidget* widget )
00850 {
00851     painter->save();
00852     QPainterPath clipPath;
00853     clipPath.addRect( headerRect );
00854     painter->setClipPath( clipPath, Qt::IntersectClip );
00855     switch( scale() )
00856     {
00857     case ScaleHour:
00858         paintHourScaleHeader( painter, headerRect, exposedRect, offset, widget );
00859         break;
00860     case ScaleDay:
00861         paintDayScaleHeader( painter, headerRect, exposedRect, offset, widget );
00862         break;
00863     case ScaleWeek:
00864         paintWeekScaleHeader( painter, headerRect, exposedRect, offset, widget );
00865         break;
00866     case ScaleMonth:
00867         paintMonthScaleHeader( painter, headerRect, exposedRect, offset, widget );
00868         break;
00869     case ScaleAuto:
00870         {
00871             DateTimeScaleFormatter *lower, *upper;
00872             d->getAutomaticFormatters( &lower, &upper );
00873             const qreal lowerHeight = d->tabHeight( lower->text( startDateTime() ) );
00874             const qreal upperHeight = d->tabHeight( upper->text( startDateTime() ) );
00875             const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
00876 
00877             const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
00878             const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1,  headerRect.height()-upperHeaderRect.height()-1 );
00879 
00880             paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, lower, widget );
00881             paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, upper, widget );
00882             break;
00883         }
00884     case ScaleUserDefined:
00885         {
00886             const qreal lowerHeight = d->tabHeight( d->lower->text( startDateTime() ) );
00887             const qreal upperHeight = d->tabHeight( d->upper->text( startDateTime() ) );
00888             const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
00889 
00890             const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
00891             const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1,  headerRect.height()-upperHeaderRect.height()-1 );
00892 
00893             paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, d->lower, widget );
00894             paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, d->upper, widget );
00895         }
00896         break;
00897     }
00898     painter->restore();
00899 }
00900 
00901 void DateTimeGrid::paintUserDefinedHeader( QPainter* painter,
00902                                            const QRectF& headerRect, const QRectF& exposedRect,
00903                                            qreal offset, const DateTimeScaleFormatter* formatter,
00904                                            QWidget* widget )
00905 {
00906     const QStyle* const style = widget ? widget->style() : QApplication::style();
00907 
00908     QDateTime dt = formatter->currentRangeBegin( d->chartXtoDateTime( offset + exposedRect.left() ));
00909     qreal x = d->dateTimeToChartX( dt );
00910 
00911     while( x < exposedRect.right() + offset ) {
00912         const QDateTime next = formatter->nextRangeBegin( dt );
00913         const qreal nextx = d->dateTimeToChartX( next );
00914 
00915         QStyleOptionHeader opt;
00916         if ( widget ) opt.init( widget );
00917         opt.rect = QRectF( x - offset+1, headerRect.top(), qMax<qreal>( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
00918         opt.textAlignment = formatter->alignment();
00919         opt.text = formatter->text( dt );
00920         style->drawControl( QStyle::CE_Header, &opt, painter, widget );
00921 
00922         dt = next;
00923         x = nextx;
00924     }
00925 }
00926 
00927 void DateTimeGrid::Private::paintHeader( QPainter* painter,
00928                                          const QRectF& headerRect, const QRectF& exposedRect,
00929                                          qreal offset, QWidget* widget,
00930                                          Private::HeaderType headerType,
00931                                          DateTextFormatter *formatter )
00932 {
00933     QStyle* style = widget?widget->style():QApplication::style();
00934 
00935     const qreal left = exposedRect.left() + offset;
00936     const qreal right = exposedRect.right() + offset;
00937 
00938     // Paint a section for each hour
00939     QDateTime dt = chartXtoDateTime( left );
00940     dt = adjustDateTimeForHeader( dt, headerType );
00941     // Determine the time step per grid line
00942     int offsetSeconds = 0;
00943     int offsetDays = 0;
00944     int offsetMonths = 0;
00945 
00946     switch ( headerType ) {
00947         case Private::HeaderHour:
00948             offsetSeconds = 60*60;
00949             break;
00950         case Private::HeaderDay:
00951             offsetDays = 1;
00952             break;
00953         case Private::HeaderWeek:
00954             offsetDays = 7;
00955             break;
00956         case Private::HeaderMonth:
00957             offsetMonths = 1;
00958             break;
00959         case Private::HeaderYear:
00960             offsetMonths = 12;
00961             break;
00962         default:
00963             // Other scales cannot be painted with this method!
00964             assert( false );
00965             break;
00966     }
00967 
00968     for ( qreal x = dateTimeToChartX( dt ); x < right;
00969           dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), dt = dt.addMonths( offsetMonths ),
00970           x = dateTimeToChartX( dt ) ) {
00971         QStyleOptionHeader opt;
00972         if ( widget ) opt.init( widget );
00973         opt.rect = formatter->textRect( x, offset, dayWidth, headerRect, dt );
00974         opt.text = formatter->format( dt );
00975         opt.textAlignment = Qt::AlignCenter;
00976         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00977     }
00978 }
00979 
00983 void DateTimeGrid::paintHourScaleHeader( QPainter* painter,
00984                                          const QRectF& headerRect, const QRectF& exposedRect,
00985                                          qreal offset, QWidget* widget )
00986 {
00987     class HourFormatter : public Private::DateTextFormatter {
00988     public:
00989         virtual ~HourFormatter() {}
00990 
00991         QString format( const QDateTime& dt ) {
00992             return dt.time().toString( QString::fromAscii( "hh" ) );
00993         }
00994         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
00995             Q_UNUSED(dt);
00996 
00997             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
00998                            QSizeF( dayWidth / 24.0, headerRect.height() / 2.0 ) ).toAlignedRect();
00999         }
01000     };
01001     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01002                     Private::HeaderHour, new HourFormatter ); // Custom parameters
01003 
01004     class DayFormatter : public Private::DateTextFormatter {
01005     public:
01006         virtual ~DayFormatter() {}
01007         QString format( const QDateTime& dt ) {
01008             return dt.date().toString();
01009         }
01010         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01011             Q_UNUSED(dt);
01012 
01013             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01014                            QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toRect();
01015         }
01016     };
01017     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01018                     Private::HeaderDay, new DayFormatter ); // Custom parameters
01019 }
01020 
01024 void DateTimeGrid::paintDayScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01025                                 qreal offset, QWidget* widget )
01026 {
01027     class DayFormatter : public Private::DateTextFormatter {
01028     public:
01029         virtual ~DayFormatter() {}
01030 
01031         QString format( const QDateTime& dt ) {
01032             return dt.toString( QString::fromAscii( "ddd" ) ).left( 1 );
01033         }
01034         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01035             Q_UNUSED(dt);
01036 
01037             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
01038                            QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toAlignedRect();
01039         }
01040     };
01041     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01042                     Private::HeaderDay, new DayFormatter ); // Custom parameters
01043 
01044     class WeekFormatter : public Private::DateTextFormatter {
01045     public:
01046         virtual ~WeekFormatter() {}
01047         QString format( const QDateTime& dt ) {
01048             return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
01049         }
01050         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01051             Q_UNUSED(dt);
01052 
01053             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01054                            QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
01055         }
01056     };
01057     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01058                     Private::HeaderWeek, new WeekFormatter ); // Custom parameters
01059 }
01060 
01064 void DateTimeGrid::paintWeekScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01065                                         qreal offset, QWidget* widget )
01066 {
01067     class WeekFormatter : public Private::DateTextFormatter {
01068     public:
01069         virtual ~WeekFormatter() {}
01070 
01071         QString format( const QDateTime& dt ) {
01072             return QString::number( dt.date().weekNumber() );
01073         }
01074         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01075             Q_UNUSED(dt);
01076 
01077             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
01078                            QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
01079         }
01080     };
01081     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01082                     Private::HeaderWeek, new WeekFormatter ); // Custom parameters
01083 
01084     class MonthFormatter : public Private::DateTextFormatter {
01085     public:
01086         virtual ~MonthFormatter() {}
01087 
01088         QString format( const QDateTime& dt ) {
01089             return QLocale().monthName(dt.date().month(), QLocale::LongFormat) + QLatin1String("/") + QString::number(dt.date().year());
01090         }
01091         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01092             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01093                            QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
01094         }
01095     };
01096     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01097                     Private::HeaderMonth, new MonthFormatter ); // Custom parameters
01098 }
01099 
01103 void DateTimeGrid::paintMonthScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01104                                         qreal offset, QWidget* widget )
01105 {
01106     class MonthFormatter : public Private::DateTextFormatter {
01107     public:
01108         virtual ~MonthFormatter() {}
01109 
01110         QString format( const QDateTime& dt ) {
01111             return QLocale().monthName(dt.date().month(), QLocale::ShortFormat) + QLatin1String("/") + QString::number(dt.date().year());
01112         }
01113         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01114             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
01115                            QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
01116         }
01117     };
01118     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01119                     Private::HeaderMonth, new MonthFormatter ); // Custom parameters
01120 
01121     class YearFormatter : public Private::DateTextFormatter {
01122     public:
01123         virtual ~YearFormatter() {}
01124 
01125         QString format( const QDateTime& dt ) {
01126             return QString::number( dt.date().year() );
01127         }
01128         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01129             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01130                            QSizeF( dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0 ) ).toRect();
01131         }
01132     };
01133     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01134                     Private::HeaderYear, new YearFormatter ); // Custom parameters
01135 }
01136 
01140 void DateTimeGrid::drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date)
01141 {
01142     Q_UNUSED(painter);
01143     Q_UNUSED(rect);
01144     Q_UNUSED(date);
01145 }
01146 
01150 void DateTimeGrid::drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date)
01151 {
01152     Q_UNUSED(painter);
01153     Q_UNUSED(rect);
01154     Q_UNUSED(date);
01155 }
01156 
01160 QRectF DateTimeGrid::computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const
01161 {
01162     qreal topLeft = d->dateTimeToChartX(from);
01163     qreal topRight = d->dateTimeToChartX(to);
01164 
01165     return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
01166 }
01167 
01171 QPair<QDateTime, QDateTime> DateTimeGrid::dateTimeRange(const QRectF& rect) const
01172 {
01173     QDateTime start;
01174     QDateTime end;
01175 
01176     start = d->chartXtoDateTime(rect.left());
01177     end = d->chartXtoDateTime(rect.right());
01178 
01179     return qMakePair(start, end);
01180 }
01181 
01182 void DateTimeGrid::drawBackground(QPainter* paint, const QRectF& rect)
01183 {
01184     int offset = (int)dayWidth();
01185 
01186     // Figure out the date at the extreme left
01187     QDate date = d->chartXtoDateTime(rect.left()).date();
01188 
01189     // We need to paint from one end to the other
01190     int startx = rect.left();
01191     int endx = rect.right();
01192 
01193     // Save the painter state
01194     paint->save();
01195 
01196     // Paint the first date column
01197     while(1)
01198     {
01199         QDate nextDate = d->chartXtoDateTime(startx+1).date();
01200         if(date != nextDate)
01201         {
01202             QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
01203             dayRect = dayRect.adjusted(1, 0, 0, 0);
01204             drawDayBackground(paint, dayRect, date);
01205             break;
01206         }
01207 
01208         ++startx;
01209     }
01210 
01211     // Paint the remaining dates
01212     for(int i=startx; i<endx; i+=offset)
01213     {
01214         date = d->chartXtoDateTime(i+1).date();
01215 
01216         QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
01217         dayRect = dayRect.adjusted(1, 0, 0, 0);
01218         drawDayBackground(paint, dayRect, date);
01219     }
01220 
01221     // Restore the painter state
01222     paint->restore();
01223 }
01224 
01225 void DateTimeGrid::drawForeground(QPainter* paint, const QRectF& rect)
01226 {
01227     int offset = (int)dayWidth();
01228 
01229     // Figure out the date at the extreme left
01230     QDate date = d->chartXtoDateTime(rect.left()).date();
01231 
01232     // We need to paint from one end to the other
01233     int startx = rect.left();
01234     int endx = rect.right();
01235 
01236     // Save the painter state
01237     paint->save();
01238 
01239     // Paint the first date column
01240     while(1)
01241     {
01242         QDate nextDate = d->chartXtoDateTime(startx+1).date();
01243         if(date != nextDate)
01244         {
01245             QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
01246             dayRect = dayRect.adjusted(1, 0, 0, 0);
01247             drawDayForeground(paint, dayRect, date);
01248             break;
01249         }
01250 
01251         ++startx;
01252     }
01253 
01254     // Paint the remaining dates
01255     for(int i=startx; i<endx; i+=offset)
01256     {
01257         date = d->chartXtoDateTime(i+1).date();
01258 
01259         QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
01260         dayRect = dayRect.adjusted(1, 0, 0, 0);
01261         drawDayForeground(paint, dayRect, date);
01262     }
01263 
01264     // Restore the painter state
01265     paint->restore();
01266 }
01267 
01268 #undef d
01269 
01270 #ifndef KDAB_NO_UNIT_TESTS
01271 
01272 #include <QStandardItemModel>
01273 #include "unittest/test.h"
01274 
01275 namespace {
01276     std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
01277     {
01278 #ifdef QT_NO_STL
01279         os << dt.toString().toLatin1().constData();
01280 #else
01281         os << dt.toString().toStdString();
01282 #endif
01283         return os;
01284     }
01285 }
01286 
01287 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, DateTimeGrid, "test" ) {
01288     QStandardItemModel model( 3, 2 );
01289     DateTimeGrid grid;
01290     QDateTime dt = QDateTime::currentDateTime();
01291     grid.setModel( &model );
01292     QDateTime startdt = dt.addDays( -10 );
01293     grid.setStartDateTime( startdt );
01294 
01295     model.setData( model.index( 0, 0 ), dt,               StartTimeRole );
01296     model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
01297 
01298     model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
01299     model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
01300 
01301     Span s = grid.mapToChart( model.index( 0, 0 ) );
01302     //qDebug() << "span="<<s;
01303 
01304     assertTrue( s.start()>0 );
01305     assertTrue( s.length()>0 );
01306 
01307     assertTrue( startdt == grid.mapToDateTime( grid.mapFromDateTime( startdt ) ) );
01308 
01309     grid.mapFromChart( s, model.index( 1, 0 ) );
01310 
01311     QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
01312     QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
01313     QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
01314     QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
01315 
01316     assertTrue( s1.isValid() );
01317     assertTrue( e1.isValid() );
01318     assertTrue( s2.isValid() );
01319     assertTrue( e2.isValid() );
01320 
01321     assertEqual( s1, s2 );
01322     assertEqual( e1, e2 );
01323 
01324     assertTrue( grid.isSatisfiedConstraint( Constraint( model.index( 0, 0 ), model.index( 2, 0 ) ) ) );
01325     assertFalse( grid.isSatisfiedConstraint( Constraint( model.index( 2, 0 ), model.index( 0, 0 ) ) ) );
01326 
01327     s = grid.mapToChart( model.index( 0, 0 ) );
01328     s.setEnd( s.end()+100000. );
01329     bool rc = grid.mapFromChart( s, model.index( 0, 0 ) );
01330     assertTrue( rc );
01331     assertEqual( s1, model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime() );
01332     Span newspan = grid.mapToChart( model.index( 0, 0 ) );
01333     assertEqual( newspan.start(), s.start() );
01334     assertEqual( newspan.length(), s.length() );
01335 
01336     {
01337         QDateTime startDateTime = QDateTime::currentDateTime();
01338         qreal dayWidth = 100;
01339         QDate currentDate = QDate::currentDate();
01340         QDateTime dt( QDate(currentDate.year(), 1, 1),  QTime( 0, 0, 0, 0 ) );
01341         assert( dt.isValid() );
01342         qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
01343         result += startDateTime.time().msecsTo(dt.time())/1000.;
01344         result *= dayWidth/( 24.*60.*60. );
01345 
01346         int days = static_cast<int>( result/dayWidth );
01347         qreal secs = result*( 24.*60.*60. )/dayWidth;
01348         QDateTime dt2 = startDateTime;
01349         QDateTime result2 = dt2.addDays( days ).addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) ).addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
01350 
01351         assertEqual( dt, result2 );
01352     }
01353 }
01354 
01355 #endif /* KDAB_NO_UNIT_TESTS */
01356 
01357 #include "moc_kdganttdatetimegrid.cpp"
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/