KD Chart 2
[rev.2.5]
|
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"