KD Chart API Documentation  3.1
kdganttdatetimegrid.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Chart library.
4 **
5 ** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
11 #include "kdganttdatetimegrid.h"
12 #include "kdganttdatetimegrid_p.h"
13 
15 
16 #include <QApplication>
17 #include <QDateTime>
18 #include <QDebug>
19 #include <QList>
20 #include <QPainter>
21 #include <QPainterPath>
22 #include <QString>
23 #include <QStyle>
24 #include <QStyleOptionHeader>
25 #include <QWidget>
26 
27 #include <cassert>
28 
29 using namespace KDGantt;
30 
32 {
33  switch (range) {
35  dbg << "KDGantt::DateTimeScaleFormatter::Second";
36  break;
38  dbg << "KDGantt::DateTimeScaleFormatter::Minute";
39  break;
41  dbg << "KDGantt::DateTimeScaleFormatter::Hour";
42  break;
44  dbg << "KDGantt::DateTimeScaleFormatter::Day";
45  break;
47  dbg << "KDGantt::DateTimeScaleFormatter::Week";
48  break;
50  dbg << "KDGantt::DateTimeScaleFormatter::Month";
51  break;
53  dbg << "KDGantt::DateTimeScaleFormatter::Year";
54  break;
55  }
56  return dbg;
57 }
58 
66 qreal DateTimeGrid::Private::dateTimeToChartX(const QDateTime &dt) const
67 {
68  assert(startDateTime.isValid());
69  qreal result = startDateTime.date().daysTo(dt.date()) * 24. * 60. * 60.;
70  result += startDateTime.time().msecsTo(dt.time()) / 1000.;
71  result *= dayWidth / (24. * 60. * 60.);
72 
73  return result;
74 }
75 
76 QDateTime DateTimeGrid::Private::chartXtoDateTime(qreal x) const
77 {
78  assert(startDateTime.isValid());
79  int days = static_cast<int>(x / dayWidth);
80  qreal secs = x * (24. * 60. * 60.) / dayWidth;
81  QDateTime dt = startDateTime;
82  QDateTime result = dt.addDays(days)
83  .addSecs(static_cast<int>(secs - (days * 24. * 60. * 60.)))
84  .addMSecs(qRound((secs - static_cast<int>(secs)) * 1000.));
85  return result;
86 }
87 
88 #define d d_func()
89 
118  const QString &templ, Qt::Alignment alignment)
119  : _d(new Private(range, format, templ, alignment))
120 {
121 }
122 
123 DateTimeScaleFormatter::DateTimeScaleFormatter(Range range, const QString &format, Qt::Alignment alignment)
124  : _d(new Private(range, format, QString::fromLatin1("%1"), alignment))
125 {
126 }
127 
129  : _d(new Private(other.range(), other.format(), other.d->templ, other.alignment()))
130 {
131 }
132 
134 {
135  delete _d;
136 }
137 
139 {
140  if (this == &other)
141  return *this;
142 
143  delete _d;
144  _d = new Private(other.range(), other.format(), other.d->templ, other.alignment());
145  return *this;
146 }
147 
151 {
152  return d->format;
153 }
154 
157 QString DateTimeScaleFormatter::format(const QDateTime &datetime) const
158 {
159  QString result = d->format;
160  // additional feature: Weeknumber
161  const QString shortWeekNumber = QString::number(datetime.date().weekNumber()) + QLatin1String("/")
162  + QString::number(datetime.date().year());
163  const QString longWeekNumber = (shortWeekNumber.length() == 1 ? QString::fromLatin1("0") : QString()) + shortWeekNumber;
164  result.replace(QString::fromLatin1("ww"), longWeekNumber);
165  result.replace(QString::fromLatin1("w"), shortWeekNumber);
166  result = datetime.toLocalTime().toString(result);
167  return result;
168 }
169 
170 QString DateTimeScaleFormatter::text(const QDateTime &datetime) const
171 {
172  return d->templ.arg(format(datetime));
173 }
174 
178 {
179  return d->range;
180 }
181 
183 {
184  return d->alignment;
185 }
186 
190 QDateTime DateTimeScaleFormatter::nextRangeBegin(const QDateTime &datetime) const
191 {
192  QDateTime result = datetime;
193  switch (d->range) {
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  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  : AbstractGrid(new Private)
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  Q_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  Q_EMIT gridChanged();
349 }
350 
366 {
367  d->scale = s;
368  Q_EMIT gridChanged();
369 }
370 
378 {
379  return d->scale;
380 }
381 
390 {
391  delete d->lower;
392  d->lower = lower;
393  Q_EMIT gridChanged();
394 }
395 
404 {
405  delete d->upper;
406  d->upper = upper;
407  Q_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  Q_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  Q_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  Q_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) || (value.type() == QVariant::String && value.toString().isEmpty())) {
509  return -1.0;
510  }
511  return d->dateTimeToChartX(value.toDateTime());
512 }
513 
518 QVariant DateTimeGrid::mapFromChart(qreal x) const
519 {
520  return d->chartXtoDateTime(x);
521 }
522 
526 Span DateTimeGrid::mapToChart(const QModelIndex &idx) const
527 {
528  assert(model());
529  if (!idx.isValid())
530  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) && ev.canConvert(QVariant::DateTime) && !(sv.type() == QVariant::String && sv.toString().isEmpty()) && !(ev.type() == QVariant::String && ev.toString().isEmpty())) {
535  QDateTime st = sv.toDateTime();
536  QDateTime et = ev.toDateTime();
537  if (et.isValid() && st.isValid()) {
538  qreal sx = d->dateTimeToChartX(st);
539  qreal ex = d->dateTimeToChartX(et) - sx;
540  // qDebug() << "DateTimeGrid::mapToChart("<<st<<et<<") => "<< Span( sx, ex );
541  return Span(sx, ex);
542  }
543  }
544  // Special case for Events with only a start date
545  if (sv.canConvert(QVariant::DateTime) && !(sv.type() == QVariant::String && sv.toString().isEmpty())) {
546  QDateTime st = sv.toDateTime();
547  if (st.isValid()) {
548  qreal sx = d->dateTimeToChartX(st);
549  return Span(sx, 0);
550  }
551  }
552  return Span();
553 }
554 
555 #if 0
556 static void debug_print_idx( const QModelIndex& idx )
557 {
558  if ( !idx.isValid() ) {
559  qDebug() << "[Invalid]";
560  return;
561  }
562  QDateTime st = idx.data( StartTimeRole ).toDateTime();
563  QDateTime et = idx.data( EndTimeRole ).toDateTime();
564  qDebug() << idx << "["<<st<<et<<"]";
565 }
566 #endif
567 
582 bool DateTimeGrid::mapFromChart(const Span &span, const QModelIndex &idx,
583  const QList<Constraint> &constraints) const
584 {
585  assert(model());
586  if (!idx.isValid())
587  return false;
588  assert(idx.model() == model());
589 
590  QDateTime st = d->chartXtoDateTime(span.start());
591  QDateTime et = d->chartXtoDateTime(span.start() + span.length());
592  // qDebug() << "DateTimeGrid::mapFromChart("<<span<<") => "<< st << et;
593  for (const Constraint &c : constraints) {
594  if (c.type() != Constraint::TypeHard || !isSatisfiedConstraint(c))
595  continue;
596  if (c.startIndex() == idx) {
597  QDateTime tmpst = model()->data(c.endIndex(), StartTimeRole).toDateTime();
598  // qDebug() << tmpst << "<" << et <<"?";
599  if (tmpst < et)
600  return false;
601  } else if (c.endIndex() == idx) {
602  QDateTime tmpet = model()->data(c.startIndex(), EndTimeRole).toDateTime();
603  // qDebug() << tmpet << ">" << st <<"?";
604  if (tmpet > st)
605  return false;
606  }
607  }
608 
609  return model()->setData(idx, QVariant::fromValue(st), StartTimeRole)
610  && model()->setData(idx, QVariant::fromValue(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().horizontalAdvance(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())
817  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)
840  opt.initFrom(widget);
841  opt.text = txt;
842  QStyle *style;
843  if (widget)
844  style = widget->style();
845  else
846  style = QApplication::style();
847  QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
848  return s.height();
849 }
850 
851 void DateTimeGrid::Private::getAutomaticFormatters(DateTimeScaleFormatter **lower, DateTimeScaleFormatter **upper)
852 {
853  const qreal tabw = QApplication::fontMetrics().horizontalAdvance(QLatin1String("XXXXX"));
854  const qreal dayw = dayWidth;
855  if (dayw > 24 * 60 * 60 * tabw) {
856  *lower = &minute_lower;
857  *upper = &minute_upper;
858  } else if (dayw > 24 * 60 * tabw) {
859  *lower = &hour_lower;
860  *upper = &hour_upper;
861  } else if (dayw > 24 * tabw) {
862  *lower = &day_lower;
863  *upper = &day_upper;
864  } else if (dayw > tabw) {
865  *lower = &week_lower;
866  *upper = &week_upper;
867  } else if (4 * dayw > tabw) {
868  *lower = &month_lower;
869  *upper = &month_upper;
870  } else {
871  *lower = &year_lower;
872  *upper = &year_upper;
873  }
874 }
875 
876 void DateTimeGrid::paintHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect,
877  qreal offset, QWidget *widget)
878 {
879  painter->save();
880  QPainterPath clipPath;
881  clipPath.addRect(headerRect);
882  painter->setClipPath(clipPath, Qt::IntersectClip);
883  switch (scale()) {
884  case ScaleHour:
885  paintHourScaleHeader(painter, headerRect, exposedRect, offset, widget);
886  break;
887  case ScaleDay:
888  paintDayScaleHeader(painter, headerRect, exposedRect, offset, widget);
889  break;
890  case ScaleWeek:
891  paintWeekScaleHeader(painter, headerRect, exposedRect, offset, widget);
892  break;
893  case ScaleMonth:
894  paintMonthScaleHeader(painter, headerRect, exposedRect, offset, widget);
895  break;
896  case ScaleAuto: {
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  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  } break;
921  }
922  painter->restore();
923 }
924 
926  const QRectF &headerRect, const QRectF &exposedRect,
927  qreal offset, const DateTimeScaleFormatter *formatter,
928  QWidget *widget)
929 {
930  const QStyle *const style = widget ? widget->style() : QApplication::style();
931 
932  QDateTime dt = formatter->currentRangeBegin(d->chartXtoDateTime(offset + exposedRect.left()));
933  qreal x = d->dateTimeToChartX(dt);
934 
935  while (x < exposedRect.right() + offset) {
936  const QDateTime next = formatter->nextRangeBegin(dt);
937  const qreal nextx = d->dateTimeToChartX(next);
938 
939  QStyleOptionHeader opt;
940  if (widget)
941  opt.initFrom(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)
998  opt.initFrom(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  {
1015  public:
1016  ~HourFormatter() override
1017  {
1018  }
1019 
1020  QString format(const QDateTime &dt) override
1021  {
1022  return dt.time().toString(QString::fromLatin1("hh"));
1023  }
1024  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1025  {
1026  Q_UNUSED(dt);
1027 
1028  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset + 1.0, headerRect.height() / 2.0),
1029  QSizeF(dayWidth / 24.0, headerRect.height() / 2.0))
1030  .toAlignedRect();
1031  }
1032  };
1033  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1034  Private::HeaderHour, new HourFormatter); // Custom parameters
1035 
1036  class DayFormatter : public Private::DateTextFormatter
1037  {
1038  public:
1039  ~DayFormatter() override
1040  {
1041  }
1042  QString format(const QDateTime &dt) override
1043  {
1044  return dt.date().toString();
1045  }
1046  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1047  {
1048  Q_UNUSED(dt);
1049 
1050  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset, 0.0),
1051  QSizeF(dayWidth, headerRect.height() / 2.0))
1052  .toRect();
1053  }
1054  };
1055  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1056  Private::HeaderDay, new DayFormatter); // Custom parameters
1057 }
1058 
1062 void DateTimeGrid::paintDayScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect,
1063  qreal offset, QWidget *widget)
1064 {
1065  class DayFormatter : public Private::DateTextFormatter
1066  {
1067  public:
1068  DayFormatter()
1069  : Private::DateTextFormatter()
1070  , m_formatter(DateTimeScaleFormatter::Range::Day, QString::fromLatin1("ddd"))
1071  {
1072  }
1073  ~DayFormatter() override
1074  {
1075  }
1076 
1077  QString format(const QDateTime &dt) override
1078  {
1079  return m_formatter.format(dt);
1080  }
1081  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1082  {
1083  Q_UNUSED(dt);
1084 
1085  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset + 1.0, headerRect.height() / 2.0),
1086  QSizeF(dayWidth, headerRect.height() / 2.0))
1087  .toAlignedRect();
1088  }
1089  DateTimeScaleFormatter m_formatter;
1090  };
1091  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1092  Private::HeaderDay, new DayFormatter); // Custom parameters
1093 
1094  class WeekFormatter : public Private::DateTextFormatter
1095  {
1096  public:
1097  ~WeekFormatter() override
1098  {
1099  }
1100  QString format(const QDateTime &dt) override
1101  {
1102  return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
1103  }
1104  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1105  {
1106  Q_UNUSED(dt);
1107 
1108  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset, 0.0),
1109  QSizeF(dayWidth * 7, headerRect.height() / 2.0))
1110  .toRect();
1111  }
1112  };
1113  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1114  Private::HeaderWeek, new WeekFormatter); // Custom parameters
1115 }
1116 
1120 void DateTimeGrid::paintWeekScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect,
1121  qreal offset, QWidget *widget)
1122 {
1123  class WeekFormatter : public Private::DateTextFormatter
1124  {
1125  public:
1126  ~WeekFormatter() override
1127  {
1128  }
1129 
1130  QString format(const QDateTime &dt) override
1131  {
1132  return QString::number(dt.date().weekNumber());
1133  }
1134  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1135  {
1136  Q_UNUSED(dt);
1137 
1138  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset, headerRect.height() / 2.0),
1139  QSizeF(dayWidth * 7, headerRect.height() / 2.0))
1140  .toRect();
1141  }
1142  };
1143  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1144  Private::HeaderWeek, new WeekFormatter); // Custom parameters
1145 
1146  class MonthFormatter : public Private::DateTextFormatter
1147  {
1148  public:
1149  ~MonthFormatter() override
1150  {
1151  }
1152 
1153  QString format(const QDateTime &dt) override
1154  {
1155  return QLocale().monthName(dt.date().month(), QLocale::LongFormat) + QLatin1String("/") + QString::number(dt.date().year());
1156  }
1157  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1158  {
1159  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset, 0.0),
1160  QSizeF(dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0))
1161  .toRect();
1162  }
1163  };
1164  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1165  Private::HeaderMonth, new MonthFormatter); // Custom parameters
1166 }
1167 
1171 void DateTimeGrid::paintMonthScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect,
1172  qreal offset, QWidget *widget)
1173 {
1174  class MonthFormatter : public Private::DateTextFormatter
1175  {
1176  public:
1177  ~MonthFormatter() override
1178  {
1179  }
1180 
1181  QString format(const QDateTime &dt) override
1182  {
1183  return QLocale().monthName(dt.date().month(), QLocale::ShortFormat) + QLatin1String("/") + QString::number(dt.date().year());
1184  }
1185  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1186  {
1187  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset, headerRect.height() / 2.0),
1188  QSizeF(dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0))
1189  .toRect();
1190  }
1191  };
1192  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1193  Private::HeaderMonth, new MonthFormatter); // Custom parameters
1194 
1195  class YearFormatter : public Private::DateTextFormatter
1196  {
1197  public:
1198  ~YearFormatter() override
1199  {
1200  }
1201 
1202  QString format(const QDateTime &dt) override
1203  {
1204  return QString::number(dt.date().year());
1205  }
1206  QRect textRect(qreal x, qreal offset, qreal dayWidth, const QRectF &headerRect, const QDateTime &dt) override
1207  {
1208  return QRectF(QPointF(x, headerRect.top()) + QPointF(-offset, 0.0),
1209  QSizeF(dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0))
1210  .toRect();
1211  }
1212  };
1213  d->paintHeader(painter, headerRect, exposedRect, offset, widget, // General parameters
1214  Private::HeaderYear, new YearFormatter); // Custom parameters
1215 }
1216 
1219 void DateTimeGrid::drawDayBackground(QPainter *painter, const QRectF &rect, const QDate &date)
1220 {
1221  Q_UNUSED(painter);
1222  Q_UNUSED(rect);
1223  Q_UNUSED(date);
1224 }
1225 
1228 void DateTimeGrid::drawDayForeground(QPainter *painter, const QRectF &rect, const QDate &date)
1229 {
1230  Q_UNUSED(painter);
1231  Q_UNUSED(rect);
1232  Q_UNUSED(date);
1233 }
1234 
1237 QRectF DateTimeGrid::computeRect(const QDateTime &from, const QDateTime &to, const QRectF &rect) const
1238 {
1239  qreal topLeft = d->dateTimeToChartX(from);
1240  qreal topRight = d->dateTimeToChartX(to);
1241 
1242  return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
1243 }
1244 
1247 QPair<QDateTime, QDateTime> DateTimeGrid::dateTimeRange(const QRectF &rect) const
1248 {
1249  QDateTime start;
1250  QDateTime end;
1251 
1252  start = d->chartXtoDateTime(rect.left());
1253  end = d->chartXtoDateTime(rect.right());
1254 
1255  return qMakePair(start, end);
1256 }
1257 
1258 void DateTimeGrid::drawBackground(QPainter *paint, const QRectF &rect)
1259 {
1260  int offset = ( int )dayWidth();
1261 
1262  // Figure out the date at the extreme left
1263  QDate date = d->chartXtoDateTime(rect.left()).date();
1264 
1265  // We need to paint from one end to the other
1266  int startx = rect.left();
1267  int endx = rect.right();
1268 
1269  // Save the painter state
1270  paint->save();
1271 
1272  // Paint the first date column
1273  while (1) {
1274  QDate nextDate = d->chartXtoDateTime(startx + 1).date();
1275  if (date != nextDate) {
1276  QRectF dayRect(startx - dayWidth(), rect.top(), dayWidth(), rect.height());
1277  dayRect = dayRect.adjusted(1, 0, 0, 0);
1278  drawDayBackground(paint, dayRect, date);
1279  break;
1280  }
1281 
1282  ++startx;
1283  }
1284 
1285  // Paint the remaining dates
1286  for (int i = startx; i < endx; i += offset) {
1287  date = d->chartXtoDateTime(i + 1).date();
1288 
1289  QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
1290  dayRect = dayRect.adjusted(1, 0, 0, 0);
1291  drawDayBackground(paint, dayRect, date);
1292  }
1293 
1294  // Restore the painter state
1295  paint->restore();
1296 }
1297 
1298 void DateTimeGrid::drawForeground(QPainter *paint, const QRectF &rect)
1299 {
1300  int offset = ( int )dayWidth();
1301 
1302  // Figure out the date at the extreme left
1303  QDate date = d->chartXtoDateTime(rect.left()).date();
1304 
1305  // We need to paint from one end to the other
1306  int startx = rect.left();
1307  int endx = rect.right();
1308 
1309  // Save the painter state
1310  paint->save();
1311 
1312  // Paint the first date column
1313  while (1) {
1314  QDate nextDate = d->chartXtoDateTime(startx + 1).date();
1315  if (date != nextDate) {
1316  QRectF dayRect(startx - dayWidth(), rect.top(), dayWidth(), rect.height());
1317  dayRect = dayRect.adjusted(1, 0, 0, 0);
1318  drawDayForeground(paint, dayRect, date);
1319  break;
1320  }
1321 
1322  ++startx;
1323  }
1324 
1325  // Paint the remaining dates
1326  for (int i = startx; i < endx; i += offset) {
1327  date = d->chartXtoDateTime(i + 1).date();
1328 
1329  QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
1330  dayRect = dayRect.adjusted(1, 0, 0, 0);
1331  drawDayForeground(paint, dayRect, date);
1332  }
1333 
1334  // Restore the painter state
1335  paint->restore();
1336 }
1337 
1338 #undef d
1339 
1340 #ifndef KDAB_NO_UNIT_TESTS
1341 
1342 #include "unittest/test.h"
1343 #include <QStandardItemModel>
1344 
1345 static std::ostream &operator<<(std::ostream &os, const QDateTime &dt)
1346 {
1347 #ifdef QT_NO_STL
1348  os << dt.toString().toLatin1().constData();
1349 #else
1350  os << dt.toString().toStdString();
1351 #endif
1352  return os;
1353 }
1354 
1356 {
1357  QStandardItemModel model(3, 2);
1358  DateTimeGrid grid;
1359  QDateTime dt = QDateTime::currentDateTime();
1360  grid.setModel(&model);
1361  QDateTime startdt = dt.addDays(-10);
1362  grid.setStartDateTime(startdt);
1363 
1364  model.setData(model.index(0, 0), dt, StartTimeRole);
1365  model.setData(model.index(0, 0), dt.addDays(17), EndTimeRole);
1366 
1367  model.setData(model.index(2, 0), dt.addDays(18), StartTimeRole);
1368  model.setData(model.index(2, 0), dt.addDays(19), EndTimeRole);
1369 
1370  Span s = grid.mapToChart(model.index(0, 0));
1371  // qDebug() << "span="<<s;
1372 
1373  assertTrue(s.start() > 0);
1374  assertTrue(s.length() > 0);
1375 
1376  assertTrue(startdt == grid.mapToDateTime(grid.mapFromDateTime(startdt)));
1377 
1378  grid.mapFromChart(s, model.index(1, 0));
1379 
1380  QDateTime s1 = model.data(model.index(0, 0), StartTimeRole).toDateTime();
1381  QDateTime e1 = model.data(model.index(0, 0), EndTimeRole).toDateTime();
1382  QDateTime s2 = model.data(model.index(1, 0), StartTimeRole).toDateTime();
1383  QDateTime e2 = model.data(model.index(1, 0), EndTimeRole).toDateTime();
1384 
1385  assertTrue(s1.isValid());
1386  assertTrue(e1.isValid());
1387  assertTrue(s2.isValid());
1388  assertTrue(e2.isValid());
1389 
1390  assertEqual(s1, s2);
1391  assertEqual(e1, e2);
1392 
1393  assertTrue(grid.isSatisfiedConstraint(Constraint(model.index(0, 0), model.index(2, 0))));
1394  assertFalse(grid.isSatisfiedConstraint(Constraint(model.index(2, 0), model.index(0, 0))));
1395 
1396  s = grid.mapToChart(model.index(0, 0));
1397  s.setEnd(s.end() + 100000.);
1398  bool rc = grid.mapFromChart(s, model.index(0, 0));
1399  assertTrue(rc);
1400  assertEqual(s1, model.data(model.index(0, 0), StartTimeRole).toDateTime());
1401  Span newspan = grid.mapToChart(model.index(0, 0));
1402  assertEqual(newspan.start(), s.start());
1403  assertEqual(newspan.length(), s.length());
1404 
1405  {
1406  QDateTime startDateTime = QDateTime::currentDateTime();
1407  qreal dayWidth = 100;
1408  QDate currentDate = QDate::currentDate();
1409  QDateTime dt(QDate(currentDate.year(), 1, 1), QTime(0, 0, 0, 0));
1410  assert(dt.isValid());
1411  qreal result = startDateTime.date().daysTo(dt.date()) * 24. * 60. * 60.;
1412  result += startDateTime.time().msecsTo(dt.time()) / 1000.;
1413  result *= dayWidth / (24. * 60. * 60.);
1414 
1415  int days = static_cast<int>(result / dayWidth);
1416  qreal secs = result * (24. * 60. * 60.) / dayWidth;
1417  QDateTime dt2 = startDateTime;
1418  QDateTime result2 = dt2.addDays(days).addSecs(static_cast<int>(secs - (days * 24. * 60. * 60.))).addMSecs(qRound((secs - static_cast<int>(secs)) * 1000.));
1419 
1420  assertEqual(dt, result2);
1421  }
1422 }
1423 
1424 #endif /* KDAB_NO_UNIT_TESTS */
1425 
1426 #include "moc_kdganttdatetimegrid.cpp"
Abstract baseclass for grids.
QAbstractItemModel * model() const
bool isSatisfiedConstraint(const Constraint &c) const
virtual void setModel(QAbstractItemModel *model)
Sets the QAbstractItemModel used by this grid implementation.
Abstract baseclass for row controllers.
virtual QModelIndex indexAbove(const QModelIndex &idx) const =0
virtual QModelIndex indexBelow(const QModelIndex &idx) const =0
virtual Span rowGeometry(const QModelIndex &idx) const =0
virtual QModelIndex indexAt(int height) const =0
A class used to represent a dependency.
This implementation of AbstractGrid works with QDateTime and shows days and week numbers in the heade...
virtual void paintHourScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
Paints the hour scale header.
virtual void drawDayForeground(QPainter *painter, const QRectF &rect, const QDate &date)
Draw the foreground for a day.
bool mapFromChart(const Span &span, const QModelIndex &idx, const QList< Constraint > &constraints=QList< Constraint >()) const override
Maps the supplied Span to QDateTimes, and puts them as start time and end time for the supplied index...
virtual void paintDayScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
Paints the day scale header.
void paintHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr) override
Implement this to paint the header part of the view.
DateTimeScaleFormatter * userDefinedUpperScale() const
QDateTime startDateTime() const
void setStartDateTime(const QDateTime &dt)
virtual void drawDayBackground(QPainter *painter, const QRectF &rect, const QDate &date)
Draw the background for a day.
void drawForeground(QPainter *paint, const QRectF &rect) override
void setRowSeparators(bool enable)
DateTimeScaleFormatter * userDefinedLowerScale() const
qreal mapFromDateTime(const QDateTime &dt) const
Maps a given point in time dt to an X value in the scene.
void setWeekStart(Qt::DayOfWeek)
Span mapToChart(const QModelIndex &idx) const override
QRectF computeRect(const QDateTime &from, const QDateTime &to, const QRectF &rect) const
void setNoInformationBrush(const QBrush &brush)
Sets the brush used to display rows where no data is found.
void drawBackground(QPainter *paint, const QRectF &rect) override
QPair< QDateTime, QDateTime > dateTimeRange(const QRectF &rect) const
QDateTime mapToDateTime(qreal x) const
Maps a given X value x in scene coordinates to a point in time.
virtual void paintWeekScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
Paints the week scale header.
Qt::DayOfWeek weekStart() const
void setUserDefinedLowerScale(DateTimeScaleFormatter *lower)
Sets the scale formatter for the lower part of the header to the user defined formatter to lower.
virtual void paintMonthScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
Paints the week scale header.
void paintGrid(QPainter *painter, const QRectF &sceneRect, const QRectF &exposedRect, AbstractRowController *rowController=nullptr, QWidget *widget=nullptr) override
Implement this to paint the background of the view – typically with some grid lines.
QSet< Qt::DayOfWeek > freeDays() const
virtual void paintUserDefinedHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, const DateTimeScaleFormatter *formatter, QWidget *widget=nullptr)
void setUserDefinedUpperScale(DateTimeScaleFormatter *upper)
Sets the scale formatter for the upper part of the header to the user defined formatter to upper.
void setFreeDaysBrush(const QBrush brush)
Sets the brush to use to paint free days.
void setFreeDays(const QSet< Qt::DayOfWeek > &fd)
This class formats dates and times used in DateTimeGrid follawing a given format.
virtual QDateTime nextRangeBegin(const QDateTime &datetime) const
virtual QString text(const QDateTime &datetime) const
virtual QDateTime currentRangeBegin(const QDateTime &datetime) const
DateTimeScaleFormatter(Range range, const QString &formatString, Qt::Alignment alignment=Qt::AlignCenter)
DateTimeScaleFormatter & operator=(const DateTimeScaleFormatter &other)
A class representing a start point and a length.
qreal length() const
qreal end() const
void setEnd(qreal end)
qreal start() const
KDAB_SCOPED_UNITTEST_SIMPLE(KDGantt, DateTimeGrid, "test")
#define d
QDebug operator<<(QDebug dbg, KDGantt::DateTimeScaleFormatter::Range range)

© 2001 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/
Generated by doxygen 1.9.1