KD Chart 2  [rev.2.5]
kdganttdatetimegrid.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2012 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 
00364 void DateTimeGrid::setScale( Scale s )
00365 {
00366     d->scale = s;
00367     emit gridChanged();
00368 }
00369 
00376 DateTimeGrid::Scale DateTimeGrid::scale() const
00377 {
00378     return d->scale;
00379 }
00380 
00388 void DateTimeGrid::setUserDefinedLowerScale( DateTimeScaleFormatter* lower )
00389 {
00390     delete d->lower;
00391     d->lower = lower;
00392     emit gridChanged();
00393 }
00394 
00402 void DateTimeGrid::setUserDefinedUpperScale( DateTimeScaleFormatter* upper )
00403 {
00404     delete d->upper;
00405     d->upper = upper;
00406     emit gridChanged();
00407 }
00408 
00411 DateTimeScaleFormatter* DateTimeGrid::userDefinedLowerScale() const
00412 {
00413     return d->lower;
00414 }
00415 
00418 DateTimeScaleFormatter* DateTimeGrid::userDefinedUpperScale() const
00419 {
00420     return d->upper;
00421 }
00422 
00428 void DateTimeGrid::setWeekStart( Qt::DayOfWeek ws )
00429 {
00430     d->weekStart = ws;
00431     emit gridChanged();
00432 }
00433 
00435 Qt::DayOfWeek DateTimeGrid::weekStart() const
00436 {
00437     return d->weekStart;
00438 }
00439 
00446 void DateTimeGrid::setFreeDays( const QSet<Qt::DayOfWeek>& fd )
00447 {
00448     d->freeDays = fd;
00449     emit gridChanged();
00450 }
00451 
00453 QSet<Qt::DayOfWeek> DateTimeGrid::freeDays() const
00454 {
00455     return d->freeDays;
00456 }
00457 
00460 void DateTimeGrid::setFreeDaysBrush(const QBrush brush)
00461 {
00462     d->freeDaysBrush = brush;
00463 }
00464 
00468 QBrush DateTimeGrid::freeDaysBrush() const
00469 {
00470     return d->freeDaysBrush;
00471 }
00472 
00474 bool DateTimeGrid::rowSeparators() const
00475 {
00476     return d->rowSeparators;
00477 }
00479 void DateTimeGrid::setRowSeparators( bool enable )
00480 {
00481     d->rowSeparators = enable;
00482 }
00483 
00488 void DateTimeGrid::setNoInformationBrush( const QBrush& brush )
00489 {
00490     d->noInformationBrush = brush;
00491     emit gridChanged();
00492 }
00493 
00496 QBrush DateTimeGrid::noInformationBrush() const
00497 {
00498     return d->noInformationBrush;
00499 }
00500 
00505 qreal DateTimeGrid::mapToChart( const QVariant& value ) const
00506 {
00507     if ( ! qVariantCanConvert<QDateTime>( value ) ||
00508          ( value.type() == QVariant::String && qVariantValue<QString>(value).isEmpty() ) )
00509     {
00510         return -1.0;
00511     }
00512     return d->dateTimeToChartX( value.toDateTime() );
00513 }
00514 
00519 QVariant DateTimeGrid::mapFromChart( qreal x ) const
00520 {
00521     return d->chartXtoDateTime( x );
00522 }
00523 
00527 Span DateTimeGrid::mapToChart( const QModelIndex& idx ) const
00528 {
00529     assert( model() );
00530     if ( !idx.isValid() ) return Span();
00531     assert( idx.model()==model() );
00532     const QVariant sv = model()->data( idx, StartTimeRole );
00533     const QVariant ev = model()->data( idx, EndTimeRole );
00534     if( qVariantCanConvert<QDateTime>(sv) &&
00535     qVariantCanConvert<QDateTime>(ev) &&
00536     !(sv.type() == QVariant::String && qVariantValue<QString>(sv).isEmpty()) &&
00537     !(ev.type() == QVariant::String && qVariantValue<QString>(ev).isEmpty())
00538     ) {
00539       QDateTime st = sv.toDateTime();
00540       QDateTime et = ev.toDateTime();
00541       if ( et.isValid() && st.isValid() ) {
00542         qreal sx = d->dateTimeToChartX( st );
00543         qreal ex = d->dateTimeToChartX( et )-sx;
00544         //qDebug() << "DateTimeGrid::mapToChart("<<st<<et<<") => "<< Span( sx, ex );
00545         return Span( sx, ex);
00546       }
00547     }
00548     // Special case for Events with only a start date
00549     if( qVariantCanConvert<QDateTime>(sv) && !(sv.type() == QVariant::String && qVariantValue<QString>(sv).isEmpty()) ) {
00550       QDateTime st = sv.toDateTime();
00551       if ( st.isValid() ) {
00552         qreal sx = d->dateTimeToChartX( st );
00553         return Span( sx, 0 );
00554       }
00555     }
00556     return Span();
00557 }
00558 
00559 #if 0
00560 static void debug_print_idx( const QModelIndex& idx )
00561 {
00562     if ( !idx.isValid() ) {
00563         qDebug() << "[Invalid]";
00564         return;
00565     }
00566     QDateTime st = idx.data( StartTimeRole ).toDateTime();
00567     QDateTime et = idx.data( EndTimeRole ).toDateTime();
00568     qDebug() << idx << "["<<st<<et<<"]";
00569 }
00570 #endif
00571 
00586 bool DateTimeGrid::mapFromChart( const Span& span, const QModelIndex& idx,
00587     const QList<Constraint>& constraints ) const
00588 {
00589     assert( model() );
00590     if ( !idx.isValid() ) return false;
00591     assert( idx.model()==model() );
00592 
00593     QDateTime st = d->chartXtoDateTime(span.start());
00594     QDateTime et = d->chartXtoDateTime(span.start()+span.length());
00595     //qDebug() << "DateTimeGrid::mapFromChart("<<span<<") => "<< st << et;
00596     Q_FOREACH( const Constraint& c, constraints ) {
00597         if ( c.type() != Constraint::TypeHard || !isSatisfiedConstraint( c )) continue;
00598         if ( c.startIndex() == idx ) {
00599             QDateTime tmpst = model()->data( c.endIndex(), StartTimeRole ).toDateTime();
00600             //qDebug() << tmpst << "<" << et <<"?";
00601             if ( tmpst<et ) return false;
00602         } else if ( c.endIndex() == idx ) {
00603             QDateTime tmpet = model()->data( c.startIndex(), EndTimeRole ).toDateTime();
00604             //qDebug() << tmpet << ">" << st <<"?";
00605             if ( tmpet>st ) return false;
00606         }
00607     }
00608 
00609     return model()->setData( idx, qVariantFromValue(st), StartTimeRole )
00610         && model()->setData( idx, qVariantFromValue(et), EndTimeRole );
00611 }
00612 
00613 Qt::PenStyle DateTimeGrid::Private::gridLinePenStyle( QDateTime dt, Private::HeaderType headerType ) const
00614 {
00615     switch ( headerType ) {
00616         case Private::HeaderHour:
00617             // Midnight
00618             if ( dt.time().hour() == 0 )
00619                 return Qt::SolidLine;
00620             return Qt::DashLine;
00621         case Private::HeaderDay:
00622             // First day of the week
00623             if ( dt.date().dayOfWeek() == weekStart )
00624                 return Qt::SolidLine;
00625             return Qt::DashLine;
00626         case Private::HeaderWeek:
00627             // First day of the month
00628             if ( dt.date().day() == 1 )
00629                 return Qt::SolidLine;
00630             // First day of the week
00631             if ( dt.date().dayOfWeek() == weekStart )
00632                 return Qt::DashLine;
00633             return Qt::NoPen;
00634         case Private::HeaderMonth:
00635             // First day of the year
00636             if ( dt.date().dayOfYear() == 1 )
00637                 return Qt::SolidLine;
00638             // First day of the month
00639             if ( dt.date().day() == 1 )
00640                 return Qt::DashLine;
00641             return Qt::NoPen;
00642         default:
00643             // Nothing to do here
00644             break;
00645    }
00646 
00647     // Default
00648     return Qt::NoPen;
00649 }
00650 
00651 QDateTime DateTimeGrid::Private::adjustDateTimeForHeader( QDateTime dt, Private::HeaderType headerType ) const
00652 {
00653     // In any case, set time to 00:00:00:00
00654     dt.setTime( QTime( 0, 0, 0, 0 ) );
00655 
00656     switch ( headerType ) {
00657         case Private::HeaderWeek:
00658             // Set day to beginning of the week
00659             while ( dt.date().dayOfWeek() != weekStart )
00660                 dt = dt.addDays( -1 );
00661             break;
00662         case Private::HeaderMonth:
00663             // Set day to beginning of the month
00664             dt = dt.addDays( 1 - dt.date().day() );
00665             break;
00666         case Private::HeaderYear:
00667             // Set day to first day of the year
00668             dt = dt.addDays( 1 - dt.date().dayOfYear() );
00669             break;
00670         default:
00671             // In any other case, we don't need to adjust the date time
00672             break;
00673     }
00674 
00675     return dt;
00676 }
00677 
00678 void DateTimeGrid::Private::paintVerticalLines( QPainter* painter,
00679                                                 const QRectF& sceneRect,
00680                                                 const QRectF& exposedRect,
00681                                                 QWidget* widget,
00682                                                 Private::HeaderType headerType )
00683 {
00684         QDateTime dt = chartXtoDateTime( exposedRect.left() );
00685         dt = adjustDateTimeForHeader( dt, headerType );
00686 
00687         int offsetSeconds = 0;
00688         int offsetDays = 0;
00689         // Determine the time step per grid line
00690         if ( headerType == Private::HeaderHour )
00691             offsetSeconds = 60*60;
00692         else
00693             offsetDays = 1;
00694 
00695         for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
00696               dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), x = dateTimeToChartX( dt ) ) {
00697                   //TODO not the best solution as it might be one paint too much, but i don't know what
00698                   //causes the test to fail yet, i think it might be a rounding error
00699             //if ( x >= exposedRect.left() ) {
00700                 QPen pen = painter->pen();
00701                 pen.setBrush( QApplication::palette().dark() );
00702                 pen.setStyle( gridLinePenStyle( dt, headerType ) );
00703                 painter->setPen( pen );
00704                 if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
00705                     if(freeDaysBrush.style() == Qt::NoBrush)
00706                         painter->setBrush( widget?widget->palette().midlight()
00707                                            :QApplication::palette().midlight() );
00708                     else
00709                         painter->setBrush(freeDaysBrush);
00710 
00711                     painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
00712                 }
00713                 painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
00714             //}
00715         }
00716 }
00717 
00718 void DateTimeGrid::Private::paintVerticalUserDefinedLines( QPainter* painter,
00719                                                            const QRectF& sceneRect,
00720                                                            const QRectF& exposedRect,
00721                                                            const DateTimeScaleFormatter* formatter,
00722                                                            QWidget* widget )
00723 {
00724     Q_UNUSED( widget );
00725     QDateTime dt = chartXtoDateTime( exposedRect.left() );
00726     dt = formatter->currentRangeBegin( dt );
00727     QPen pen = painter->pen();
00728     pen.setBrush( QApplication::palette().dark() );
00729     pen.setStyle( Qt::DashLine );
00730     painter->setPen( pen );
00731     for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
00732         dt = formatter->nextRangeBegin( dt ),x=dateTimeToChartX( dt ) ) {
00733         if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
00734             QBrush oldBrush = painter->brush();
00735             if(freeDaysBrush.style() == Qt::NoBrush)
00736                 painter->setBrush( widget?widget->palette().midlight()
00737                                  :QApplication::palette().midlight() );
00738             else
00739                 painter->setBrush(freeDaysBrush);
00740 
00741           painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
00742           painter->setBrush( oldBrush );
00743         }
00744               //TODO not the best solution as it might be one paint too much, but i don't know what
00745               //causes the test to fail yet, i think it might be a rounding error
00746         //if ( x >= exposedRect.left() ) {
00747             // FIXME: Also fill area between this and the next vertical line to indicate free days? (Johannes)
00748     painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
00749         //}
00750     }
00751 }
00752 
00753 DateTimeGrid::Private::HeaderType DateTimeGrid::Private::headerTypeForScale( DateTimeGrid::Scale scale )
00754 {
00755     switch ( scale ) {
00756         case ScaleHour:
00757             return Private::HeaderHour;
00758         case ScaleDay:
00759             return Private::HeaderDay;
00760         case ScaleWeek:
00761             return Private::HeaderWeek;
00762         case ScaleMonth:
00763             return Private::HeaderMonth;
00764         default:
00765             // There are no specific header types for any other scale!
00766             assert( false );
00767             break;
00768     }
00769         return Private::HeaderDay;
00770 }
00771 
00772 void DateTimeGrid::paintGrid( QPainter* painter,
00773                               const QRectF& sceneRect,
00774                               const QRectF& exposedRect,
00775                               AbstractRowController* rowController,
00776                               QWidget* widget )
00777 {
00778     // TODO: Support hours and weeks
00779     switch( scale() ) {
00780     case ScaleHour:
00781     case ScaleDay:
00782     case ScaleWeek:
00783     case ScaleMonth:
00784         d->paintVerticalLines( painter, sceneRect, exposedRect, widget, d->headerTypeForScale( scale() ) );
00785         break;
00786     case ScaleAuto: {
00787         const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
00788         const qreal dayw = dayWidth();
00789         if ( dayw > 24*60*60*tabw ) {
00790 
00791             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->minute_lower, widget );
00792         } else if ( dayw > 24*60*tabw ) {
00793             d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderHour );
00794         } else if ( dayw > 24*tabw ) {
00795         d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderDay );
00796         } else if ( dayw > tabw ) {
00797             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->week_lower, widget );
00798         } else if ( 4*dayw > tabw ) {
00799             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->month_lower, widget );
00800         } else {
00801             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->year_lower, widget );
00802         }
00803         break;
00804     }
00805     case ScaleUserDefined:
00806         d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, d->lower, widget );
00807         break;
00808     }
00809     if ( rowController ) {
00810         // First draw the rows
00811         QPen pen = painter->pen();
00812         pen.setBrush( QApplication::palette().dark() );
00813         pen.setStyle( Qt::DashLine );
00814         painter->setPen( pen );
00815         QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
00816         if ( rowController->indexAbove( idx ).isValid() ) idx = rowController->indexAbove( idx );
00817         qreal y = 0;
00818         while ( y < exposedRect.bottom() && idx.isValid() ) {
00819             const Span s = rowController->rowGeometry( idx );
00820             y = s.start()+s.length();
00821             if ( d->rowSeparators ) {
00822                 painter->drawLine( QPointF( sceneRect.left(), y ),
00823                                    QPointF( sceneRect.right(), y ) );
00824             }
00825             if ( !idx.data( ItemTypeRole ).isValid() && d->noInformationBrush.style() != Qt::NoBrush ) {
00826                 painter->fillRect( QRectF( exposedRect.left(), s.start(), exposedRect.width(), s.length() ), d->noInformationBrush );
00827             }
00828             // Is alternating background better?
00829             //if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
00830             idx =  rowController->indexBelow( idx );
00831         }
00832     }
00833 }
00834 
00835 int DateTimeGrid::Private::tabHeight( const QString& txt, QWidget* widget ) const
00836 {
00837     QStyleOptionHeader opt;
00838     if ( widget ) opt.initFrom( widget );
00839     opt.text = txt;
00840     QStyle* style;
00841     if ( widget ) style = widget->style();
00842     else style = QApplication::style();
00843     QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
00844     return s.height();
00845 }
00846 
00847 void DateTimeGrid::Private::getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
00848 {
00849     const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
00850     const qreal dayw = dayWidth;
00851     if ( dayw > 24*60*60*tabw ) {
00852         *lower = &minute_lower;
00853         *upper = &minute_upper;
00854     } else if ( dayw > 24*60*tabw ) {
00855         *lower = &hour_lower;
00856         *upper = &hour_upper;
00857     } else if ( dayw > 24*tabw ) {
00858         *lower = &day_lower;
00859         *upper = &day_upper;
00860     } else if ( dayw > tabw ) {
00861         *lower = &week_lower;
00862         *upper = &week_upper;
00863     } else if ( 4*dayw > tabw ) {
00864         *lower = &month_lower;
00865         *upper = &month_upper;
00866     } else {
00867         *lower = &year_lower;
00868         *upper = &year_upper;
00869     }
00870 }
00871 
00872 
00873 void DateTimeGrid::paintHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00874                                 qreal offset, QWidget* widget )
00875 {
00876     painter->save();
00877     QPainterPath clipPath;
00878     clipPath.addRect( headerRect );
00879     painter->setClipPath( clipPath, Qt::IntersectClip );
00880     switch( scale() )
00881     {
00882     case ScaleHour:
00883         paintHourScaleHeader( painter, headerRect, exposedRect, offset, widget );
00884         break;
00885     case ScaleDay:
00886         paintDayScaleHeader( painter, headerRect, exposedRect, offset, widget );
00887         break;
00888     case ScaleWeek:
00889         paintWeekScaleHeader( painter, headerRect, exposedRect, offset, widget );
00890         break;
00891     case ScaleMonth:
00892         paintMonthScaleHeader( painter, headerRect, exposedRect, offset, widget );
00893         break;
00894     case ScaleAuto:
00895         {
00896             DateTimeScaleFormatter *lower, *upper;
00897             d->getAutomaticFormatters( &lower, &upper );
00898             const qreal lowerHeight = d->tabHeight( lower->text( startDateTime() ) );
00899             const qreal upperHeight = d->tabHeight( upper->text( startDateTime() ) );
00900             const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
00901 
00902             const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
00903             const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1,  headerRect.height()-upperHeaderRect.height()-1 );
00904 
00905             paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, lower, widget );
00906             paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, upper, widget );
00907             break;
00908         }
00909     case ScaleUserDefined:
00910         {
00911             const qreal lowerHeight = d->tabHeight( d->lower->text( startDateTime() ) );
00912             const qreal upperHeight = d->tabHeight( d->upper->text( startDateTime() ) );
00913             const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
00914 
00915             const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
00916             const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1,  headerRect.height()-upperHeaderRect.height()-1 );
00917 
00918             paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, d->lower, widget );
00919             paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, d->upper, widget );
00920         }
00921         break;
00922     }
00923     painter->restore();
00924 }
00925 
00926 void DateTimeGrid::paintUserDefinedHeader( QPainter* painter,
00927                                            const QRectF& headerRect, const QRectF& exposedRect,
00928                                            qreal offset, const DateTimeScaleFormatter* formatter,
00929                                            QWidget* widget )
00930 {
00931     const QStyle* const style = widget ? widget->style() : QApplication::style();
00932 
00933     QDateTime dt = formatter->currentRangeBegin( d->chartXtoDateTime( offset + exposedRect.left() ));
00934     qreal x = d->dateTimeToChartX( dt );
00935 
00936     while( x < exposedRect.right() + offset ) {
00937         const QDateTime next = formatter->nextRangeBegin( dt );
00938         const qreal nextx = d->dateTimeToChartX( next );
00939 
00940         QStyleOptionHeader opt;
00941         if ( widget ) opt.init( widget );
00942         opt.rect = QRectF( x - offset+1, headerRect.top(), qMax<qreal>( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
00943         opt.textAlignment = formatter->alignment();
00944         opt.text = formatter->text( dt );
00945         style->drawControl( QStyle::CE_Header, &opt, painter, widget );
00946 
00947         dt = next;
00948         x = nextx;
00949     }
00950 }
00951 
00952 void DateTimeGrid::Private::paintHeader( QPainter* painter,
00953                                          const QRectF& headerRect, const QRectF& exposedRect,
00954                                          qreal offset, QWidget* widget,
00955                                          Private::HeaderType headerType,
00956                                          DateTextFormatter *formatter )
00957 {
00958     QStyle* style = widget?widget->style():QApplication::style();
00959 
00960     const qreal left = exposedRect.left() + offset;
00961     const qreal right = exposedRect.right() + offset;
00962 
00963     // Paint a section for each hour
00964     QDateTime dt = chartXtoDateTime( left );
00965     dt = adjustDateTimeForHeader( dt, headerType );
00966     // Determine the time step per grid line
00967     int offsetSeconds = 0;
00968     int offsetDays = 0;
00969     int offsetMonths = 0;
00970 
00971     switch ( headerType ) {
00972         case Private::HeaderHour:
00973             offsetSeconds = 60*60;
00974             break;
00975         case Private::HeaderDay:
00976             offsetDays = 1;
00977             break;
00978         case Private::HeaderWeek:
00979             offsetDays = 7;
00980             break;
00981         case Private::HeaderMonth:
00982             offsetMonths = 1;
00983             break;
00984         case Private::HeaderYear:
00985             offsetMonths = 12;
00986             break;
00987         default:
00988             // Other scales cannot be painted with this method!
00989             assert( false );
00990             break;
00991     }
00992 
00993     for ( qreal x = dateTimeToChartX( dt ); x < right;
00994           dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), dt = dt.addMonths( offsetMonths ),
00995           x = dateTimeToChartX( dt ) ) {
00996         QStyleOptionHeader opt;
00997         if ( widget ) opt.init( widget );
00998         opt.rect = formatter->textRect( x, offset, dayWidth, headerRect, dt );
00999         opt.text = formatter->format( dt );
01000         opt.textAlignment = Qt::AlignCenter;
01001         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
01002     }
01003 }
01004 
01008 void DateTimeGrid::paintHourScaleHeader( QPainter* painter,
01009                                          const QRectF& headerRect, const QRectF& exposedRect,
01010                                          qreal offset, QWidget* widget )
01011 {
01012     class HourFormatter : public Private::DateTextFormatter {
01013     public:
01014         virtual ~HourFormatter() {}
01015 
01016         QString format( const QDateTime& dt ) {
01017             return dt.time().toString( QString::fromAscii( "hh" ) );
01018         }
01019         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01020             Q_UNUSED(dt);
01021 
01022             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
01023                            QSizeF( dayWidth / 24.0, headerRect.height() / 2.0 ) ).toAlignedRect();
01024         }
01025     };
01026     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01027                     Private::HeaderHour, new HourFormatter ); // Custom parameters
01028 
01029     class DayFormatter : public Private::DateTextFormatter {
01030     public:
01031         virtual ~DayFormatter() {}
01032         QString format( const QDateTime& dt ) {
01033             return dt.date().toString();
01034         }
01035         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01036             Q_UNUSED(dt);
01037 
01038             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01039                            QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toRect();
01040         }
01041     };
01042     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01043                     Private::HeaderDay, new DayFormatter ); // Custom parameters
01044 }
01045 
01049 void DateTimeGrid::paintDayScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01050                                 qreal offset, QWidget* widget )
01051 {
01052     class DayFormatter : public Private::DateTextFormatter {
01053     public:
01054         virtual ~DayFormatter() {}
01055 
01056         QString format( const QDateTime& dt ) {
01057             return dt.toString( QString::fromAscii( "ddd" ) ).left( 1 );
01058         }
01059         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01060             Q_UNUSED(dt);
01061 
01062             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
01063                            QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toAlignedRect();
01064         }
01065     };
01066     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01067                     Private::HeaderDay, new DayFormatter ); // Custom parameters
01068 
01069     class WeekFormatter : public Private::DateTextFormatter {
01070     public:
01071         virtual ~WeekFormatter() {}
01072         QString format( const QDateTime& dt ) {
01073             return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
01074         }
01075         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01076             Q_UNUSED(dt);
01077 
01078             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01079                            QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
01080         }
01081     };
01082     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01083                     Private::HeaderWeek, new WeekFormatter ); // Custom parameters
01084 }
01085 
01089 void DateTimeGrid::paintWeekScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01090                                         qreal offset, QWidget* widget )
01091 {
01092     class WeekFormatter : public Private::DateTextFormatter {
01093     public:
01094         virtual ~WeekFormatter() {}
01095 
01096         QString format( const QDateTime& dt ) {
01097             return QString::number( dt.date().weekNumber() );
01098         }
01099         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01100             Q_UNUSED(dt);
01101 
01102             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
01103                            QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
01104         }
01105     };
01106     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01107                     Private::HeaderWeek, new WeekFormatter ); // Custom parameters
01108 
01109     class MonthFormatter : public Private::DateTextFormatter {
01110     public:
01111         virtual ~MonthFormatter() {}
01112 
01113         QString format( const QDateTime& dt ) {
01114             return QLocale().monthName(dt.date().month(), QLocale::LongFormat) + QLatin1String("/") + QString::number(dt.date().year());
01115         }
01116         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01117             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01118                            QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
01119         }
01120     };
01121     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01122                     Private::HeaderMonth, new MonthFormatter ); // Custom parameters
01123 }
01124 
01128 void DateTimeGrid::paintMonthScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01129                                         qreal offset, QWidget* widget )
01130 {
01131     class MonthFormatter : public Private::DateTextFormatter {
01132     public:
01133         virtual ~MonthFormatter() {}
01134 
01135         QString format( const QDateTime& dt ) {
01136             return QLocale().monthName(dt.date().month(), QLocale::ShortFormat) + QLatin1String("/") + QString::number(dt.date().year());
01137         }
01138         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01139             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
01140                            QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
01141         }
01142     };
01143     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01144                     Private::HeaderMonth, new MonthFormatter ); // Custom parameters
01145 
01146     class YearFormatter : public Private::DateTextFormatter {
01147     public:
01148         virtual ~YearFormatter() {}
01149 
01150         QString format( const QDateTime& dt ) {
01151             return QString::number( dt.date().year() );
01152         }
01153         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01154             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01155                            QSizeF( dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0 ) ).toRect();
01156         }
01157     };
01158     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01159                     Private::HeaderYear, new YearFormatter ); // Custom parameters
01160 }
01161 
01165 void DateTimeGrid::drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date)
01166 {
01167     Q_UNUSED(painter);
01168     Q_UNUSED(rect);
01169     Q_UNUSED(date);
01170 }
01171 
01175 void DateTimeGrid::drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date)
01176 {
01177     Q_UNUSED(painter);
01178     Q_UNUSED(rect);
01179     Q_UNUSED(date);
01180 }
01181 
01185 QRectF DateTimeGrid::computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const
01186 {
01187     qreal topLeft = d->dateTimeToChartX(from);
01188     qreal topRight = d->dateTimeToChartX(to);
01189 
01190     return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
01191 }
01192 
01196 QPair<QDateTime, QDateTime> DateTimeGrid::dateTimeRange(const QRectF& rect) const
01197 {
01198     QDateTime start;
01199     QDateTime end;
01200 
01201     start = d->chartXtoDateTime(rect.left());
01202     end = d->chartXtoDateTime(rect.right());
01203 
01204     return qMakePair(start, end);
01205 }
01206 
01207 void DateTimeGrid::drawBackground(QPainter* paint, const QRectF& rect)
01208 {
01209     int offset = (int)dayWidth();
01210 
01211     // Figure out the date at the extreme left
01212     QDate date = d->chartXtoDateTime(rect.left()).date();
01213 
01214     // We need to paint from one end to the other
01215     int startx = rect.left();
01216     int endx = rect.right();
01217 
01218     // Save the painter state
01219     paint->save();
01220 
01221     // Paint the first date column
01222     while(1)
01223     {
01224         QDate nextDate = d->chartXtoDateTime(startx+1).date();
01225         if(date != nextDate)
01226         {
01227             QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
01228             dayRect = dayRect.adjusted(1, 0, 0, 0);
01229             drawDayBackground(paint, dayRect, date);
01230             break;
01231         }
01232 
01233         ++startx;
01234     }
01235 
01236     // Paint the remaining dates
01237     for(int i=startx; i<endx; i+=offset)
01238     {
01239         date = d->chartXtoDateTime(i+1).date();
01240 
01241         QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
01242         dayRect = dayRect.adjusted(1, 0, 0, 0);
01243         drawDayBackground(paint, dayRect, date);
01244     }
01245 
01246     // Restore the painter state
01247     paint->restore();
01248 }
01249 
01250 void DateTimeGrid::drawForeground(QPainter* paint, const QRectF& rect)
01251 {
01252     int offset = (int)dayWidth();
01253 
01254     // Figure out the date at the extreme left
01255     QDate date = d->chartXtoDateTime(rect.left()).date();
01256 
01257     // We need to paint from one end to the other
01258     int startx = rect.left();
01259     int endx = rect.right();
01260 
01261     // Save the painter state
01262     paint->save();
01263 
01264     // Paint the first date column
01265     while(1)
01266     {
01267         QDate nextDate = d->chartXtoDateTime(startx+1).date();
01268         if(date != nextDate)
01269         {
01270             QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
01271             dayRect = dayRect.adjusted(1, 0, 0, 0);
01272             drawDayForeground(paint, dayRect, date);
01273             break;
01274         }
01275 
01276         ++startx;
01277     }
01278 
01279     // Paint the remaining dates
01280     for(int i=startx; i<endx; i+=offset)
01281     {
01282         date = d->chartXtoDateTime(i+1).date();
01283 
01284         QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
01285         dayRect = dayRect.adjusted(1, 0, 0, 0);
01286         drawDayForeground(paint, dayRect, date);
01287     }
01288 
01289     // Restore the painter state
01290     paint->restore();
01291 }
01292 
01293 #undef d
01294 
01295 #ifndef KDAB_NO_UNIT_TESTS
01296 
01297 #include <QStandardItemModel>
01298 #include "unittest/test.h"
01299 
01300 static std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
01301 {
01302 #ifdef QT_NO_STL
01303     os << dt.toString().toLatin1().constData();
01304 #else
01305     os << dt.toString().toStdString();
01306 #endif
01307     return os;
01308 }
01309 
01310 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, DateTimeGrid, "test" ) {
01311     QStandardItemModel model( 3, 2 );
01312     DateTimeGrid grid;
01313     QDateTime dt = QDateTime::currentDateTime();
01314     grid.setModel( &model );
01315     QDateTime startdt = dt.addDays( -10 );
01316     grid.setStartDateTime( startdt );
01317 
01318     model.setData( model.index( 0, 0 ), dt,               StartTimeRole );
01319     model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
01320 
01321     model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
01322     model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
01323 
01324     Span s = grid.mapToChart( model.index( 0, 0 ) );
01325     //qDebug() << "span="<<s;
01326 
01327     assertTrue( s.start()>0 );
01328     assertTrue( s.length()>0 );
01329 
01330     assertTrue( startdt == grid.mapToDateTime( grid.mapFromDateTime( startdt ) ) );
01331 
01332     grid.mapFromChart( s, model.index( 1, 0 ) );
01333 
01334     QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
01335     QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
01336     QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
01337     QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
01338 
01339     assertTrue( s1.isValid() );
01340     assertTrue( e1.isValid() );
01341     assertTrue( s2.isValid() );
01342     assertTrue( e2.isValid() );
01343 
01344     assertEqual( s1, s2 );
01345     assertEqual( e1, e2 );
01346 
01347     assertTrue( grid.isSatisfiedConstraint( Constraint( model.index( 0, 0 ), model.index( 2, 0 ) ) ) );
01348     assertFalse( grid.isSatisfiedConstraint( Constraint( model.index( 2, 0 ), model.index( 0, 0 ) ) ) );
01349 
01350     s = grid.mapToChart( model.index( 0, 0 ) );
01351     s.setEnd( s.end()+100000. );
01352     bool rc = grid.mapFromChart( s, model.index( 0, 0 ) );
01353     assertTrue( rc );
01354     assertEqual( s1, model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime() );
01355     Span newspan = grid.mapToChart( model.index( 0, 0 ) );
01356     assertEqual( newspan.start(), s.start() );
01357     assertEqual( newspan.length(), s.length() );
01358 
01359     {
01360         QDateTime startDateTime = QDateTime::currentDateTime();
01361         qreal dayWidth = 100;
01362         QDate currentDate = QDate::currentDate();
01363         QDateTime dt( QDate(currentDate.year(), 1, 1),  QTime( 0, 0, 0, 0 ) );
01364         assert( dt.isValid() );
01365         qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
01366         result += startDateTime.time().msecsTo(dt.time())/1000.;
01367         result *= dayWidth/( 24.*60.*60. );
01368 
01369         int days = static_cast<int>( result/dayWidth );
01370         qreal secs = result*( 24.*60.*60. )/dayWidth;
01371         QDateTime dt2 = startDateTime;
01372         QDateTime result2 = dt2.addDays( days ).addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) ).addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
01373 
01374         assertEqual( dt, result2 );
01375     }
01376 }
01377 
01378 #endif /* KDAB_NO_UNIT_TESTS */
01379 
01380 #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/