• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kdgantt

kdganttdatetimegrid.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB.  All rights reserved.
00003  **
00004  ** This file is part of the KD Gantt library.
00005  **
00006  ** This file may be used under the terms of the GNU General Public
00007  ** License versions 2.0 or 3.0 as published by the Free Software
00008  ** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
00009  ** included in the packaging of this file.  Alternatively you may (at
00010  ** your option) use any later version of the GNU General Public
00011  ** License if such license has been publicly approved by
00012  ** Klarälvdalens Datakonsult AB (or its successors, if any).
00013  ** 
00014  ** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
00015  ** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
00016  ** A PARTICULAR PURPOSE. Klarälvdalens Datakonsult AB reserves all rights
00017  ** not expressly granted herein.
00018  ** 
00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
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 <QDebug>
00035 
00036 #include <cassert>
00037 
00038 using namespace KDGantt;
00039 
00049 // TODO: I think maybe this class should be responsible
00050 // for unit-transformation of the scene...
00051 
00052 qreal DateTimeGrid::Private::dateTimeToChartX( const QDateTime& dt ) const
00053 {
00054     assert( startDateTime.isValid() );
00055     qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
00056     result += startDateTime.time().msecsTo(dt.time())/1000.;
00057     result *= dayWidth/( 24.*60.*60. );
00058 
00059     return result;
00060 }
00061 
00062 QDateTime DateTimeGrid::Private::chartXtoDateTime( qreal x ) const
00063 {
00064     assert( startDateTime.isValid() );
00065     int days = static_cast<int>( x/dayWidth );
00066     qreal secs = x*( 24.*60.*60. )/dayWidth;
00067     QDateTime dt = startDateTime;
00068     QDateTime result = dt.addDays( days )
00069                        .addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) )
00070                        .addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
00071     return result;
00072 }
00073 
00074 #define d d_func()
00075 
00076 DateTimeGrid::DateTimeGrid() : AbstractGrid( new Private )
00077 {
00078 }
00079 
00080 DateTimeGrid::~DateTimeGrid()
00081 {
00082 }
00083 
00088 QDateTime DateTimeGrid::startDateTime() const
00089 {
00090     return d->startDateTime;
00091 }
00092 
00098 void DateTimeGrid::setStartDateTime( const QDateTime& dt )
00099 {
00100     d->startDateTime = dt;
00101     emit gridChanged();
00102 }
00103 
00108 qreal DateTimeGrid::dayWidth() const
00109 {
00110     return d->dayWidth;
00111 }
00112 
00118 void DateTimeGrid::setDayWidth( qreal w )
00119 {
00120     qDebug()<<"DateTimeGrid::setDayWidth"<<w;
00121     d->dayWidth = qMax( w, qreal(1.0) );
00122     emit gridChanged();
00123 }
00124 
00130 void DateTimeGrid::setScale( Scale s )
00131 {
00132     d->scale = s;
00133     emit gridChanged();
00134 }
00135 
00142 DateTimeGrid::Scale DateTimeGrid::scale() const
00143 {
00144     return d->scale;
00145 }
00146 
00152 void DateTimeGrid::setWeekStart( Qt::DayOfWeek ws )
00153 {
00154     d->weekStart = ws;
00155     emit gridChanged();
00156 }
00157 
00159 Qt::DayOfWeek DateTimeGrid::weekStart() const
00160 {
00161     return d->weekStart;
00162 }
00163 
00170 void DateTimeGrid::setFreeDays( const QSet<Qt::DayOfWeek>& fd )
00171 {
00172     d->freeDays = fd;
00173     emit gridChanged();
00174 }
00175 
00177 bool DateTimeGrid::rowSeparators() const
00178 {
00179     return d->rowSeparators;
00180 }
00182 void DateTimeGrid::setRowSeparators( bool enable )
00183 {
00184     d->rowSeparators = enable;
00185 }
00186 
00188 QSet<Qt::DayOfWeek> DateTimeGrid::freeDays() const
00189 {
00190     return d->freeDays;
00191 }
00192 
00196 Span DateTimeGrid::mapToChart( const QModelIndex& idx ) const
00197 {
00198     assert( model() );
00199     if ( !idx.isValid() ) return Span();
00200     assert( idx.model()==model() );
00201     const QVariant sv = model()->data( idx, StartTimeRole );
00202     const QVariant ev = model()->data( idx, EndTimeRole );
00203     if( qVariantCanConvert<QDateTime>(sv) &&
00204     qVariantCanConvert<QDateTime>(ev) &&
00205     !(sv.type() == QVariant::String && qVariantValue<QString>(sv).isEmpty()) &&
00206     !(ev.type() == QVariant::String && qVariantValue<QString>(ev).isEmpty())
00207     ) {
00208       QDateTime st = sv.toDateTime();
00209       QDateTime et = ev.toDateTime();
00210       if ( et.isValid() && st.isValid() ) {
00211         qreal sx = d->dateTimeToChartX( st );
00212         qreal ex = d->dateTimeToChartX( et )-sx;
00213         //qDebug() << "DateTimeGrid::mapToChart("<<st<<et<<") => "<< Span( sx, ex );
00214         return Span( sx, ex);
00215       }
00216     }
00217     // Special case for Events with only a start date
00218     if( qVariantCanConvert<QDateTime>(sv) && !(sv.type() == QVariant::String && qVariantValue<QString>(sv).isEmpty()) ) {
00219       QDateTime st = sv.toDateTime();
00220       if ( st.isValid() ) {
00221         qreal sx = d->dateTimeToChartX( st );
00222         return Span( sx, 0 );
00223       }
00224     }
00225     return Span();
00226 }
00227 
00228 #if 0
00229 static void debug_print_idx( const QModelIndex& idx )
00230 {
00231     if ( !idx.isValid() ) {
00232         qDebug() << "[Invalid]";
00233         return;
00234     }
00235     QDateTime st = idx.data( StartTimeRole ).toDateTime();
00236     QDateTime et = idx.data( StartTimeRole ).toDateTime();
00237     qDebug() << idx << "["<<st<<et<<"]";
00238 }
00239 #endif
00240 
00255 bool DateTimeGrid::mapFromChart( const Span& span, const QModelIndex& idx,
00256     const QList<Constraint>& constraints ) const
00257 {
00258     assert( model() );
00259     if ( !idx.isValid() ) return false;
00260     assert( idx.model()==model() );
00261 
00262     QDateTime st = d->chartXtoDateTime(span.start());
00263     QDateTime et = d->chartXtoDateTime(span.start()+span.length());
00264     //qDebug() << "DateTimeGrid::mapFromChart("<<span<<") => "<< st << et;
00265     Q_FOREACH( const Constraint& c, constraints ) {
00266         if ( c.type() != Constraint::TypeHard || !isSatisfiedConstraint( c )) continue;
00267         if ( c.startIndex() == idx ) {
00268             QDateTime tmpst = model()->data( c.endIndex(), StartTimeRole ).toDateTime();
00269             //qDebug() << tmpst << "<" << et <<"?";
00270             if ( tmpst<et ) return false;
00271         } else if ( c.endIndex() == idx ) {
00272             QDateTime tmpet = model()->data( c.startIndex(), EndTimeRole ).toDateTime();
00273             //qDebug() << tmpet << ">" << st <<"?";
00274             if ( tmpet>st ) return false;
00275         }
00276     }
00277     return model()->setData( idx, qVariantFromValue(st), StartTimeRole )
00278         && model()->setData( idx, qVariantFromValue(et), EndTimeRole );
00279 }
00280 
00281 int DateTimeGrid::autoScale() const
00282 {
00283     int scale = ScaleDay;
00284     if ( dayWidth() > 450) {
00285         scale = ScaleHour;
00286     } else if (dayWidth() * 7 < 20) {
00287         scale = ScaleMonth;
00288     } else if (dayWidth() < 12) {
00289         scale = ScaleWeek;
00290     }
00291     return scale;
00292 }
00293 
00294 void DateTimeGrid::paintGrid( QPainter* painter,
00295                               const QRectF& sceneRect,
00296                               const QRectF& exposedRect,
00297                               AbstractRowController* rowController,
00298                               QWidget* widget )
00299 {
00300     //qDebug()<<"paintGrid()"<<scale()<<dayWidth();
00301     
00302     paintRowGrid(painter,sceneRect,exposedRect,rowController,widget);
00303     
00304     switch(scale()) {
00305         case ScaleHour:
00306             paintHourGrid(painter,sceneRect,exposedRect,rowController,widget);
00307             break;
00308         case ScaleDay:
00309             paintDayGrid(painter,sceneRect,exposedRect,rowController,widget);
00310             break;
00311         case ScaleWeek:
00312             paintWeekGrid(painter,sceneRect,exposedRect,rowController,widget);
00313             break;
00314         case ScaleMonth:
00315             paintMonthGrid(painter,sceneRect,exposedRect,rowController,widget);
00316             break;
00317         case ScaleAuto:
00318             switch(autoScale()) {
00319                 case ScaleHour:
00320                     paintHourGrid(painter,sceneRect,exposedRect,rowController,widget);
00321                     break;
00322                 case ScaleDay:
00323                     paintDayGrid(painter,sceneRect,exposedRect,rowController,widget);
00324                     break;
00325                 case ScaleWeek:
00326                     paintWeekGrid(painter,sceneRect,exposedRect,rowController,widget);
00327                     break;
00328                 case ScaleMonth:
00329                     paintMonthGrid(painter,sceneRect,exposedRect,rowController,widget);
00330                     break;
00331             }
00332             break;
00333     }
00334 }
00335 
00336 void DateTimeGrid::paintHourGrid( QPainter* painter,
00337                               const QRectF& sceneRect,
00338                               const QRectF& exposedRect,
00339                               AbstractRowController* rowController,
00340                               QWidget* widget )
00341 {
00342     //qDebug()<<"paintHourGrid()"<<scale()<<dayWidth();
00343     QDateTime dt = d->chartXtoDateTime( exposedRect.left() );
00344     dt.setTime( QTime( dt.time().hour(), 0, 0, 0 ) );
00345     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right(); dt = dt.addSecs( 60*60 ),x=d->dateTimeToChartX( dt ) ) {
00346         QPen pen = painter->pen();
00347         pen.setBrush( QApplication::palette().dark() );
00348         if ( dt.time() == QTime( 23, 0, 0 ) ) {
00349             pen.setStyle( Qt::SolidLine );
00350         } else {
00351             pen.setStyle( Qt::DashLine );
00352         }
00353         painter->setPen( pen );
00354         x += ( dayWidth() / 24.0 ) - 1;
00355         painter->drawLine( QPointF( x, exposedRect.top() ), QPointF( x, exposedRect.bottom() ) );
00356     }
00357 }
00358 
00359 void DateTimeGrid::paintDayGrid( QPainter* painter,
00360                                   const QRectF& sceneRect,
00361                                   const QRectF& exposedRect,
00362                                   AbstractRowController* rowController,
00363                                   QWidget* widget )
00364 {
00365     //qDebug()<<"paintDayGrid()"<<scale()<<dayWidth();
00366     QDateTime dt = d->chartXtoDateTime( exposedRect.left() );
00367     dt.setTime( QTime( 0, 0, 0, 0 ) );
00368     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right(); dt = dt.addDays( 1 ),x=d->dateTimeToChartX( dt ) ) {
00369         QPen pen = painter->pen();
00370         pen.setBrush( QApplication::palette().dark() );
00371         if ( dt.date().addDays( 1 ).dayOfWeek() == d->weekStart ) {
00372             pen.setStyle( Qt::SolidLine );
00373         } else {
00374             pen.setStyle( Qt::DashLine );
00375         }
00376         painter->setPen( pen );
00377         paintFreeDay( painter, x, exposedRect, dt.date(), widget );
00378         x += dayWidth() - 1;
00379         painter->drawLine( QPointF( x, exposedRect.top() ), QPointF( x, exposedRect.bottom() ) );
00380     }
00381 }
00382 
00383 void DateTimeGrid::paintWeekGrid( QPainter* painter,
00384                                   const QRectF& sceneRect,
00385                                   const QRectF& exposedRect,
00386                                   AbstractRowController* rowController,
00387                                   QWidget* widget )
00388 {
00389     //qDebug()<<"paintWeekGrid()"<<scale()<<dayWidth();
00390     QDateTime dt = d->chartXtoDateTime( exposedRect.left() );
00391     dt.setTime( QTime( 0, 0, 0, 0 ) );
00392     while ( dt.date().dayOfWeek() != d->weekStart ) dt = dt.addDays( -1 );
00393     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right(); dt = dt.addDays( 1 ),x=d->dateTimeToChartX( dt ) ) {
00394         QPen pen = painter->pen();
00395         pen.setBrush( QApplication::palette().dark() );
00396         if ( dt.date().addDays( 1 ).day() == 1 ) {
00397             pen.setStyle( Qt::SolidLine );
00398         } else if ( dt.date().addDays( 1 ).dayOfWeek() == d->weekStart ) {
00399             pen.setStyle( Qt::DashLine );
00400         } else {
00401             pen.setStyle( Qt::NoPen );
00402         }
00403         painter->setPen( pen );
00404         paintFreeDay( painter, x, exposedRect, dt.date(), widget );
00405         if ( pen.style() != Qt::NoPen ) {
00406             //qDebug()<<"paintWeekGrid()"<<dt;
00407             x += dayWidth() - 1;
00408             painter->drawLine( QPointF( x, exposedRect.top() ), QPointF( x, exposedRect.bottom() ) );
00409         }
00410     }
00411 }
00412 
00413 void DateTimeGrid::paintMonthGrid( QPainter* painter,
00414                                   const QRectF& sceneRect,
00415                                   const QRectF& exposedRect,
00416                                   AbstractRowController* rowController,
00417                                   QWidget* widget )
00418 {
00419     //qDebug()<<"paintMonthGrid()"<<scale()<<dayWidth();
00420     QDateTime dt = d->chartXtoDateTime( exposedRect.left() );
00421     dt.setTime( QTime( 0, 0, 0, 0 ) );
00422     dt = dt.addDays( 1 - dt.date().day() );
00423     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right(); dt = dt.addDays( 1 ),x=d->dateTimeToChartX( dt ) ) {
00424         QPen pen = painter->pen();
00425         pen.setBrush( QApplication::palette().dark() );
00426         if ( dt.date().addMonths( 1 ).month() == 1 && dt.date().addDays( 1 ).day() == 1 ) {
00427             pen.setStyle( Qt::SolidLine );
00428         } else if ( dt.date().addDays( 1 ).day() == 1 ) {
00429             pen.setStyle( Qt::DashLine );
00430         } else {
00431             pen.setStyle( Qt::NoPen );
00432         }
00433         painter->setPen( pen );
00434         paintFreeDay( painter, x, exposedRect, dt.date(), widget );
00435         if ( pen.style() != Qt::NoPen ) {
00436             //qDebug()<<"paintMonthGrid()"<<dt;
00437             x += dayWidth() - 1;
00438             painter->drawLine( QPointF( x, exposedRect.top() ), QPointF( x, exposedRect.bottom() ) );
00439         }
00440     }
00441 }
00442 
00443 void DateTimeGrid::paintFreeDay( QPainter* painter, qreal x, const QRectF& exposedRect, const QDate &dt, QWidget* widget )
00444 {
00445     if ( d->freeDays.contains( static_cast<Qt::DayOfWeek>( dt.dayOfWeek() ) ) ) {
00446         //FIXME We now use same color for alternating rows and free days
00447         painter->setBrush( widget ? widget->palette().alternateBase() : QApplication::palette().alternateBase() );
00448         painter->fillRect( QRectF( x, exposedRect.top(), dayWidth(), exposedRect.height() ), painter->brush() );
00449     }
00450 }
00451 
00452 void DateTimeGrid::paintRowGrid( QPainter* painter,
00453                                   const QRectF& sceneRect,
00454                                   const QRectF& exposedRect,
00455                                   AbstractRowController* rowController,
00456                                   QWidget* widget )
00457 {
00458     if ( rowController && rowSeparators() ) {
00459         // First draw the rows
00460         QPen pen = painter->pen();
00461         pen.setBrush( QApplication::palette().dark() );
00462         pen.setStyle( Qt::DashLine );
00463         painter->setPen( pen );
00464         QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
00465         qreal y = 0;
00466         while ( y < exposedRect.bottom() && idx.isValid() ) {
00467             const Span s = rowController->rowGeometry( idx );
00468             y = s.start()+s.length();
00469             //painter->drawLine( QPointF( sceneRect.left(), y ), QPointF( sceneRect.right(), y ) );
00470             // Is alternating background better?
00471             if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
00472             idx =  rowController->indexBelow( idx );
00473         }
00474     }
00475 }
00476 
00477 void DateTimeGrid::render( QPainter* painter,  const QRectF &target, const QRectF& headerRect, const QRectF& exposedRect, QWidget *widget, Qt::AspectRatioMode aspectRatioMode )
00478 {
00479     painter->save();
00480     
00481     qreal xratio = target.width() / exposedRect.width();
00482     qreal yratio = target.height() / exposedRect.height();
00483     //qDebug()<<"QGraphicsScene::render()"<<xratio<<yratio;
00484     // Scale according to the aspect ratio mode.
00485     switch (aspectRatioMode) {
00486         case Qt::KeepAspectRatio:
00487             xratio = yratio = qMin(xratio, yratio);
00488             break;
00489         case Qt::KeepAspectRatioByExpanding:
00490             xratio = yratio = qMax(xratio, yratio);
00491             break;
00492         case Qt::IgnoreAspectRatio:
00493             break;
00494     }
00495 
00496     //qDebug()<<"DateTimeGrid::render()"<<"target="<<target<<"exposedRect="<<exposedRect<<"xr="<<xratio<<"yr="<<yratio;
00497     
00498     painter->setClipRect( target );
00499     QTransform painterTransform;
00500     painterTransform *= QTransform()
00501             .translate(target.left(), target.top())
00502             .scale(xratio, yratio)
00503             .translate(-exposedRect.left(), -exposedRect.top());
00504     painter->setWorldTransform(painterTransform, true);
00505     
00506     paintHeader( painter, headerRect, exposedRect, 0.0, widget );
00507     painter->restore();
00508 }
00509 
00510 void DateTimeGrid::paintHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00511                                 qreal offset, QWidget* widget )
00512 {
00513     switch(scale()) {
00514         case ScaleHour: paintHourScaleHeader(painter,headerRect,exposedRect,offset,widget); break;
00515         case ScaleDay: paintDayScaleHeader(painter,headerRect,exposedRect,offset,widget); break;
00516         case ScaleWeek: paintWeekScaleHeader(painter,headerRect,exposedRect,offset,widget); break;
00517         case ScaleMonth: paintMonthScaleHeader(painter,headerRect,exposedRect,offset,widget); break;
00518         case ScaleAuto:
00519             switch(autoScale()) {
00520                 case ScaleHour:
00521                     paintHourScaleHeader(painter,headerRect,exposedRect,offset,widget);
00522                     break;
00523                 case ScaleDay:
00524                     paintDayScaleHeader(painter,headerRect,exposedRect,offset,widget);
00525                     break;
00526                 case ScaleWeek:
00527                     paintWeekScaleHeader(painter,headerRect,exposedRect,offset,widget);
00528                     break;
00529                 case ScaleMonth:
00530                     paintMonthScaleHeader(painter,headerRect,exposedRect,offset,widget);
00531                     break;
00532             }
00533             break;
00534     }
00535 }
00536 
00540 void DateTimeGrid::paintHourScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00541                                 qreal offset, QWidget* widget )
00542 {
00543     QStyle* style = widget?widget->style():QApplication::style();
00544 
00545     // Paint a section for each hour
00546     QDateTime dt = d->chartXtoDateTime( offset+exposedRect.left() );
00547     dt.setTime( QTime( dt.time().hour(), 0, 0, 0 ) );
00548     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right()+offset;
00549           dt = dt.addSecs( 60*60 /*1 hour*/ ),x=d->dateTimeToChartX( dt ) ) {
00550         QStyleOptionHeader opt;
00551         opt.init( widget );
00552         opt.rect = QRectF( x-offset, headerRect.top()+headerRect.height()/2., dayWidth()/24., headerRect.height()/2. ).toRect();
00553         opt.text = dt.time().toString( QString::fromAscii( "hh" ) );
00554         opt.textAlignment = Qt::AlignCenter;
00555         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00556     }
00557 
00558     dt = d->chartXtoDateTime( offset+exposedRect.left() );
00559     dt.setTime( QTime( 0, 0, 0, 0 ) );
00560     // Paint a section for each day
00561     for ( qreal x2 = d->dateTimeToChartX( dt ); x2 < exposedRect.right()+offset;
00562           dt = dt.addDays( 1 ),x2=d->dateTimeToChartX( dt ) ) {
00563         QStyleOptionHeader opt;
00564         opt.init( widget );
00565         opt.rect = QRectF( x2-offset, headerRect.top(), dayWidth(), headerRect.height()/2. ).toRect();
00566         opt.text = QDate::longDayName( dt.date().dayOfWeek() );
00567         opt.textAlignment = Qt::AlignCenter;
00568         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00569     }
00570 }
00571 
00575 void DateTimeGrid::paintDayScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00576                                 qreal offset, QWidget* widget )
00577 {
00578     // For starters, support only the regular tab-per-day look
00579     QStyle* style = widget?widget->style():QApplication::style();
00580 
00581     // Paint a section for each day
00582     QDateTime dt = d->chartXtoDateTime( offset+exposedRect.left() );
00583     dt.setTime( QTime( 0, 0, 0, 0 ) );
00584     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right()+offset;
00585           dt = dt.addDays( 1 ),x=d->dateTimeToChartX( dt ) ) {
00586         QStyleOptionHeader opt;
00587         opt.init( widget );
00588         opt.rect = QRectF( x-offset, headerRect.top()+headerRect.height()/2., dayWidth(), headerRect.height()/2. ).toRect();
00589         opt.text = dt.toString( QString::fromAscii( "ddd" ) ).left( 1 );
00590         opt.textAlignment = Qt::AlignCenter;
00591         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00592     }
00593 
00594     dt = d->chartXtoDateTime( offset+exposedRect.left() );
00595     dt.setTime( QTime( 0, 0, 0, 0 ) );
00596     // Go backwards until start of week
00597     while ( dt.date().dayOfWeek() != d->weekStart ) dt = dt.addDays( -1 );
00598     // Paint a section for each week
00599     for ( qreal x2 = d->dateTimeToChartX( dt ); x2 < exposedRect.right()+offset;
00600           dt = dt.addDays( 7 ),x2=d->dateTimeToChartX( dt ) ) {
00601         QStyleOptionHeader opt;
00602         opt.init( widget );
00603         opt.rect = QRectF( x2-offset, headerRect.top(), dayWidth()*7., headerRect.height()/2. ).toRect();
00604         opt.text = QString::number( dt.date().weekNumber() );
00605         opt.textAlignment = Qt::AlignCenter;
00606         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00607     }
00608 }
00609 
00613 void DateTimeGrid::paintWeekScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00614                                         qreal offset, QWidget* widget )
00615 {
00616     QStyle* style = widget?widget->style():QApplication::style();
00617 
00618     // Paint a section for each week
00619     QDateTime sdt = d->chartXtoDateTime( offset+exposedRect.left() );
00620     sdt.setTime( QTime( 0, 0, 0, 0 ) );
00621     // Go backwards until start of week
00622     while ( sdt.date().dayOfWeek() != d->weekStart ) sdt = sdt.addDays( -1 );
00623     QDateTime dt = sdt;
00624     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right()+offset;
00625             dt = dt.addDays( 7 ),x=d->dateTimeToChartX( dt ) ) {
00626         QStyleOptionHeader opt;
00627         opt.init( widget );
00628         opt.rect = QRectF( x-offset, headerRect.top()+headerRect.height()/2., dayWidth()*7, headerRect.height()/2. ).toRect();
00629         opt.text = QString::number( dt.date().weekNumber() );
00630         opt.textAlignment = Qt::AlignCenter;
00631         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00632     }
00633 
00634     // Paint a section for each month
00635     dt = sdt;
00636     for ( qreal x2 = d->dateTimeToChartX( dt ); x2 < exposedRect.right()+offset; x2=d->dateTimeToChartX( dt ) ) {
00637         //qDebug()<<"paintWeekScaleHeader()"<<dt;
00638         QDate next = dt.date().addMonths( 1 );
00639         next = next.addDays( 1 - next.day() );
00640 
00641         QStyleOptionHeader opt;
00642         opt.init( widget );
00643         opt.rect = QRectF( x2-offset, headerRect.top(), dayWidth()*dt.date().daysTo( next ), headerRect.height()/2. ).toRect();
00644         opt.text = QDate::longMonthName( dt.date().month() );
00645         opt.textAlignment = Qt::AlignCenter;
00646         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00647         
00648         dt.setDate( next );
00649     }
00650 }
00651 
00655 void DateTimeGrid::paintMonthScaleHeader( QPainter* painter,  const QRectF& headerRect, const QRectF& exposedRect,
00656                                         qreal offset, QWidget* widget )
00657 {
00658     QStyle* style = widget?widget->style():QApplication::style();
00659 
00660     // Paint a section for each month
00661     QDateTime sdt = d->chartXtoDateTime( offset+exposedRect.left() );
00662     sdt.setTime( QTime( 0, 0, 0, 0 ) );
00663     sdt = sdt.addDays( 1 - sdt.date().day() );
00664     QDateTime dt = sdt;
00665     for ( qreal x = d->dateTimeToChartX( dt ); x < exposedRect.right()+offset;
00666             dt = dt.addMonths( 1 ),x=d->dateTimeToChartX( dt ) ) {
00667         QStyleOptionHeader opt;
00668         opt.init( widget );
00669         opt.rect = QRectF( x-offset, headerRect.top()+headerRect.height()/2., dayWidth()*dt.date().daysInMonth(), headerRect.height()/2. ).toRect();
00670         opt.text = QDate::shortMonthName( dt.date().month() );
00671         opt.textAlignment = Qt::AlignCenter;
00672         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00673     }
00674 
00675     // Paint a section for each year
00676     dt = sdt;
00677     for ( qreal x2 = d->dateTimeToChartX( dt ); x2 < exposedRect.right()+offset; x2=d->dateTimeToChartX( dt ) ) {
00678         //qDebug()<<"paintMonthScaleHeader()"<<dt;
00679         QDate next = dt.date().addYears( 1 );
00680         next = next.addMonths( 1 - next.month() );
00681         
00682         QStyleOptionHeader opt;
00683         opt.init( widget );
00684         opt.rect = QRectF( x2-offset, headerRect.top(), dayWidth()*dt.date().daysTo( next ), headerRect.height()/2. ).toRect();
00685         opt.text = QString::number( dt.date().year() );
00686         opt.textAlignment = Qt::AlignCenter;
00687         style->drawControl(QStyle::CE_Header, &opt, painter, widget);
00688         
00689         dt.setDate( next );
00690     }
00691 }
00692 
00693 #undef d
00694 
00695 #ifndef KDAB_NO_UNIT_TESTS
00696 
00697 #include <QStandardItemModel>
00698 #include "unittest/test.h"
00699 
00700 namespace {
00701     std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
00702     {
00703         os << dt.toString().toStdString();
00704         return os;
00705     }
00706 }
00707 
00708 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, DateTimeGrid, "test" ) {
00709     QStandardItemModel model( 3, 2 );
00710     DateTimeGrid grid;
00711     QDateTime dt = QDateTime::currentDateTime();
00712     grid.setModel( &model );
00713     grid.setStartDateTime( dt.addDays( -10 ) );
00714 
00715     model.setData( model.index( 0, 0 ), dt,               StartTimeRole );
00716     model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
00717 
00718     model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
00719     model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
00720 
00721     Span s = grid.mapToChart( model.index( 0, 0 ) );
00722     //qDebug() << "span="<<s;
00723 
00724     assertTrue( s.start()>0 );
00725     assertTrue( s.length()>0 );
00726 
00727     grid.mapFromChart( s, model.index( 1, 0 ) );
00728 
00729     QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
00730     QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
00731     QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
00732     QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
00733 
00734     assertTrue( s1.isValid() );
00735     assertTrue( e1.isValid() );
00736     assertTrue( s2.isValid() );
00737     assertTrue( e2.isValid() );
00738 
00739     assertEqual( s1, s2 );
00740     assertEqual( e1, e2 );
00741 
00742     assertTrue( grid.