KD Chart 2  [rev.2.6]
kdganttdatetimegrid.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2019 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "kdganttdatetimegrid.h"
24 #include "kdganttdatetimegrid_p.h"
25 
27 
28 #include <QApplication>
29 #include <QDateTime>
30 #include <QPainter>
31 #include <QStyle>
32 #include <QStyleOptionHeader>
33 #include <QWidget>
34 #include <QString>
35 #include <QDebug>
36 #include <QList>
37 
38 #include <cassert>
39 
40 using namespace KDGantt;
41 
43 {
44  switch ( range ) {
45  case KDGantt::DateTimeScaleFormatter::Second: dbg << "KDGantt::DateTimeScaleFormatter::Second"; break;
46  case KDGantt::DateTimeScaleFormatter::Minute: dbg << "KDGantt::DateTimeScaleFormatter::Minute"; break;
47  case KDGantt::DateTimeScaleFormatter::Hour: dbg << "KDGantt::DateTimeScaleFormatter::Hour"; break;
48  case KDGantt::DateTimeScaleFormatter::Day: dbg << "KDGantt::DateTimeScaleFormatter::Day"; break;
49  case KDGantt::DateTimeScaleFormatter::Week: dbg << "KDGantt::DateTimeScaleFormatter::Week"; break;
50  case KDGantt::DateTimeScaleFormatter::Month: dbg << "KDGantt::DateTimeScaleFormatter::Month"; break;
51  case KDGantt::DateTimeScaleFormatter::Year: dbg << "KDGantt::DateTimeScaleFormatter::Year"; break;
52  }
53  return dbg;
54 }
55 
56 
64 qreal DateTimeGrid::Private::dateTimeToChartX( const QDateTime& dt ) const
65 {
66  assert( startDateTime.isValid() );
67  qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
68  result += startDateTime.time().msecsTo(dt.time())/1000.;
69  result *= dayWidth/( 24.*60.*60. );
70 
71  return result;
72 }
73 
74 QDateTime DateTimeGrid::Private::chartXtoDateTime( qreal x ) const
75 {
76  assert( startDateTime.isValid() );
77  int days = static_cast<int>( x/dayWidth );
78  qreal secs = x*( 24.*60.*60. )/dayWidth;
79  QDateTime dt = startDateTime;
80  QDateTime result = dt.addDays( days )
81  .addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) )
82  .addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
83  return result;
84 }
85 
86 #define d d_func()
87 
116  const QString& templ, Qt::Alignment alignment )
117  : _d( new Private( range, format, templ, alignment ) )
118 {
119 }
120 
122  : _d( new Private( range, format, QString::fromLatin1( "%1" ), alignment ) )
123 {
124 }
125 
127  : _d( new Private( other.range(), other.format(), other.d->templ, other.alignment() ) )
128 {
129 }
130 
132 {
133  delete _d;
134 }
135 
137 {
138  if ( this == &other )
139  return *this;
140 
141  delete _d;
142  _d = new Private( other.range(), other.format(), other.d->templ, other.alignment() );
143  return *this;
144 }
145 
149 {
150  return d->format;
151 }
152 
155 QString DateTimeScaleFormatter::format( const QDateTime& datetime ) const
156 {
157  QString result = d->format;
158  // additional feature: Weeknumber
159  const QString shortWeekNumber = QString::number( datetime.date().weekNumber()) + QLatin1String("/")
160  + QString::number( datetime.date().year());
161  const QString longWeekNumber = ( shortWeekNumber.length() == 1 ? QString::fromLatin1( "0" ) : QString() ) + shortWeekNumber;
162  result.replace( QString::fromLatin1( "ww" ), longWeekNumber );
163  result.replace( QString::fromLatin1( "w" ), shortWeekNumber );
164  result = datetime.toLocalTime().toString( result );
165  return result;
166 }
167 
168 QString DateTimeScaleFormatter::text( const QDateTime& datetime ) const
169 {
170  return d->templ.arg( format( datetime ) );
171 }
172 
176 {
177  return d->range;
178 }
179 
181 {
182  return d->alignment;
183 }
184 
188 QDateTime DateTimeScaleFormatter::nextRangeBegin( const QDateTime& datetime ) const
189 {
190  QDateTime result = datetime;
191  switch ( d->range )
192  {
193  case Second:
194  result = result.addSecs( 60 );
195  break;
196  case Minute:
197  // set it to the begin of the next minute
198  result.setTime( QTime( result.time().hour(), result.time().minute() ) );
199  result = result.addSecs( 60 );
200  break;
201  case Hour:
202  // set it to the begin of the next hour
203  result.setTime( QTime( result.time().hour(), 0 ) );
204  result = result.addSecs( 60 * 60 );
205  break;
206  case Day:
207  // set it to midnight the next day
208  result.setTime( QTime( 0, 0 ) );
209  result = result.addDays( 1 );
210  break;
211  case Week:
212  // set it to midnight
213  result.setTime( QTime( 0, 0 ) );
214  // iterate day-wise, until weekNumber changes
215  {
216  const int weekNumber = result.date().weekNumber();
217  while ( weekNumber == result.date().weekNumber() )
218  result = result.addDays( 1 );
219  }
220  break;
221  case Month:
222  // set it to midnight
223  result.setTime( QTime( 0, 0 ) );
224  // set it to the first of the next month
225  result.setDate( QDate( result.date().year(), result.date().month(), 1 ).addMonths( 1 ) );
226  break;
227  case Year:
228  // set it to midnight
229  result.setTime( QTime( 0, 0 ) );
230  // set it to the first of the next year
231  result.setDate( QDate( result.date().year(), 1, 1 ).addYears( 1 ) );
232  break;
233  }
234  //result = result.toLocalTime();
235  assert( result != datetime );
236  //qDebug() << "DateTimeScaleFormatter::nextRangeBegin("<<datetime<<")="<<d->range<<result;
237  return result;
238 }
239 
243 QDateTime DateTimeScaleFormatter::currentRangeBegin( const QDateTime& datetime ) const
244 {
245  QDateTime result = datetime;
246  switch ( d->range )
247  {
248  case Second:
249  break; // nothing
250  case Minute:
251  // set it to the begin of the current minute
252  result.setTime( QTime( result.time().hour(), result.time().minute() ) );
253  break;
254  case Hour:
255  // set it to the begin of the current hour
256  result.setTime( QTime( result.time().hour(), 0 ) );
257  break;
258  case Day:
259  // set it to midnight the current day
260  result.setTime( QTime( 0, 0 ) );
261  break;
262  case Week:
263  // set it to midnight
264  result.setTime( QTime( 0, 0 ) );
265  // iterate day-wise, as long weekNumber is the same
266  {
267  const int weekNumber = result.date().weekNumber();
268  while ( weekNumber == result.date().addDays( -1 ).weekNumber() )
269  result = result.addDays( -1 );
270  }
271  break;
272  case Month:
273  // set it to midnight
274  result.setTime( QTime( 0, 0 ) );
275  // set it to the first of the current month
276  result.setDate( QDate( result.date().year(), result.date().month(), 1 ) );
277  break;
278  case Year:
279  // set it to midnight
280  result.setTime( QTime( 0, 0 ) );
281  // set it to the first of the current year
282  result.setDate( QDate( result.date().year(), 1, 1 ) );
283  break;
284  }
285  return result;
286 }
287 
289 {
290 }
291 
293 {
294 }
295 
301 {
302  return d->startDateTime;
303 }
304 
310 void DateTimeGrid::setStartDateTime( const QDateTime& dt )
311 {
312  d->startDateTime = dt;
313  emit gridChanged();
314 }
315 
321 {
322  return d->dayWidth;
323 }
324 
327 qreal DateTimeGrid::mapFromDateTime( const QDateTime& dt) const
328 {
329  return d->dateTimeToChartX( dt );
330 }
331 
334 QDateTime DateTimeGrid::mapToDateTime( qreal x ) const
335 {
336  return d->chartXtoDateTime( x );
337 }
338 
344 {
345  assert( w>0 );
346  d->dayWidth = w;
347  emit gridChanged();
348 }
349 
365 {
366  d->scale = s;
367  emit gridChanged();
368 }
369 
377 {
378  return d->scale;
379 }
380 
389 {
390  delete d->lower;
391  d->lower = lower;
392  emit gridChanged();
393 }
394 
403 {
404  delete d->upper;
405  d->upper = upper;
406  emit gridChanged();
407 }
408 
412 {
413  return d->lower;
414 }
415 
419 {
420  return d->upper;
421 }
422 
428 void DateTimeGrid::setWeekStart( Qt::DayOfWeek ws )
429 {
430  d->weekStart = ws;
431  emit gridChanged();
432 }
433 
435 Qt::DayOfWeek DateTimeGrid::weekStart() const
436 {
437  return d->weekStart;
438 }
439 
446 void DateTimeGrid::setFreeDays( const QSet<Qt::DayOfWeek>& fd )
447 {
448  d->freeDays = fd;
449  emit gridChanged();
450 }
451 
453 QSet<Qt::DayOfWeek> DateTimeGrid::freeDays() const
454 {
455  return d->freeDays;
456 }
457 
460 void DateTimeGrid::setFreeDaysBrush(const QBrush brush)
461 {
462  d->freeDaysBrush = brush;
463 }
464 
469 {
470  return d->freeDaysBrush;
471 }
472 
475 {
476  return d->rowSeparators;
477 }
480 {
481  d->rowSeparators = enable;
482 }
483 
488 void DateTimeGrid::setNoInformationBrush( const QBrush& brush )
489 {
490  d->noInformationBrush = brush;
491  emit gridChanged();
492 }
493 
497 {
498  return d->noInformationBrush;
499 }
500 
505 qreal DateTimeGrid::mapToChart( const QVariant& value ) const
506 {
507  if ( ! value.canConvert( QVariant::DateTime ) ||
508  ( value.type() == QVariant::String && value.toString().isEmpty() ) )
509  {
510  return -1.0;
511  }
512  return d->dateTimeToChartX( value.toDateTime() );
513 }
514 
519 QVariant DateTimeGrid::mapFromChart( qreal x ) const
520 {
521  return d->chartXtoDateTime( x );
522 }
523 
527 Span DateTimeGrid::mapToChart( const QModelIndex& idx ) const
528 {
529  assert( model() );
530  if ( !idx.isValid() ) return Span();
531  assert( idx.model()==model() );
532  const QVariant sv = model()->data( idx, StartTimeRole );
533  const QVariant ev = model()->data( idx, EndTimeRole );
534  if ( sv.canConvert( QVariant::DateTime ) &&
535  ev.canConvert( QVariant::DateTime ) &&
536  !(sv.type() == QVariant::String && sv.toString().isEmpty()) &&
537  !(ev.type() == QVariant::String && ev.toString().isEmpty())
538  ) {
539  QDateTime st = sv.toDateTime();
540  QDateTime et = ev.toDateTime();
541  if ( et.isValid() && st.isValid() ) {
542  qreal sx = d->dateTimeToChartX( st );
543  qreal ex = d->dateTimeToChartX( et )-sx;
544  //qDebug() << "DateTimeGrid::mapToChart("<<st<<et<<") => "<< Span( sx, ex );
545  return Span( sx, ex);
546  }
547  }
548  // Special case for Events with only a start date
549  if ( sv.canConvert( QVariant::DateTime ) && !(sv.type() == QVariant::String && sv.toString().isEmpty()) ) {
550  QDateTime st = sv.toDateTime();
551  if ( st.isValid() ) {
552  qreal sx = d->dateTimeToChartX( st );
553  return Span( sx, 0 );
554  }
555  }
556  return Span();
557 }
558 
559 #if 0
560 static void debug_print_idx( const QModelIndex& idx )
561 {
562  if ( !idx.isValid() ) {
563  qDebug() << "[Invalid]";
564  return;
565  }
566  QDateTime st = idx.data( StartTimeRole ).toDateTime();
567  QDateTime et = idx.data( EndTimeRole ).toDateTime();
568  qDebug() << idx << "["<<st<<et<<"]";
569 }
570 #endif
571 
586 bool DateTimeGrid::mapFromChart( const Span& span, const QModelIndex& idx,
587  const QList<Constraint>& constraints ) const
588 {
589  assert( model() );
590  if ( !idx.isValid() ) return false;
591  assert( idx.model()==model() );
592 
593  QDateTime st = d->chartXtoDateTime(span.start());
594  QDateTime et = d->chartXtoDateTime(span.start()+span.length());
595  //qDebug() << "DateTimeGrid::mapFromChart("<<span<<") => "<< st << et;
596  Q_FOREACH( const Constraint& c, constraints ) {
597  if ( c.type() != Constraint::TypeHard || !isSatisfiedConstraint( c )) continue;
598  if ( c.startIndex() == idx ) {
599  QDateTime tmpst = model()->data( c.endIndex(), StartTimeRole ).toDateTime();
600  //qDebug() << tmpst << "<" << et <<"?";
601  if ( tmpst<et ) return false;
602  } else if ( c.endIndex() == idx ) {
603  QDateTime tmpet = model()->data( c.startIndex(), EndTimeRole ).toDateTime();
604  //qDebug() << tmpet << ">" << st <<"?";
605  if ( tmpet>st ) return false;
606  }
607  }
608 
609  return model()->setData( idx, qVariantFromValue(st), StartTimeRole )
610  && model()->setData( idx, qVariantFromValue(et), EndTimeRole );
611 }
612 
613 Qt::PenStyle DateTimeGrid::Private::gridLinePenStyle( QDateTime dt, Private::HeaderType headerType ) const
614 {
615  switch ( headerType ) {
616  case Private::HeaderHour:
617  // Midnight
618  if ( dt.time().hour() == 0 )
619  return Qt::SolidLine;
620  return Qt::DashLine;
621  case Private::HeaderDay:
622  // First day of the week
623  if ( dt.date().dayOfWeek() == weekStart )
624  return Qt::SolidLine;
625  return Qt::DashLine;
626  case Private::HeaderWeek:
627  // First day of the month
628  if ( dt.date().day() == 1 )
629  return Qt::SolidLine;
630  // First day of the week
631  if ( dt.date().dayOfWeek() == weekStart )
632  return Qt::DashLine;
633  return Qt::NoPen;
634  case Private::HeaderMonth:
635  // First day of the year
636  if ( dt.date().dayOfYear() == 1 )
637  return Qt::SolidLine;
638  // First day of the month
639  if ( dt.date().day() == 1 )
640  return Qt::DashLine;
641  return Qt::NoPen;
642  default:
643  // Nothing to do here
644  break;
645  }
646 
647  // Default
648  return Qt::NoPen;
649 }
650 
651 QDateTime DateTimeGrid::Private::adjustDateTimeForHeader( QDateTime dt, Private::HeaderType headerType ) const
652 {
653  // In any case, set time to 00:00:00:00
654  dt.setTime( QTime( 0, 0, 0, 0 ) );
655 
656  switch ( headerType ) {
657  case Private::HeaderWeek:
658  // Set day to beginning of the week
659  while ( dt.date().dayOfWeek() != weekStart )
660  dt = dt.addDays( -1 );
661  break;
662  case Private::HeaderMonth:
663  // Set day to beginning of the month
664  dt = dt.addDays( 1 - dt.date().day() );
665  break;
666  case Private::HeaderYear:
667  // Set day to first day of the year
668  dt = dt.addDays( 1 - dt.date().dayOfYear() );
669  break;
670  default:
671  // In any other case, we don't need to adjust the date time
672  break;
673  }
674 
675  return dt;
676 }
677 
678 void DateTimeGrid::Private::paintVerticalLines( QPainter* painter,
679  const QRectF& sceneRect,
680  const QRectF& exposedRect,
681  QWidget* widget,
682  Private::HeaderType headerType )
683 {
684  QDateTime dt = chartXtoDateTime( exposedRect.left() );
685  dt = adjustDateTimeForHeader( dt, headerType );
686 
687  int offsetSeconds = 0;
688  int offsetDays = 0;
689  // Determine the time step per grid line
690  if ( headerType == Private::HeaderHour )
691  offsetSeconds = 60*60;
692  else
693  offsetDays = 1;
694 
695  for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
696  dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), x = dateTimeToChartX( dt ) ) {
697  //TODO not the best solution as it might be one paint too much, but i don't know what
698  //causes the test to fail yet, i think it might be a rounding error
699  //if ( x >= exposedRect.left() ) {
700  QPen pen = painter->pen();
701  pen.setBrush( QApplication::palette().dark() );
702  pen.setStyle( gridLinePenStyle( dt, headerType ) );
703  painter->setPen( pen );
704  if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
705  if (freeDaysBrush.style() == Qt::NoBrush)
706  painter->setBrush( widget?widget->palette().midlight()
707  :QApplication::palette().midlight() );
708  else
709  painter->setBrush(freeDaysBrush);
710 
711  painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
712  }
713  painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
714  //}
715  }
716 }
717 
718 void DateTimeGrid::Private::paintVerticalUserDefinedLines( QPainter* painter,
719  const QRectF& sceneRect,
720  const QRectF& exposedRect,
721  const DateTimeScaleFormatter* formatter,
722  QWidget* widget )
723 {
724  Q_UNUSED( widget );
725  QDateTime dt = chartXtoDateTime( exposedRect.left() );
726  dt = formatter->currentRangeBegin( dt );
727  QPen pen = painter->pen();
728  pen.setBrush( QApplication::palette().dark() );
729  pen.setStyle( Qt::DashLine );
730  painter->setPen( pen );
731  for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
732  dt = formatter->nextRangeBegin( dt ),x=dateTimeToChartX( dt ) ) {
733  if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
734  QBrush oldBrush = painter->brush();
735  if (freeDaysBrush.style() == Qt::NoBrush)
736  painter->setBrush( widget?widget->palette().midlight()
737  :QApplication::palette().midlight() );
738  else
739  painter->setBrush(freeDaysBrush);
740 
741  painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
742  painter->setBrush( oldBrush );
743  }
744  //TODO not the best solution as it might be one paint too much, but i don't know what
745  //causes the test to fail yet, i think it might be a rounding error
746  //if ( x >= exposedRect.left() ) {
747  // FIXME: Also fill area between this and the next vertical line to indicate free days? (Johannes)
748  painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
749  //}
750  }
751 }
752 
753 DateTimeGrid::Private::HeaderType DateTimeGrid::Private::headerTypeForScale( DateTimeGrid::Scale scale )
754 {
755  switch ( scale ) {
756  case ScaleHour:
757  return Private::HeaderHour;
758  case ScaleDay:
759  return Private::HeaderDay;
760  case ScaleWeek:
761  return Private::HeaderWeek;
762  case ScaleMonth:
763  return Private::HeaderMonth;
764  default:
765  // There are no specific header types for any other scale!
766  assert( false );
767  break;
768  }
769  return Private::HeaderDay;
770 }
771 
772 void DateTimeGrid::paintGrid( QPainter* painter,
773  const QRectF& sceneRect,
774  const QRectF& exposedRect,
775  AbstractRowController* rowController,
776  QWidget* widget )
777 {
778  // TODO: Support hours and weeks
779  switch ( scale() ) {
780  case ScaleHour:
781  case ScaleDay:
782  case ScaleWeek:
783  case ScaleMonth:
784  d->paintVerticalLines( painter, sceneRect, exposedRect, widget, d->headerTypeForScale( scale() ) );
785  break;
786  case ScaleAuto: {
787  const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
788  const qreal dayw = dayWidth();
789  if ( dayw > 24*60*60*tabw ) {
790 
791  d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->minute_lower, widget );
792  } else if ( dayw > 24*60*tabw ) {
793  d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderHour );
794  } else if ( dayw > 24*tabw ) {
795  d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderDay );
796  } else if ( dayw > tabw ) {
797  d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->week_lower, widget );
798  } else if ( 4*dayw > tabw ) {
799  d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->month_lower, widget );
800  } else {
801  d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->year_lower, widget );
802  }
803  break;
804  }
805  case ScaleUserDefined:
806  d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, d->lower, widget );
807  break;
808  }
809  if ( rowController ) {
810  // First draw the rows
811  QPen pen = painter->pen();
812  pen.setBrush( QApplication::palette().dark() );
813  pen.setStyle( Qt::DashLine );
814  painter->setPen( pen );
815  QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
816  if ( rowController->indexAbove( idx ).isValid() ) idx = rowController->indexAbove( idx );
817  qreal y = 0;
818  while ( y < exposedRect.bottom() && idx.isValid() ) {
819  const Span s = rowController->rowGeometry( idx );
820  y = s.start()+s.length();
821  if ( d->rowSeparators ) {
822  painter->drawLine( QPointF( sceneRect.left(), y ),
823  QPointF( sceneRect.right(), y ) );
824  }
825  if ( !idx.data( ItemTypeRole ).isValid() && d->noInformationBrush.style() != Qt::NoBrush ) {
826  painter->fillRect( QRectF( exposedRect.left(), s.start(), exposedRect.width(), s.length() ), d->noInformationBrush );
827  }
828  // Is alternating background better?
829  //if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
830  idx = rowController->indexBelow( idx );
831  }
832  }
833 }
834 
835 int DateTimeGrid::Private::tabHeight( const QString& txt, QWidget* widget ) const
836 {
837  QStyleOptionHeader opt;
838  if ( widget ) opt.initFrom( widget );
839  opt.text = txt;
840  QStyle* style;
841  if ( widget ) style = widget->style();
842  else style = QApplication::style();
843  QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
844  return s.height();
845 }
846 
847 void DateTimeGrid::Private::getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
848 {
849  const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
850  const qreal dayw = dayWidth;
851  if ( dayw > 24*60*60*tabw ) {
852  *lower = &minute_lower;
853  *upper = &minute_upper;
854  } else if ( dayw > 24*60*tabw ) {
855  *lower = &hour_lower;
856  *upper = &hour_upper;
857  } else if ( dayw > 24*tabw ) {
858  *lower = &day_lower;
859  *upper = &day_upper;
860  } else if ( dayw > tabw ) {
861  *lower = &week_lower;
862  *upper = &week_upper;
863  } else if ( 4*dayw > tabw ) {
864  *lower = &month_lower;
865  *upper = &month_upper;
866  } else {
867  *lower = &year_lower;
868  *upper = &year_upper;
869  }
870 }
871 
872 
873 void DateTimeGrid::paintHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
874  qreal offset, QWidget* widget )
875 {
876  painter->save();
877  QPainterPath clipPath;
878  clipPath.addRect( headerRect );
879  painter->setClipPath( clipPath, Qt::IntersectClip );
880  switch ( scale() )
881  {
882  case ScaleHour:
883  paintHourScaleHeader( painter, headerRect, exposedRect, offset, widget );
884  break;
885  case ScaleDay:
886  paintDayScaleHeader( painter, headerRect, exposedRect, offset, widget );
887  break;
888  case ScaleWeek:
889  paintWeekScaleHeader( painter, headerRect, exposedRect, offset, widget );
890  break;
891  case ScaleMonth:
892  paintMonthScaleHeader( painter, headerRect, exposedRect, offset, widget );
893  break;
894  case ScaleAuto:
895  {
896  DateTimeScaleFormatter *lower, *upper;
897  d->getAutomaticFormatters( &lower, &upper );
898  const qreal lowerHeight = d->tabHeight( lower->text( startDateTime() ) );
899  const qreal upperHeight = d->tabHeight( upper->text( startDateTime() ) );
900  const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
901 
902  const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
903  const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1, headerRect.height()-upperHeaderRect.height()-1 );
904 
905  paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, lower, widget );
906  paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, upper, widget );
907  break;
908  }
909  case ScaleUserDefined:
910  {
911  const qreal lowerHeight = d->tabHeight( d->lower->text( startDateTime() ) );
912  const qreal upperHeight = d->tabHeight( d->upper->text( startDateTime() ) );
913  const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
914 
915  const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
916  const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1, headerRect.height()-upperHeaderRect.height()-1 );
917 
918  paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, d->lower, widget );
919  paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, d->upper, widget );
920  }
921  break;
922  }
923  painter->restore();
924 }
925 
926 void DateTimeGrid::paintUserDefinedHeader( QPainter* painter,
927  const QRectF& headerRect, const QRectF& exposedRect,
928  qreal offset, const DateTimeScaleFormatter* formatter,
929  QWidget* widget )
930 {
931  const QStyle* const style = widget ? widget->style() : QApplication::style();
932 
933  QDateTime dt = formatter->currentRangeBegin( d->chartXtoDateTime( offset + exposedRect.left() ));
934  qreal x = d->dateTimeToChartX( dt );
935 
936  while ( x < exposedRect.right() + offset ) {
937  const QDateTime next = formatter->nextRangeBegin( dt );
938  const qreal nextx = d->dateTimeToChartX( next );
939 
940  QStyleOptionHeader opt;
941  if ( widget ) opt.init( widget );
942  opt.rect = QRectF( x - offset+1, headerRect.top(), qMax<qreal>( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
943  opt.textAlignment = formatter->alignment();
944  opt.text = formatter->text( dt );
945  style->drawControl( QStyle::CE_Header, &opt, painter, widget );
946 
947  dt = next;
948  x = nextx;
949  }
950 }
951 
952 void DateTimeGrid::Private::paintHeader( QPainter* painter,
953  const QRectF& headerRect, const QRectF& exposedRect,
954  qreal offset, QWidget* widget,
955  Private::HeaderType headerType,
956  DateTextFormatter *formatter )
957 {
958  QStyle* style = widget?widget->style():QApplication::style();
959 
960  const qreal left = exposedRect.left() + offset;
961  const qreal right = exposedRect.right() + offset;
962 
963  // Paint a section for each hour
964  QDateTime dt = chartXtoDateTime( left );
965  dt = adjustDateTimeForHeader( dt, headerType );
966  // Determine the time step per grid line
967  int offsetSeconds = 0;
968  int offsetDays = 0;
969  int offsetMonths = 0;
970 
971  switch ( headerType ) {
972  case Private::HeaderHour:
973  offsetSeconds = 60*60;
974  break;
975  case Private::HeaderDay:
976  offsetDays = 1;
977  break;
978  case Private::HeaderWeek:
979  offsetDays = 7;
980  break;
981  case Private::HeaderMonth:
982  offsetMonths = 1;
983  break;
984  case Private::HeaderYear:
985  offsetMonths = 12;
986  break;
987  default:
988  // Other scales cannot be painted with this method!
989  assert( false );
990  break;
991  }
992 
993  for ( qreal x = dateTimeToChartX( dt ); x < right;
994  dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), dt = dt.addMonths( offsetMonths ),
995  x = dateTimeToChartX( dt ) ) {
996  QStyleOptionHeader opt;
997  if ( widget ) opt.init( widget );
998  opt.rect = formatter->textRect( x, offset, dayWidth, headerRect, dt );
999  opt.text = formatter->format( dt );
1000  opt.textAlignment = Qt::AlignCenter;
1001  style->drawControl(QStyle::CE_Header, &opt, painter, widget);
1002  }
1003 }
1004 
1008 void DateTimeGrid::paintHourScaleHeader( QPainter* painter,
1009  const QRectF& headerRect, const QRectF& exposedRect,
1010  qreal offset, QWidget* widget )
1011 {
1012  class HourFormatter : public Private::DateTextFormatter {
1013  public:
1014  virtual ~HourFormatter() {}
1015 
1016  QString format( const QDateTime& dt ) {
1017  return dt.time().toString( QString::fromLatin1( "hh" ) );
1018  }
1019  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1020  Q_UNUSED(dt);
1021 
1022  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
1023  QSizeF( dayWidth / 24.0, headerRect.height() / 2.0 ) ).toAlignedRect();
1024  }
1025  };
1026  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1027  Private::HeaderHour, new HourFormatter ); // Custom parameters
1028 
1029  class DayFormatter : public Private::DateTextFormatter {
1030  public:
1031  virtual ~DayFormatter() {}
1032  QString format( const QDateTime& dt ) {
1033  return dt.date().toString();
1034  }
1035  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1036  Q_UNUSED(dt);
1037 
1038  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1039  QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toRect();
1040  }
1041  };
1042  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1043  Private::HeaderDay, new DayFormatter ); // Custom parameters
1044 }
1045 
1049 void DateTimeGrid::paintDayScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
1050  qreal offset, QWidget* widget )
1051 {
1052  class DayFormatter : public Private::DateTextFormatter {
1053  public:
1054  virtual ~DayFormatter() {}
1055 
1056  QString format( const QDateTime& dt ) {
1057  return dt.toString( QString::fromLatin1( "ddd" ) ).left( 1 );
1058  }
1059  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1060  Q_UNUSED(dt);
1061 
1062  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
1063  QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toAlignedRect();
1064  }
1065  };
1066  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1067  Private::HeaderDay, new DayFormatter ); // Custom parameters
1068 
1069  class WeekFormatter : public Private::DateTextFormatter {
1070  public:
1071  virtual ~WeekFormatter() {}
1072  QString format( const QDateTime& dt ) {
1073  return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
1074  }
1075  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1076  Q_UNUSED(dt);
1077 
1078  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1079  QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
1080  }
1081  };
1082  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1083  Private::HeaderWeek, new WeekFormatter ); // Custom parameters
1084 }
1085 
1089 void DateTimeGrid::paintWeekScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
1090  qreal offset, QWidget* widget )
1091 {
1092  class WeekFormatter : public Private::DateTextFormatter {
1093  public:
1094  virtual ~WeekFormatter() {}
1095 
1096  QString format( const QDateTime& dt ) {
1097  return QString::number( dt.date().weekNumber() );
1098  }
1099  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1100  Q_UNUSED(dt);
1101 
1102  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
1103  QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
1104  }
1105  };
1106  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1107  Private::HeaderWeek, new WeekFormatter ); // Custom parameters
1108 
1109  class MonthFormatter : public Private::DateTextFormatter {
1110  public:
1111  virtual ~MonthFormatter() {}
1112 
1113  QString format( const QDateTime& dt ) {
1114  return QLocale().monthName(dt.date().month(), QLocale::LongFormat) + QLatin1String("/") + QString::number(dt.date().year());
1115  }
1116  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1117  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1118  QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
1119  }
1120  };
1121  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1122  Private::HeaderMonth, new MonthFormatter ); // Custom parameters
1123 }
1124 
1128 void DateTimeGrid::paintMonthScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
1129  qreal offset, QWidget* widget )
1130 {
1131  class MonthFormatter : public Private::DateTextFormatter {
1132  public:
1133  virtual ~MonthFormatter() {}
1134 
1135  QString format( const QDateTime& dt ) {
1136  return QLocale().monthName(dt.date().month(), QLocale::ShortFormat) + QLatin1String("/") + QString::number(dt.date().year());
1137  }
1138  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1139  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
1140  QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
1141  }
1142  };
1143  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1144  Private::HeaderMonth, new MonthFormatter ); // Custom parameters
1145 
1146  class YearFormatter : public Private::DateTextFormatter {
1147  public:
1148  virtual ~YearFormatter() {}
1149 
1150  QString format( const QDateTime& dt ) {
1151  return QString::number( dt.date().year() );
1152  }
1153  QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) {
1154  return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1155  QSizeF( dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0 ) ).toRect();
1156  }
1157  };
1158  d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1159  Private::HeaderYear, new YearFormatter ); // Custom parameters
1160 }
1161 
1164 void DateTimeGrid::drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date)
1165 {
1166  Q_UNUSED(painter);
1167  Q_UNUSED(rect);
1168  Q_UNUSED(date);
1169 }
1170 
1173 void DateTimeGrid::drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date)
1174 {
1175  Q_UNUSED(painter);
1176  Q_UNUSED(rect);
1177  Q_UNUSED(date);
1178 }
1179 
1182 QRectF DateTimeGrid::computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const
1183 {
1184  qreal topLeft = d->dateTimeToChartX(from);
1185  qreal topRight = d->dateTimeToChartX(to);
1186 
1187  return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
1188 }
1189 
1193 {
1194  QDateTime start;
1195  QDateTime end;
1196 
1197  start = d->chartXtoDateTime(rect.left());
1198  end = d->chartXtoDateTime(rect.right());
1199 
1200  return qMakePair(start, end);
1201 }
1202 
1203 void DateTimeGrid::drawBackground(QPainter* paint, const QRectF& rect)
1204 {
1205  int offset = (int)dayWidth();
1206 
1207  // Figure out the date at the extreme left
1208  QDate date = d->chartXtoDateTime(rect.left()).date();
1209 
1210  // We need to paint from one end to the other
1211  int startx = rect.left();
1212  int endx = rect.right();
1213 
1214  // Save the painter state
1215  paint->save();
1216 
1217  // Paint the first date column
1218  while (1)
1219  {
1220  QDate nextDate = d->chartXtoDateTime(startx+1).date();
1221  if (date != nextDate)
1222  {
1223  QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
1224  dayRect = dayRect.adjusted(1, 0, 0, 0);
1225  drawDayBackground(paint, dayRect, date);
1226  break;
1227  }
1228 
1229  ++startx;
1230  }
1231 
1232  // Paint the remaining dates
1233  for (int i=startx; i<endx; i+=offset)
1234  {
1235  date = d->chartXtoDateTime(i+1).date();
1236 
1237  QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
1238  dayRect = dayRect.adjusted(1, 0, 0, 0);
1239  drawDayBackground(paint, dayRect, date);
1240  }
1241 
1242  // Restore the painter state
1243  paint->restore();
1244 }
1245 
1246 void DateTimeGrid::drawForeground(QPainter* paint, const QRectF& rect)
1247 {
1248  int offset = (int)dayWidth();
1249 
1250  // Figure out the date at the extreme left
1251  QDate date = d->chartXtoDateTime(rect.left()).date();
1252 
1253  // We need to paint from one end to the other
1254  int startx = rect.left();
1255  int endx = rect.right();
1256 
1257  // Save the painter state
1258  paint->save();
1259 
1260  // Paint the first date column
1261  while (1)
1262  {
1263  QDate nextDate = d->chartXtoDateTime(startx+1).date();
1264  if (date != nextDate)
1265  {
1266  QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
1267  dayRect = dayRect.adjusted(1, 0, 0, 0);
1268  drawDayForeground(paint, dayRect, date);
1269  break;
1270  }
1271 
1272  ++startx;
1273  }
1274 
1275  // Paint the remaining dates
1276  for (int i=startx; i<endx; i+=offset)
1277  {
1278  date = d->chartXtoDateTime(i+1).date();
1279 
1280  QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
1281  dayRect = dayRect.adjusted(1, 0, 0, 0);
1282  drawDayForeground(paint, dayRect, date);
1283  }
1284 
1285  // Restore the painter state
1286  paint->restore();
1287 }
1288 
1289 #undef d
1290 
1291 #ifndef KDAB_NO_UNIT_TESTS
1292 
1293 #include <QStandardItemModel>
1294 #include "unittest/test.h"
1295 
1296 static std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
1297 {
1298 #ifdef QT_NO_STL
1299  os << dt.toString().toLatin1().constData();
1300 #else
1301  os << dt.toString().toStdString();
1302 #endif
1303  return os;
1304 }
1305 
1307  QStandardItemModel model( 3, 2 );
1308  DateTimeGrid grid;
1309  QDateTime dt = QDateTime::currentDateTime();
1310  grid.setModel( &model );
1311  QDateTime startdt = dt.addDays( -10 );
1312  grid.setStartDateTime( startdt );
1313 
1314  model.setData( model.index( 0, 0 ), dt, StartTimeRole );
1315  model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
1316 
1317  model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
1318  model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
1319 
1320  Span s = grid.mapToChart( model.index( 0, 0 ) );
1321  //qDebug() << "span="<<s;
1322 
1323  assertTrue( s.start()>0 );
1324  assertTrue( s.length()>0 );
1325 
1326  assertTrue( startdt == grid.mapToDateTime( grid.mapFromDateTime( startdt ) ) );
1327 
1328  grid.mapFromChart( s, model.index( 1, 0 ) );
1329 
1330  QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
1331  QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
1332  QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
1333  QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
1334 
1335  assertTrue( s1.isValid() );
1336  assertTrue( e1.isValid() );
1337  assertTrue( s2.isValid() );
1338  assertTrue( e2.isValid() );
1339 
1340  assertEqual( s1, s2 );
1341  assertEqual( e1, e2 );
1342 
1343  assertTrue( grid.isSatisfiedConstraint( Constraint( model.index( 0, 0 ), model.index( 2, 0 ) ) ) );
1344  assertFalse( grid.isSatisfiedConstraint( Constraint( model.index( 2, 0 ), model.index( 0, 0 ) ) ) );
1345 
1346  s = grid.mapToChart( model.index( 0, 0 ) );
1347  s.setEnd( s.end()+100000. );
1348  bool rc = grid.mapFromChart( s, model.index( 0, 0 ) );
1349  assertTrue( rc );
1350  assertEqual( s1, model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime() );
1351  Span newspan = grid.mapToChart( model.index( 0, 0 ) );
1352  assertEqual( newspan.start(), s.start() );
1353  assertEqual( newspan.length(), s.length() );
1354 
1355  {
1356  QDateTime startDateTime = QDateTime::currentDateTime();
1357  qreal dayWidth = 100;
1358  QDate currentDate = QDate::currentDate();
1359  QDateTime dt( QDate(currentDate.year(), 1, 1), QTime( 0, 0, 0, 0 ) );
1360  assert( dt.isValid() );
1361  qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
1362  result += startDateTime.time().msecsTo(dt.time())/1000.;
1363  result *= dayWidth/( 24.*60.*60. );
1364 
1365  int days = static_cast<int>( result/dayWidth );
1366  qreal secs = result*( 24.*60.*60. )/dayWidth;
1367  QDateTime dt2 = startDateTime;
1368  QDateTime result2 = dt2.addDays( days ).addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) ).addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
1369 
1370  assertEqual( dt, result2 );
1371  }
1372 }
1373 
1374 #endif /* KDAB_NO_UNIT_TESTS */
1375 
1376 #include "moc_kdganttdatetimegrid.cpp"
void setNoInformationBrush(const QBrush &brush)
qreal start() const
DateTimeScaleFormatter * userDefinedUpperScale() const
KDAB_SCOPED_UNITTEST_SIMPLE(KDGantt, DateTimeGrid,"test")
virtual QDateTime currentRangeBegin(const QDateTime &datetime) const
QDateTime mapToDateTime(qreal x) const
DateTimeScaleFormatter & operator=(const DateTimeScaleFormatter &other)
void setUserDefinedLowerScale(DateTimeScaleFormatter *lower)
Abstract baseclass for grids. A grid is used to convert between QModelIndex&#39;es and gantt chart values...
virtual void paintUserDefinedHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, const DateTimeScaleFormatter *formatter, QWidget *widget=0)
virtual QModelIndex indexBelow(const QModelIndex &idx) const =0
qreal mapFromDateTime(const QDateTime &dt) const
Span mapToChart(const QModelIndex &idx) const
void setEnd(qreal end)
void paintHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=0)
A class used to represent a dependency.
virtual Span rowGeometry(const QModelIndex &idx) const =0
QPair< QDateTime, QDateTime > dateTimeRange(const QRectF &rect) const
Return a date-range represented by the rectangle.
QDebug operator<<(QDebug dbg, KDGantt::DateTimeScaleFormatter::Range range)
virtual void paintMonthScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=0)
QRectF computeRect(const QDateTime &from, const QDateTime &to, const QRectF &rect) const
Return the rectangle that represents the date-range.
bool mapFromChart(const Span &span, const QModelIndex &idx, const QList< Constraint > &constraints=QList< Constraint >()) const
virtual void paintWeekScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=0)
DateTimeScaleFormatter(Range range, const QString &formatString, Qt::Alignment alignment=Qt::AlignCenter)
void setUserDefinedUpperScale(DateTimeScaleFormatter *upper)
void drawForeground(QPainter *paint, const QRectF &rect)
virtual void drawDayBackground(QPainter *painter, const QRectF &rect, const QDate &date)
virtual QModelIndex indexAt(int height) const =0
A class representing a start point and a length.
#define d
virtual QModelIndex indexAbove(const QModelIndex &idx) const =0
bool isSatisfiedConstraint(const Constraint &c) const
virtual void setModel(QAbstractItemModel *model)
QAbstractItemModel * model() const
virtual QString text(const QDateTime &datetime) const
virtual void drawDayForeground(QPainter *painter, const QRectF &rect, const QDate &date)
void setWeekStart(Qt::DayOfWeek)
void setStartDateTime(const QDateTime &dt)
DateTimeScaleFormatter * userDefinedLowerScale() const
void setFreeDaysBrush(const QBrush brush)
void paintGrid(QPainter *painter, const QRectF &sceneRect, const QRectF &exposedRect, AbstractRowController *rowController=0, QWidget *widget=0)
virtual void paintDayScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=0)
void setFreeDays(const QSet< Qt::DayOfWeek > &fd)
qreal length() const
QModelIndex endIndex() const
void drawBackground(QPainter *paint, const QRectF &rect)
virtual void paintHourScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=0)
QDateTime startDateTime() const
QSet< Qt::DayOfWeek > freeDays() const
virtual QDateTime nextRangeBegin(const QDateTime &datetime) const
#define assertFalse(x)
Definition: test.h:42
Qt::DayOfWeek weekStart() const
Class only listed here to document inheritance of some KDChart classes.
Abstract baseclass for row controllers. A row controller is used by the GraphicsView to nagivate the ...
QModelIndex startIndex() const
void setRowSeparators(bool enable)
#define assertTrue(x)
Definition: test.h:41
#define assertEqual(x, y)
Definition: test.h:43
QBrush noInformationBrush() const

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