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                   //TODO not the best solution as it might be one paint too much, but i don't know what
00689                   //causes the test to fail yet, i think it might be a rounding error
00690             //if ( x >= exposedRect.left() ) {
00691                 QPen pen = painter->pen();
00692                 pen.setBrush( QApplication::palette().dark() );
00693                 pen.setStyle( gridLinePenStyle( dt, headerType ) );
00694                 painter->setPen( pen );
00695                 if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
00696                     if(freeDaysBrush.style() == Qt::NoBrush)
00697                         painter->setBrush( widget?widget->palette().midlight()
00698                                            :QApplication::palette().midlight() );
00699                     else
00700                         painter->setBrush(freeDaysBrush);
00701 
00702                     painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
00703                 }
00704                 painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
00705             //}
00706         }
00707 }
00708 
00709 void DateTimeGrid::Private::paintVerticalUserDefinedLines( QPainter* painter,
00710                                                            const QRectF& sceneRect,
00711                                                            const QRectF& exposedRect,
00712                                                            const DateTimeScaleFormatter* formatter,
00713                                                            QWidget* widget )
00714 {
00715     Q_UNUSED( widget );
00716     QDateTime dt = chartXtoDateTime( exposedRect.left() );
00717     dt = formatter->currentRangeBegin( dt );
00718     QPen pen = painter->pen();
00719     pen.setBrush( QApplication::palette().dark() );
00720     pen.setStyle( Qt::DashLine );
00721     painter->setPen( pen );
00722     for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
00723         dt = formatter->nextRangeBegin( dt ),x=dateTimeToChartX( dt ) ) {
00724         if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
00725             QBrush oldBrush = painter->brush();
00726             if(freeDaysBrush.style() == Qt::NoBrush)
00727                 painter->setBrush( widget?widget->palette().midlight()
00728                                  :QApplication::palette().midlight() );
00729             else
00730                 painter->setBrush(freeDaysBrush);
00731 
00732           painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
00733           painter->setBrush( oldBrush );
00734         }
00735               //TODO not the best solution as it might be one paint too much, but i don't know what
00736               //causes the test to fail yet, i think it might be a rounding error
00737         //if ( x >= exposedRect.left() ) {
00738             // FIXME: Also fill area between this and the next vertical line to indicate free days? (Johannes)
00739     painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
00740         //}
00741     }
00742 }
00743 
00744 DateTimeGrid::Private::HeaderType DateTimeGrid::Private::headerTypeForScale( DateTimeGrid::Scale scale )
00745 {
00746     switch ( scale ) {
00747         case ScaleHour:
00748             return Private::HeaderHour;
00749         case ScaleDay:
00750             return Private::HeaderDay;
00751         case ScaleWeek:
00752             return Private::HeaderWeek;
00753         case ScaleMonth:
00754             return Private::HeaderMonth;
00755         default:
00756             // There are no specific header types for any other scale!
00757             assert( false );
00758             break;
00759     }
00760         return Private::HeaderDay;
00761 }
00762 
00763 void DateTimeGrid::paintGrid( QPainter* painter,
00764                               const QRectF& sceneRect,
00765                               const QRectF& exposedRect,
00766                               AbstractRowController* rowController,
00767                               QWidget* widget )
00768 {
00769     // TODO: Support hours and weeks
00770     switch( scale() ) {
00771     case ScaleHour:
00772     case ScaleDay:
00773     case ScaleWeek:
00774     case ScaleMonth:
00775         d->paintVerticalLines( painter, sceneRect, exposedRect, widget, d->headerTypeForScale( scale() ) );
00776         break;
00777     case ScaleAuto: {
00778         const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
00779         const qreal dayw = dayWidth();
00780         if ( dayw > 24*60*60*tabw ) {
00781 
00782             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->minute_lower, widget );
00783         } else if ( dayw > 24*60*tabw ) {
00784             d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderHour );
00785         } else if ( dayw > 24*tabw ) {
00786         d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderDay );
00787         } else if ( dayw > tabw ) {
00788             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->week_lower, widget );
00789         } else if ( 4*dayw > tabw ) {
00790             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->month_lower, widget );
00791         } else {
00792             d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->year_lower, widget );
00793         }
00794         break;
00795     }
00796     case ScaleUserDefined:
00797         d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, d->lower, widget );
00798         break;
00799     }
00800     if ( rowController ) {
00801         // First draw the rows
00802         QPen pen = painter->pen();
00803         pen.setBrush( QApplication::palette().dark() );
00804         pen.setStyle( Qt::DashLine );
00805         painter->setPen( pen );
00806         QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
00807         if ( rowController->indexAbove( idx ).isValid() ) idx = rowController->indexAbove( idx );
00808         qreal y = 0;
00809         while ( y < exposedRect.bottom() && idx.isValid() ) {
00810             const Span s = rowController->rowGeometry( idx );
00811             y = s.start()+s.length();
00812             if ( d->rowSeparators ) {
00813                 painter->drawLine( QPointF( sceneRect.left(), y ),
00814                                    QPointF( sceneRect.right(), y ) );
00815             }
00816             if ( !idx.data( ItemTypeRole ).isValid() && d->noInformationBrush.style() != Qt::NoBrush ) {
00817                 painter->fillRect( QRectF( exposedRect.left(), s.start(), exposedRect.width(), s.length() ), d->noInformationBrush );
00818             }
00819             // Is alternating background better?
00820             //if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
00821             idx =  rowController->indexBelow( idx );
00822         }
00823     }
00824 }
00825 
00826 int DateTimeGrid::Private::tabHeight( const QString& txt, QWidget* widget ) const
00827 {
00828     QStyleOptionHeader opt;
00829     if ( widget ) opt.initFrom( widget );
00830     opt.text = txt;
00831     QStyle* style;
00832     if ( widget ) style = widget->style();
00833     else style = QApplication::style();
00834     QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
00835     return s.height();
00836 }
00837 
00838 void DateTimeGrid::Private::getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
00839 {
00840     const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
00841     const qreal dayw = dayWidth;
00842     if ( dayw > 24*60*60*tabw ) {
00843         *lower = &minute_lower;
00844         *upper = &minute_upper;
00845     } else if ( dayw > 24*60*tabw ) {
00846         *lower = &hour_lower;
00847         *upper = &hour_upper;
00848     } else if ( dayw > 24*tabw ) {
00849         *lower = &day_lower;
00850         *upper = &day_upper;
00851     } else if ( dayw > tabw ) {
00852         *lower = &week_lower;
00853         *upper = &week_upper;
00854     } else if ( 4*dayw > tabw ) {
00855         *lower = &month_lower;
00856         *upper = &month_upper;
00857     } else {
00858         *lower = &year_lower;
00859         *upper = &year_upper;
00860     }
00861 }
00862 
00863 
00864 void DateTimeGrid::paintHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00865                                 qreal offset, QWidget* widget )
00866 {
00867     painter->save();
00868     QPainterPath clipPath;
00869     clipPath.addRect( headerRect );
00870     painter->setClipPath( clipPath, Qt::IntersectClip );
00871     switch( scale() )
00872     {
00873     case ScaleHour:
00874         paintHourScaleHeader( painter, headerRect, exposedRect, offset, widget );
00875         break;
00876     case ScaleDay:
00877         paintDayScaleHeader( painter, headerRect, exposedRect, offset, widget );
00878         break;
00879     case ScaleWeek:
00880         paintWeekScaleHeader( painter, headerRect, exposedRect, offset, widget );
00881         break;
00882     case ScaleMonth:
00883         paintMonthScaleHeader( painter, headerRect, exposedRect, offset, widget );
00884         break;
00885     case ScaleAuto:
00886         {
00887             DateTimeScaleFormatter *lower, *upper;
00888             d->getAutomaticFormatters( &lower, &upper );
00889             const qreal lowerHeight = d->tabHeight( lower->text( startDateTime() ) );
00890             const qreal upperHeight = d->tabHeight( upper->text( startDateTime() ) );
00891             const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
00892 
00893             const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
00894             const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1,  headerRect.height()-upperHeaderRect.height()-1 );
00895 
00896             paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, lower, widget );
00897             paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, upper, widget );
00898             break;
00899         }
00900     case ScaleUserDefined:
00901         {
00902             const qreal lowerHeight = d->tabHeight( d->lower->text( startDateTime() ) );
00903             const qreal upperHeight = d->tabHeight( d->upper->text( startDateTime() ) );
00904             const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
00905 
00906             const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
00907             const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1,  headerRect.height()-upperHeaderRect.height()-1 );
00908 
00909             paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, d->lower, widget );
00910             paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, d->upper, widget );
00911         }
00912         break;
00913     }
00914     painter->restore();
00915 }
00916 
00917 void DateTimeGrid::paintUserDefinedHeader( QPainter* painter,
00918                                            const QRectF& headerRect, const QRectF& exposedRect,
00919                                            qreal offset, const DateTimeScaleFormatter* formatter,
00920                                            QWidget* widget )
00921 {
00922     const QStyle* const style = widget ? widget->style() : QApplication::style();
00923 
00924     QDateTime dt = formatter->currentRangeBegin( d->chartXtoDateTime( offset + exposedRect.left() ));
00925     qreal x = d->dateTimeToChartX( dt );
00926 
00927     while( x < exposedRect.right() + offset ) {
00928         const QDateTime next = formatter->nextRangeBegin( dt );
00929         const qreal nextx = d->dateTimeToChartX( next );
00930 
00931         QStyleOptionHeader opt;
00932         if ( widget ) opt.init( widget );
00933         opt.rect = QRectF( x - offset+1, headerRect.top(), qMax<qreal>( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
00934         opt.textAlignment = formatter->alignment();
00935         opt.text = formatter->text( dt );
00936         style->drawControl( QStyle::CE_Header, &opt, painter, widget );
00937 
00938         dt = next;
00939         x = nextx;
00940     }
00941 }
00942 
00943 void DateTimeGrid::Private::paintHeader( QPainter* painter,
00944                                          const QRectF& headerRect, const QRectF& exposedRect,
00945                                          qreal offset, QWidget* widget,
00946                                          Private::HeaderType headerType,
00947                                          DateTextFormatter *formatter )
00948 {
00949     QStyle* style = widget?widget->style():QApplication::style();
00950 
00951     const qreal left = exposedRect.left() + offset;
00952     const qreal right = exposedRect.right() + offset;
00953 
00954     // Paint a section for each hour
00955     QDateTime dt = chartXtoDateTime( left );
00956     dt = adjustDateTimeForHeader( dt, headerType );
00957     // Determine the time step per grid line
00958     int offsetSeconds = 0;
00959     int offsetDays = 0;
00960     int offsetMonths = 0;
00961 
00962     switch ( headerType ) {
00963         case Private::HeaderHour:
00964             offsetSeconds = 60*60;
00965             break;
00966         case Private::HeaderDay:
00967             offsetDays = 1;
00968             break;
00969         case Private::HeaderWeek:
00970             offsetDays = 7;
00971             break;
00972         case Private::HeaderMonth:
00973             offsetMonths = 1;
00974             break;
00975         case Private::HeaderYear:
00976             offsetMonths = 12;
00977             break;
00978         default:
00979             // Other scales cannot be painted with this method!
00980             assert( false );
00981             break;
00982     }
00983 
00984     for ( qreal x = dateTimeToChartX( dt ); x < right;
00985           dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), dt = dt.addMonths( offsetMonths ),
00986           x = dateTimeToChartX( dt ) ) {
00987         QStyleOptionHeader opt;
00988         if ( widget ) opt.init( widget );
00989         opt.rect = formatter->textRect( x, offset, dayWidth, headerRect, dt );
00990         opt.text = formatter->format( dt );
00991         opt.textAlignment = Qt::AlignCenter;
00992         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00993     }
00994 }
00995 
00999 void DateTimeGrid::paintHourScaleHeader( QPainter* painter,
01000                                          const QRectF& headerRect, const QRectF& exposedRect,
01001                                          qreal offset, QWidget* widget )
01002 {
01003     class HourFormatter : public Private::DateTextFormatter {
01004     public:
01005         virtual ~HourFormatter() {}
01006 
01007         QString format( const QDateTime& dt ) {
01008             return dt.time().toString( QString::fromAscii( "hh" ) );
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 + 1.0, headerRect.height() / 2.0 ),
01014                            QSizeF( dayWidth / 24.0, headerRect.height() / 2.0 ) ).toAlignedRect();
01015         }
01016     };
01017     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01018                     Private::HeaderHour, new HourFormatter ); // Custom parameters
01019 
01020     class DayFormatter : public Private::DateTextFormatter {
01021     public:
01022         virtual ~DayFormatter() {}
01023         QString format( const QDateTime& dt ) {
01024             return dt.date().toString();
01025         }
01026         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01027             Q_UNUSED(dt);
01028 
01029             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01030                            QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toRect();
01031         }
01032     };
01033     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01034                     Private::HeaderDay, new DayFormatter ); // Custom parameters
01035 }
01036 
01040 void DateTimeGrid::paintDayScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01041                                 qreal offset, QWidget* widget )
01042 {
01043     class DayFormatter : public Private::DateTextFormatter {
01044     public:
01045         virtual ~DayFormatter() {}
01046 
01047         QString format( const QDateTime& dt ) {
01048             return dt.toString( QString::fromAscii( "ddd" ) ).left( 1 );
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 + 1.0, headerRect.height() / 2.0 ),
01054                            QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toAlignedRect();
01055         }
01056     };
01057     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01058                     Private::HeaderDay, new DayFormatter ); // Custom parameters
01059 
01060     class WeekFormatter : public Private::DateTextFormatter {
01061     public:
01062         virtual ~WeekFormatter() {}
01063         QString format( const QDateTime& dt ) {
01064             return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
01065         }
01066         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01067             Q_UNUSED(dt);
01068 
01069             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01070                            QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
01071         }
01072     };
01073     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01074                     Private::HeaderWeek, new WeekFormatter ); // Custom parameters
01075 }
01076 
01080 void DateTimeGrid::paintWeekScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01081                                         qreal offset, QWidget* widget )
01082 {
01083     class WeekFormatter : public Private::DateTextFormatter {
01084     public:
01085         virtual ~WeekFormatter() {}
01086 
01087         QString format( const QDateTime& dt ) {
01088             return QString::number( dt.date().weekNumber() );
01089         }
01090         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01091             Q_UNUSED(dt);
01092 
01093             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
01094                            QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
01095         }
01096     };
01097     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01098                     Private::HeaderWeek, new WeekFormatter ); // Custom parameters
01099 
01100     class MonthFormatter : public Private::DateTextFormatter {
01101     public:
01102         virtual ~MonthFormatter() {}
01103 
01104         QString format( const QDateTime& dt ) {
01105             return QLocale().monthName(dt.date().month(), QLocale::LongFormat) + QLatin1String("/") + QString::number(dt.date().year());
01106         }
01107         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01108             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01109                            QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
01110         }
01111     };
01112     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01113                     Private::HeaderMonth, new MonthFormatter ); // Custom parameters
01114 }
01115 
01119 void DateTimeGrid::paintMonthScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
01120                                         qreal offset, QWidget* widget )
01121 {
01122     class MonthFormatter : public Private::DateTextFormatter {
01123     public:
01124         virtual ~MonthFormatter() {}
01125 
01126         QString format( const QDateTime& dt ) {
01127             return QLocale().monthName(dt.date().month(), QLocale::ShortFormat) + QLatin1String("/") + QString::number(dt.date().year());
01128         }
01129         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01130             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
01131                            QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
01132         }
01133     };
01134     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01135                     Private::HeaderMonth, new MonthFormatter ); // Custom parameters
01136 
01137     class YearFormatter : public Private::DateTextFormatter {
01138     public:
01139         virtual ~YearFormatter() {}
01140 
01141         QString format( const QDateTime& dt ) {
01142             return QString::number( dt.date().year() );
01143         }
01144         QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
01145             return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
01146                            QSizeF( dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0 ) ).toRect();
01147         }
01148     };
01149     d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
01150                     Private::HeaderYear, new YearFormatter ); // Custom parameters
01151 }
01152 
01156 void DateTimeGrid::drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date)
01157 {
01158     Q_UNUSED(painter);
01159     Q_UNUSED(rect);
01160     Q_UNUSED(date);
01161 }
01162 
01166 void DateTimeGrid::drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date)
01167 {
01168     Q_UNUSED(painter);
01169     Q_UNUSED(rect);
01170     Q_UNUSED(date);
01171 }
01172 
01176 QRectF DateTimeGrid::computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const
01177 {
01178     qreal topLeft = d->dateTimeToChartX(from);
01179     qreal topRight = d->dateTimeToChartX(to);
01180 
01181     return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
01182 }
01183 
01187 QPair<QDateTime, QDateTime> DateTimeGrid::dateTimeRange(const QRectF& rect) const
01188 {
01189     QDateTime start;
01190     QDateTime end;
01191 
01192     start = d->chartXtoDateTime(rect.left());
01193     end = d->chartXtoDateTime(rect.right());
01194 
01195     return qMakePair(start, end);
01196 }
01197 
01198 void DateTimeGrid::drawBackground(QPainter* paint, const QRectF& rect)
01199 {
01200     int offset = (int)dayWidth();
01201 
01202     // Figure out the date at the extreme left
01203     QDate date = d->chartXtoDateTime(rect.left()).date();
01204 
01205     // We need to paint from one end to the other
01206     int startx = rect.left();
01207     int endx = rect.right();
01208 
01209     // Save the painter state
01210     paint->save();
01211 
01212     // Paint the first date column
01213     while(1)
01214     {
01215         QDate nextDate = d->chartXtoDateTime(startx+1).date();
01216         if(date != nextDate)
01217         {
01218             QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
01219             dayRect = dayRect.adjusted(1, 0, 0, 0);
01220             drawDayBackground(paint, dayRect, date);
01221             break;
01222         }
01223 
01224         ++startx;
01225     }
01226 
01227     // Paint the remaining dates
01228     for(int i=startx; i<endx; i+=offset)
01229     {
01230         date = d->chartXtoDateTime(i+1).date();
01231 
01232         QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
01233         dayRect = dayRect.adjusted(1, 0, 0, 0);
01234         drawDayBackground(paint, dayRect, date);
01235     }
01236 
01237     // Restore the painter state
01238     paint->restore();
01239 }
01240 
01241 void DateTimeGrid::drawForeground(QPainter* paint, const QRectF& rect)
01242 {
01243     int offset = (int)dayWidth();
01244 
01245     // Figure out the date at the extreme left
01246     QDate date = d->chartXtoDateTime(rect.left()).date();
01247 
01248     // We need to paint from one end to the other
01249     int startx = rect.left();
01250     int endx = rect.right();
01251 
01252     // Save the painter state
01253     paint->save();
01254 
01255     // Paint the first date column
01256     while(1)
01257     {
01258         QDate nextDate = d->chartXtoDateTime(startx+1).date();
01259         if(date != nextDate)
01260         {
01261             QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
01262             dayRect = dayRect.adjusted(1, 0, 0, 0);
01263             drawDayForeground(paint, dayRect, date);
01264             break;
01265         }
01266 
01267         ++startx;
01268     }
01269 
01270     // Paint the remaining dates
01271     for(int i=startx; i<endx; i+=offset)
01272     {
01273         date = d->chartXtoDateTime(i+1).date();
01274 
01275         QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
01276         dayRect = dayRect.adjusted(1, 0, 0, 0);
01277         drawDayForeground(paint, dayRect, date);
01278     }
01279 
01280     // Restore the painter state
01281     paint->restore();
01282 }
01283 
01284 #undef d
01285 
01286 #ifndef KDAB_NO_UNIT_TESTS
01287 
01288 #include <QStandardItemModel>
01289 #include "unittest/test.h"
01290 
01291 namespace {
01292     std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
01293     {
01294 #ifdef QT_NO_STL
01295         os << dt.toString().toLatin1().constData();
01296 #else
01297         os << dt.toString().toStdString();
01298 #endif
01299         return os;
01300     }
01301 }
01302 
01303 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, DateTimeGrid, "test" ) {
01304     QStandardItemModel model( 3, 2 );
01305     DateTimeGrid grid;
01306     QDateTime dt = QDateTime::currentDateTime();
01307     grid.setModel( &model );
01308     QDateTime startdt = dt.addDays( -10 );
01309     grid.setStartDateTime( startdt );
01310 
01311     model.setData( model.index( 0, 0 ), dt,               StartTimeRole );
01312     model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
01313 
01314     model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
01315     model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
01316 
01317     Span s = grid.mapToChart( model.index( 0, 0 ) );
01318     //qDebug() << "span="<<s;
01319 
01320     assertTrue( s.start()>0 );
01321     assertTrue( s.length()>0 );
01322 
01323     assertTrue( startdt == grid.mapToDateTime( grid.mapFromDateTime( startdt ) ) );
01324 
01325     grid.mapFromChart( s, model.index( 1, 0 ) );
01326 
01327     QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
01328     QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
01329     QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
01330     QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
01331 
01332     assertTrue( s1.isValid() );
01333     assertTrue( e1.isValid() );
01334     assertTrue( s2.isValid() );
01335     assertTrue( e2.isValid() );
01336 
01337     assertEqual( s1, s2 );
01338     assertEqual( e1, e2 );
01339 
01340     assertTrue( grid.isSatisfiedConstraint( Constraint( model.index( 0, 0 ), model.index( 2, 0 ) ) ) );
01341     assertFalse( grid.isSatisfiedConstraint( Constraint( model.index( 2, 0 ), model.index( 0, 0 ) ) ) );
01342 
01343     s = grid.mapToChart( model.index( 0, 0 ) );
01344     s.setEnd( s.end()+100000. );
01345     bool rc = grid.mapFromChart( s, model.index( 0, 0 ) );
01346     assertTrue( rc );
01347     assertEqual( s1, model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime() );
01348     Span newspan = grid.mapToChart( model.index( 0, 0 ) );
01349     assertEqual( newspan.start(), s.start() );
01350     assertEqual( newspan.length(), s.length() );
01351 
01352     {
01353         QDateTime startDateTime = QDateTime::currentDateTime();
01354         qreal dayWidth = 100;
01355         QDate currentDate = QDate::currentDate();
01356         QDateTime dt( QDate(currentDate.year(), 1, 1),  QTime( 0, 0, 0, 0 ) );
01357         assert( dt.isValid() );
01358         qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
01359         result += startDateTime.time().msecsTo(dt.time())/1000.;
01360         result *= dayWidth/( 24.*60.*60. );
01361 
01362         int days = static_cast<int>( result/dayWidth );
01363         qreal secs = result*( 24.*60.*60. )/dayWidth;
01364         QDateTime dt2 = startDateTime;
01365         QDateTime result2 = dt2.addDays( days ).addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) ).addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
01366 
01367         assertEqual( dt, result2 );
01368     }
01369 }
01370 
01371 #endif /* KDAB_NO_UNIT_TESTS */
01372 
01373 #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/