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

https://www.kdab.com/development-resources/qt-tools/kd-chart/