KGantt

kganttdatetimegrid.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KGantt library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kganttdatetimegrid.h"
10#include "kganttdatetimegrid_p.h"
11
12#include "kganttabstractrowcontroller.h"
13
14#include <QApplication>
15#include <QLocale>
16#include <QPainter>
17#include <QPainterPath>
18#include <QStyle>
19#include <QStyleOptionHeader>
20#include <QWidget>
21#include <QString>
22#include <QDebug>
23#include <QList>
24#include <QPainterPath>
25
26#include <cassert>
27
28using namespace KGantt;
29
30QDebug operator<<( QDebug dbg, KGantt::DateTimeScaleFormatter::Range range )
31{
32 switch ( range ) {
33 case KGantt::DateTimeScaleFormatter::Second: dbg << "KGantt::DateTimeScaleFormatter::Second"; break;
34 case KGantt::DateTimeScaleFormatter::Minute: dbg << "KGantt::DateTimeScaleFormatter::Minute"; break;
35 case KGantt::DateTimeScaleFormatter::Hour: dbg << "KGantt::DateTimeScaleFormatter::Hour"; break;
36 case KGantt::DateTimeScaleFormatter::Day: dbg << "KGantt::DateTimeScaleFormatter::Day"; break;
37 case KGantt::DateTimeScaleFormatter::Week: dbg << "KGantt::DateTimeScaleFormatter::Week"; break;
38 case KGantt::DateTimeScaleFormatter::Month: dbg << "KGantt::DateTimeScaleFormatter::Month"; break;
39 case KGantt::DateTimeScaleFormatter::Year: dbg << "KGantt::DateTimeScaleFormatter::Year"; break;
40 }
41 return dbg;
42}
43
44
45
46
47qreal DateTimeGrid::Private::dateTimeToChartX( const QDateTime& dt ) const
48{
49 assert( startDateTime.isValid() );
50 qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
51 result += startDateTime.time().msecsTo(dt.time())/1000.;
52 result *= dayWidth/( 24.*60.*60. );
53
54 return result;
55}
56
57QDateTime DateTimeGrid::Private::chartXtoDateTime( qreal x ) const
58{
59 assert( startDateTime.isValid() );
60 int days = static_cast<int>( x/dayWidth );
61 qreal secs = x*( 24.*60.*60. )/dayWidth;
63 QDateTime result = dt.addDays( days )
64 .addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) )
65 .addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
66 return result;
67}
68
69#define d d_func()
70
71
72
73
75 const QString& templ, Qt::Alignment alignment )
76 : _d( new Private( range, format, templ, alignment ) )
77{
78}
79
81 : _d( new Private( range, format, QString::fromLatin1( "%1" ), alignment ) )
82{
83}
84
86 : _d( new Private( other.range(), other.format(), other.d->templ, other.alignment() ) )
87{
88}
89
90DateTimeScaleFormatter::~DateTimeScaleFormatter()
91{
92 delete _d;
93}
94
95DateTimeScaleFormatter& DateTimeScaleFormatter::operator=( const DateTimeScaleFormatter& other )
96{
97 if ( this == &other )
98 return *this;
99
100 delete _d;
101 _d = new Private( other.range(), other.format(), other.d->templ, other.alignment() );
102 return *this;
103}
104
105
107{
108 return d->format;
109}
110
111
113{
114 QString result = d->format;
115 // additional feature: Weeknumber
116 const QString shortWeekNumber = QString::number( datetime.date().weekNumber()) + QLatin1String("/")
117 + QString::number( datetime.date().year());
118 const QString longWeekNumber = ( shortWeekNumber.length() == 1 ? QString::fromLatin1( "0" ) : QString() ) + shortWeekNumber;
119 result.replace( QString::fromLatin1( "ww" ), longWeekNumber );
120 result.replace( QString::fromLatin1( "w" ), shortWeekNumber );
121 result = QLocale().toString(datetime.toLocalTime(), result);
122 return result;
123}
124
125QString DateTimeScaleFormatter::text( const QDateTime& datetime ) const
126{
127 return d->templ.arg( format( datetime ) );
128}
129
130
131DateTimeScaleFormatter::Range DateTimeScaleFormatter::range() const
132{
133 return d->range;
134}
135
136Qt::Alignment DateTimeScaleFormatter::alignment() const
137{
138 return d->alignment;
139}
140
141
143{
144 QDateTime result = datetime;
145 switch ( d->range )
146 {
147 case Second:
148 result = result.addSecs( 60 );
149 break;
150 case Minute:
151 // set it to the begin of the next minute
152 result.setTime( QTime( result.time().hour(), result.time().minute() ) );
153 result = result.addSecs( 60 );
154 break;
155 case Hour:
156 // set it to the begin of the next hour
157 result.setTime( QTime( result.time().hour(), 0 ) );
158 result = result.addSecs( 60 * 60 );
159 break;
160 case Day:
161 // set it to midnight the next day
162 result.setTime( QTime( 0, 0 ) );
163 result = result.addDays( 1 );
164 break;
165 case Week:
166 // set it to midnight
167 result.setTime( QTime( 0, 0 ) );
168 // iterate day-wise, until weekNumber changes
169 {
170 const int weekNumber = result.date().weekNumber();
171 while ( weekNumber == result.date().weekNumber() )
172 result = result.addDays( 1 );
173 }
174 break;
175 case Month:
176 // set it to midnight
177 result.setTime( QTime( 0, 0 ) );
178 // set it to the first of the next month
179 result.setDate( QDate( result.date().year(), result.date().month(), 1 ).addMonths( 1 ) );
180 break;
181 case Year:
182 // set it to midnight
183 result.setTime( QTime( 0, 0 ) );
184 // set it to the first of the next year
185 result.setDate( QDate( result.date().year(), 1, 1 ).addYears( 1 ) );
186 break;
187 }
188 //result = result.toLocalTime();
189 assert( result != datetime );
190 //qDebug() << "DateTimeScaleFormatter::nextRangeBegin("<<datetime<<")="<<d->range<<result;
191 return result;
192}
193
194
196{
197 QDateTime result = datetime;
198 switch ( d->range )
199 {
200 case Second:
201 break; // nothing
202 case Minute:
203 // set it to the begin of the current minute
204 result.setTime( QTime( result.time().hour(), result.time().minute() ) );
205 break;
206 case Hour:
207 // set it to the begin of the current hour
208 result.setTime( QTime( result.time().hour(), 0 ) );
209 break;
210 case Day:
211 // set it to midnight the current day
212 result.setTime( QTime( 0, 0 ) );
213 break;
214 case Week:
215 // set it to midnight
216 result.setTime( QTime( 0, 0 ) );
217 // iterate day-wise, as long weekNumber is the same
218 {
219 const int weekNumber = result.date().weekNumber();
220 while ( weekNumber == result.date().addDays( -1 ).weekNumber() )
221 result = result.addDays( -1 );
222 }
223 break;
224 case Month:
225 // set it to midnight
226 result.setTime( QTime( 0, 0 ) );
227 // set it to the first of the current month
228 result.setDate( QDate( result.date().year(), result.date().month(), 1 ) );
229 break;
230 case Year:
231 // set it to midnight
232 result.setTime( QTime( 0, 0 ) );
233 // set it to the first of the current year
234 result.setDate( QDate( result.date().year(), 1, 1 ) );
235 break;
236 }
237 return result;
238}
239
240DateTimeGrid::DateTimeGrid() : AbstractGrid( new Private )
241{
242}
243
244DateTimeGrid::~DateTimeGrid()
245{
246}
247
248
250{
251 return d->startDateTime;
252}
253
254
256{
257 d->startDateTime = dt;
258 Q_EMIT gridChanged();
259}
260
261
263{
264 return d->dayWidth;
265}
266
267
269{
270 return d->dateTimeToChartX( dt );
271}
272
273
275{
276 return d->chartXtoDateTime( x );
277}
278
279
281{
282 assert( w>0 );
283 d->dayWidth = w;
284 Q_EMIT gridChanged();
285}
286
287
289{
290 d->scale = s;
291 Q_EMIT gridChanged();
292}
293
294
295DateTimeGrid::Scale DateTimeGrid::scale() const
296{
297 return d->scale;
298}
299
300
302{
303 delete d->lower;
304 d->lower = lower;
305 Q_EMIT gridChanged();
306}
307
308
310{
311 delete d->upper;
312 d->upper = upper;
313 Q_EMIT gridChanged();
314}
315
316
318{
319 return d->lower;
320}
321
322
324{
325 return d->upper;
326}
327
328
330{
331 d->weekStart = ws;
332 Q_EMIT gridChanged();
333}
334
335
337{
338 return d->weekStart;
339}
340
341
343{
344 d->freeDays = fd;
345 Q_EMIT gridChanged();
346}
347
348
350{
351 return d->freeDays;
352}
353
354
356{
357 d->freeDaysBrush = brush;
358}
359
360
362{
363 return d->freeDaysBrush;
364}
365
366
368{
369 return d->rowSeparators;
370}
371
373{
374 d->rowSeparators = enable;
375}
376
377
379{
380 d->noInformationBrush = brush;
381 Q_EMIT gridChanged();
382}
383
384
386{
387 return d->noInformationBrush;
388}
389
390
391qreal DateTimeGrid::mapToChart( const QVariant& value ) const
392{
393 if ( ! value.canConvert( QVariant::DateTime ) ||
394 ( value.type() == QVariant::String && value.toString().isEmpty() ) )
395 {
396 return -1.0;
397 }
398 return d->dateTimeToChartX( value.toDateTime() );
399}
400
401
403{
404 return d->chartXtoDateTime( x );
405}
406
407
409{
410 assert( model() );
411 if ( !idx.isValid() ) return Span();
412 assert( idx.model()==model() );
413 const QVariant sv = model()->data( idx, StartTimeRole );
414 const QVariant ev = model()->data( idx, EndTimeRole );
415 if ( sv.canConvert( QVariant::DateTime ) &&
417 !(sv.type() == QVariant::String && sv.toString().isEmpty()) &&
418 !(ev.type() == QVariant::String && ev.toString().isEmpty())
419 ) {
420 QDateTime st = sv.toDateTime();
421 QDateTime et = ev.toDateTime();
422 if ( et.isValid() && st.isValid() ) {
423 qreal sx = d->dateTimeToChartX( st );
424 qreal ex = d->dateTimeToChartX( et )-sx;
425 //qDebug() << "DateTimeGrid::mapToChart("<<st<<et<<") => "<< Span( sx, ex );
426 return Span( sx, ex);
427 }
428 }
429 // Special case for Events with only a start date
430 if ( sv.canConvert( QVariant::DateTime ) && !(sv.type() == QVariant::String && sv.toString().isEmpty()) ) {
431 QDateTime st = sv.toDateTime();
432 if ( st.isValid() ) {
433 qreal sx = d->dateTimeToChartX( st );
434 return Span( sx, 0 );
435 }
436 }
437 return Span();
438}
439
440#if 0
441static void debug_print_idx( const QModelIndex& idx )
442{
443 if ( !idx.isValid() ) {
444 qDebug() << "[Invalid]";
445 return;
446 }
448 QDateTime et = idx.data( EndTimeRole ).toDateTime();
449 qDebug() << idx << "["<<st<<et<<"]";
450}
451#endif
452
453
454bool DateTimeGrid::mapFromChart( const Span& span, const QModelIndex& idx,
455 const QList<Constraint>& constraints ) const
456{
457 assert( model() );
458 if ( !idx.isValid() ) return false;
459 assert( idx.model()==model() );
460
461 QDateTime st = d->chartXtoDateTime(span.start());
462 QDateTime et = d->chartXtoDateTime(span.start()+span.length());
463 //qDebug() << "DateTimeGrid::mapFromChart("<<span<<") => "<< st << et;
464 for ( const Constraint& c : constraints ) {
465 if ( c.type() != Constraint::TypeHard || !isSatisfiedConstraint( c )) continue;
466 if ( c.startIndex() == idx ) {
467 QDateTime tmpst = model()->data( c.endIndex(), StartTimeRole ).toDateTime();
468 //qDebug() << tmpst << "<" << et <<"?";
469 if ( tmpst<et ) return false;
470 } else if ( c.endIndex() == idx ) {
471 QDateTime tmpet = model()->data( c.startIndex(), EndTimeRole ).toDateTime();
472 //qDebug() << tmpet << ">" << st <<"?";
473 if ( tmpet>st ) return false;
474 }
475 }
476
477 return model()->setData( idx, QVariant::fromValue(st), StartTimeRole )
478 && model()->setData( idx, QVariant::fromValue(et), EndTimeRole );
479}
480
481Qt::PenStyle DateTimeGrid::Private::gridLinePenStyle( QDateTime dt, Private::HeaderType headerType ) const
482{
483 switch ( headerType ) {
484 case Private::HeaderHour:
485 // Midnight
486 if ( dt.time().hour() == 0 )
487 return Qt::SolidLine;
488 return Qt::DashLine;
489 case Private::HeaderDay:
490 // First day of the week
491 if ( dt.date().dayOfWeek() == weekStart )
492 return Qt::SolidLine;
493 return Qt::DashLine;
494 case Private::HeaderWeek:
495 // First day of the month
496 if ( dt.date().day() == 1 )
497 return Qt::SolidLine;
498 // First day of the week
499 if ( dt.date().dayOfWeek() == weekStart )
500 return Qt::DashLine;
501 return Qt::NoPen;
502 case Private::HeaderMonth:
503 // First day of the year
504 if ( dt.date().dayOfYear() == 1 )
505 return Qt::SolidLine;
506 // First day of the month
507 if ( dt.date().day() == 1 )
508 return Qt::DashLine;
509 return Qt::NoPen;
510 default:
511 // Nothing to do here
512 break;
513 }
514
515 // Default
516 return Qt::NoPen;
517}
518
519QDateTime DateTimeGrid::Private::adjustDateTimeForHeader( QDateTime dt, Private::HeaderType headerType ) const
520{
521 // In any case, set time to 00:00:00:00
522 dt.setTime( QTime( 0, 0, 0, 0 ) );
523
524 switch ( headerType ) {
525 case Private::HeaderWeek:
526 // Set day to beginning of the week
527 while ( dt.date().dayOfWeek() != weekStart )
528 dt = dt.addDays( -1 );
529 break;
530 case Private::HeaderMonth:
531 // Set day to beginning of the month
532 dt = dt.addDays( 1 - dt.date().day() );
533 break;
534 case Private::HeaderYear:
535 // Set day to first day of the year
536 dt = dt.addDays( 1 - dt.date().dayOfYear() );
537 break;
538 default:
539 // In any other case, we don't need to adjust the date time
540 break;
541 }
542
543 return dt;
544}
545
546void DateTimeGrid::Private::paintVerticalLines( QPainter* painter,
547 const QRectF& sceneRect,
548 const QRectF& exposedRect,
549 QWidget* widget,
550 Private::HeaderType headerType )
551{
552 QDateTime dt = chartXtoDateTime( exposedRect.left() );
553 dt = adjustDateTimeForHeader( dt, headerType );
554
555 int offsetSeconds = 0;
556 int offsetDays = 0;
557 // Determine the time step per grid line
558 if ( headerType == Private::HeaderHour )
559 offsetSeconds = 60*60;
560 else
561 offsetDays = 1;
562
563 for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
564 dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), x = dateTimeToChartX( dt ) ) {
565 //TODO not the best solution as it might be one paint too much, but i don't know what
566 //causes the test to fail yet, i think it might be a rounding error
567 //if ( x >= exposedRect.left() ) {
568 QPen pen = painter->pen();
569 pen.setBrush( QApplication::palette().dark() );
570 pen.setStyle( gridLinePenStyle( dt, headerType ) );
571 painter->setPen( pen );
572 if ( freeDays.contains( static_cast<Qt::DayOfWeek>( dt.date().dayOfWeek() ) ) ) {
573 if (freeDaysBrush.style() == Qt::NoBrush)
574 painter->setBrush( widget?widget->palette().midlight()
576 else
577 painter->setBrush(freeDaysBrush);
578
579 painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
580 }
581 painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
582 //}
583 }
584}
585
586void DateTimeGrid::Private::paintVerticalUserDefinedLines( QPainter* painter,
587 const QRectF& sceneRect,
588 const QRectF& exposedRect,
589 QWidget* widget )
590{
591 Q_UNUSED( widget );
592 DateTimeScaleFormatter *lowerFormatter, *upperFormatter;
593 switch ( scale ) {
594 case ScaleUserDefined:
595 lowerFormatter = lower;
596 upperFormatter = upper;
597 break;
598 default:
599 getAutomaticFormatters( &lowerFormatter, &upperFormatter );
600 break;
601 }
602 QPen pen = painter->pen();
603 pen.setBrush( QApplication::palette().dark() );
604
605 // Do freeDays, we need to iterate over all dates
606 QDateTime dtLeft = chartXtoDateTime( exposedRect.left() );
607 if ( ! freeDays.isEmpty() ) {
608 QDate lastDate = chartXtoDateTime( exposedRect.right() ).date();
609 for (QDateTime date(dtLeft.date(), QTime()); date.date() <= lastDate; date = date.addDays(1)) {
610 if ( freeDays.contains( static_cast<Qt::DayOfWeek>( date.date().dayOfWeek() ) ) ) {
611 if (freeDaysBrush.style() == Qt::NoBrush) {
612 painter->setBrush( widget?widget->palette().midlight():QApplication::palette().midlight() );
613 } else {
614 painter->setBrush(freeDaysBrush);
615 }
616 qreal x = dateTimeToChartX( date );
617 painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
618 }
619 }
620 }
621 QDateTime dt = upperFormatter->currentRangeBegin( dtLeft );
622 // Get all upper scale gridline x values to avoid mixing with lower scale gridlines
623 QList<qreal> upperXList;
624 for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right(); dt = upperFormatter->nextRangeBegin( dt ), x=dateTimeToChartX( dt ) ) {
625 upperXList.append(x);
626 }
627 dt = lowerFormatter->currentRangeBegin( dtLeft );
628 for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
629 dt = lowerFormatter->nextRangeBegin( dt ),x=dateTimeToChartX( dt ) )
630 {
631 if (!upperXList.contains(x)) {
632 pen.setStyle( Qt::DashLine );
633 painter->setPen( pen );
634 painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
635 }
636 }
637 dt = upperFormatter->currentRangeBegin( dtLeft );
638 for ( qreal x : upperXList )
639 {
640 pen.setStyle( Qt::SolidLine );
641 painter->setPen( pen );
642 painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
643 }
644}
645
646DateTimeGrid::Private::HeaderType DateTimeGrid::Private::headerTypeForScale( DateTimeGrid::Scale scale )
647{
648 switch ( scale ) {
649 case ScaleHour:
650 return Private::HeaderHour;
651 case ScaleDay:
652 return Private::HeaderDay;
653 case ScaleWeek:
654 return Private::HeaderWeek;
655 case ScaleMonth:
656 return Private::HeaderMonth;
657 default:
658 // There are no specific header types for any other scale!
659 assert( false );
660 break;
661 }
662 return Private::HeaderDay;
663}
664
666 const QRectF& sceneRect,
667 const QRectF& exposedRect,
668 AbstractRowController* rowController,
669 QWidget* widget )
670{
671 switch ( scale() ) {
672 case ScaleHour:
673 case ScaleDay:
674 case ScaleWeek:
675 case ScaleMonth:
676 d->paintVerticalLines( painter, sceneRect, exposedRect, widget, d->headerTypeForScale( scale() ) );
677 break;
678 case ScaleAuto:
679 case ScaleUserDefined:
680 d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, widget );
681 break;
682 }
683 if ( rowController ) {
684 // First draw the rows
685 QPen pen = painter->pen();
686 pen.setBrush( QApplication::palette().dark() );
687 pen.setStyle( Qt::DashLine );
688 painter->setPen( pen );
689 QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
690 if ( rowController->indexAbove( idx ).isValid() ) idx = rowController->indexAbove( idx );
691 qreal y = 0;
692 while ( y < exposedRect.bottom() && idx.isValid() ) {
693 const Span s = rowController->rowGeometry( idx );
694 y = s.start()+s.length();
695 if ( d->rowSeparators ) {
696 painter->drawLine( QPointF( sceneRect.left(), y ),
697 QPointF( sceneRect.right(), y ) );
698 }
699 if ( !idx.data( ItemTypeRole ).isValid() && d->noInformationBrush.style() != Qt::NoBrush ) {
700 painter->fillRect( QRectF( exposedRect.left(), s.start(), exposedRect.width(), s.length() ), d->noInformationBrush );
701 }
702 // Is alternating background better?
703 //if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
704 idx = rowController->indexBelow( idx );
705 }
706 }
707}
708
709int DateTimeGrid::Private::tabHeight( const QString& txt, QWidget* widget ) const
710{
712 if ( widget ) opt.initFrom( widget );
713 else opt.palette = QApplication::palette();
714 opt.text = txt;
715 QStyle* style;
716 if ( widget ) style = widget->style();
717 else style = QApplication::style();
718 QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
719 return s.height();
720}
721
722void DateTimeGrid::Private::getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
723{
724 const qreal tabw = QApplication::fontMetrics().boundingRect( QLatin1String( "XXXXX" ) ).width();
725 const qreal dayw = dayWidth;
726 if ( dayw > 24*60*60*tabw ) {
727 *lower = &minute_lower;
728 *upper = &minute_upper;
729 } else if ( dayw > 24*60*tabw ) {
730 *lower = &hour_lower;
731 *upper = &hour_upper;
732 } else if ( dayw > 24*tabw ) {
733 *lower = &day_lower;
734 *upper = &day_upper;
735 } else if ( dayw > tabw ) {
736 *lower = &week_lower;
737 *upper = &week_upper;
738 } else if ( 4*dayw > tabw ) {
739 *lower = &month_lower;
740 *upper = &month_upper;
741 } else {
742 *lower = &year_lower;
743 *upper = &year_upper;
744 }
745}
746
747void DateTimeGrid::Private::getFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
748{
749 switch ( scale ) {
750 case DateTimeGrid::ScaleHour:
751 *lower = &hour_lower;
752 *upper = &hour_upper;
753 break;
754 case DateTimeGrid::ScaleDay:
755 *lower = &day_lower;
756 *upper = &day_upper;
757 break;
758 case DateTimeGrid::ScaleWeek:
759 *lower = &week_lower;
760 *upper = &week_upper;
761 break;
762 case DateTimeGrid::ScaleMonth:
763 *lower = &month_lower;
764 *upper = &month_upper;
765 break;
766 case DateTimeGrid::ScaleUserDefined:
767 *lower = this->lower;
768 *upper = this->upper;
769 break;
770 default: /*ScaleAuto:*/
771 getAutomaticFormatters( lower, upper );
772 break;
773 }
774}
775
776DateTimeGrid::HeaderType DateTimeGrid::sectionHandleAtPos(int x, int y, const QRect &headerRect) const
777{
778 QDateTime dt1 = d->chartXtoDateTime( x );
779 QDateTime dt2 = d->chartXtoDateTime( x + 5 );
780
781 DateTimeScaleFormatter *lower, *upper;
782 const_cast<Private*>(d)->getFormatters( &lower, &upper );
783
784 const qreal lowerHeight = d->tabHeight( lower->text( dt1 ) );
785 const qreal upperHeight = d->tabHeight( upper->text( dt1 ) );
786 const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
787
788 const QRectF upperHeaderRect( x, headerRect.top(), 5, headerRect.height() * upperRatio );
789 const QRectF lowerHeaderRect( x, upperHeaderRect.bottom()+1, 5, headerRect.height()-upperHeaderRect.height()-1 );
790 if ( upperHeaderRect.contains( QPoint( x , y ) ) ) {
791 return upper->currentRangeBegin(dt2) == upper->nextRangeBegin(dt1) ? UpperHeader : NoHeader;
792 }
793 if (lowerHeaderRect.contains( QPoint( x , y ) ) ) {
794 return lower->currentRangeBegin(dt2)==lower->nextRangeBegin(dt1) ? LowerHeader : NoHeader;
795 }
796 return NoHeader;
797}
798
799void DateTimeGrid::paintHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
800 qreal offset, QWidget* widget )
801{
802 painter->save();
803 QPainterPath clipPath;
804 clipPath.addRect( headerRect );
805 painter->setClipPath( clipPath, Qt::IntersectClip );
806 switch ( scale() )
807 {
808 case ScaleHour:
809 paintHourScaleHeader( painter, headerRect, exposedRect, offset, widget );
810 break;
811 case ScaleDay:
812 paintDayScaleHeader( painter, headerRect, exposedRect, offset, widget );
813 break;
814 case ScaleWeek:
815 paintWeekScaleHeader( painter, headerRect, exposedRect, offset, widget );
816 break;
817 case ScaleMonth:
818 paintMonthScaleHeader( painter, headerRect, exposedRect, offset, widget );
819 break;
820 case ScaleAuto:
821 {
822 DateTimeScaleFormatter *lower, *upper;
823 d->getAutomaticFormatters( &lower, &upper );
824 const qreal lowerHeight = d->tabHeight( lower->text( startDateTime() ) );
825 const qreal upperHeight = d->tabHeight( upper->text( startDateTime() ) );
826 const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
827
828 const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
829 const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1, headerRect.height()-upperHeaderRect.height()-1 );
830
831 paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, lower, widget );
832 paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, upper, widget );
833 break;
834 }
835 case ScaleUserDefined:
836 {
837 const qreal lowerHeight = d->tabHeight( d->lower->text( startDateTime() ) );
838 const qreal upperHeight = d->tabHeight( d->upper->text( startDateTime() ) );
839 const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
840
841 const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
842 const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1, headerRect.height()-upperHeaderRect.height()-1 );
843
844 paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, d->lower, widget );
845 paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, d->upper, widget );
846 }
847 break;
848 }
849 painter->restore();
850}
851
852void DateTimeGrid::paintUserDefinedHeader( QPainter* painter,
853 const QRectF& headerRect, const QRectF& exposedRect,
854 qreal offset, const DateTimeScaleFormatter* formatter,
855 QWidget* widget )
856{
857 const QStyle* const style = widget ? widget->style() : QApplication::style();
858
859 QDateTime dt = formatter->currentRangeBegin( d->chartXtoDateTime( offset + exposedRect.left() ));
860 qreal x = d->dateTimeToChartX( dt );
861
862 while ( x < exposedRect.right() + offset ) {
863 const QDateTime next = formatter->nextRangeBegin( dt );
864 const qreal nextx = d->dateTimeToChartX( next );
865
867 if ( widget ) opt.initFrom( widget );
868 else opt.palette = QApplication::palette();
869 opt.rect = QRectF( x - offset+1, headerRect.top(), qMax<qreal>( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
870 opt.textAlignment = formatter->alignment();
871 opt.text = formatter->text( dt );
872 style->drawControl( QStyle::CE_Header, &opt, painter, widget );
873
874 dt = next;
875 x = nextx;
876 }
877}
878
879void DateTimeGrid::Private::paintHeader( QPainter* painter,
880 const QRectF& headerRect, const QRectF& exposedRect,
881 qreal offset, QWidget* widget,
882 Private::HeaderType headerType,
883 DateTextFormatter *formatter )
884{
885 QStyle* style = widget?widget->style():QApplication::style();
886
887 const qreal left = exposedRect.left() + offset;
888 const qreal right = exposedRect.right() + offset;
889
890 // Paint a section for each hour
891 QDateTime dt = chartXtoDateTime( left );
892 dt = adjustDateTimeForHeader( dt, headerType );
893 // Determine the time step per grid line
894 int offsetSeconds = 0;
895 int offsetDays = 0;
896 int offsetMonths = 0;
897
898 switch ( headerType ) {
899 case Private::HeaderHour:
900 offsetSeconds = 60*60;
901 break;
902 case Private::HeaderDay:
903 offsetDays = 1;
904 break;
905 case Private::HeaderWeek:
906 offsetDays = 7;
907 break;
908 case Private::HeaderMonth:
909 offsetMonths = 1;
910 break;
911 case Private::HeaderYear:
912 offsetMonths = 12;
913 break;
914 default:
915 // Other scales cannot be painted with this method!
916 assert( false );
917 break;
918 }
919
920 for ( qreal x = dateTimeToChartX( dt ); x < right;
921 dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), dt = dt.addMonths( offsetMonths ),
922 x = dateTimeToChartX( dt ) ) {
924 if ( widget ) opt.initFrom( widget );
925 else opt.palette = QApplication::palette();
926 opt.rect = formatter->textRect( x, offset, dayWidth, headerRect, dt );
927 opt.text = formatter->format( dt );
928 opt.textAlignment = Qt::AlignCenter;
929 style->drawControl(QStyle::CE_Header, &opt, painter, widget);
930 }
931 delete formatter;
932 formatter = nullptr;
933}
934
935
937 const QRectF& headerRect, const QRectF& exposedRect,
938 qreal offset, QWidget* widget )
939{
940 class HourFormatter : public Private::DateTextFormatter {
941 public:
942 ~HourFormatter() override {}
943
944 QString format( const QDateTime& dt ) override {
945 return QLocale().toString(dt.time(), QString::fromLatin1( "hh" ) );
946 }
947 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
948 Q_UNUSED(dt);
949
950 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
951 QSizeF( dayWidth / 24.0, headerRect.height() / 2.0 ) ).toAlignedRect();
952 }
953 };
954 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
955 Private::HeaderHour, new HourFormatter ); // Custom parameters
956
957 class DayFormatter : public Private::DateTextFormatter {
958 public:
959 ~DayFormatter() override {}
960 QString format( const QDateTime& dt ) override {
961 return QLocale().toString(dt.date());
962 }
963 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
964 Q_UNUSED(dt);
965
966 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
967 QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toRect();
968 }
969 };
970 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
971 Private::HeaderDay, new DayFormatter ); // Custom parameters
972}
973
974
975void DateTimeGrid::paintDayScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
976 qreal offset, QWidget* widget )
977{
978 class DayFormatter : public Private::DateTextFormatter {
979 public:
980 ~DayFormatter() override {}
981
982 QString format( const QDateTime& dt ) override {
983 return QLocale().toString(dt, QStringLiteral("ddd")).left(1);
984 }
985 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
986 Q_UNUSED(dt);
987
988 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
989 QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toAlignedRect();
990 }
991 };
992 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
993 Private::HeaderDay, new DayFormatter ); // Custom parameters
994
995 class WeekFormatter : public Private::DateTextFormatter {
996 public:
997 ~WeekFormatter() override {}
998 QString format( const QDateTime& dt ) override {
999 return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
1000 }
1001 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
1002 Q_UNUSED(dt);
1003
1004 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1005 QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
1006 }
1007 };
1008 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1009 Private::HeaderWeek, new WeekFormatter ); // Custom parameters
1010}
1011
1012
1013void DateTimeGrid::paintWeekScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
1014 qreal offset, QWidget* widget )
1015{
1016 class WeekFormatter : public Private::DateTextFormatter {
1017 public:
1018 ~WeekFormatter() override {}
1019
1020 QString format( const QDateTime& dt ) override {
1021 return QString::number( dt.date().weekNumber() );
1022 }
1023 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
1024 Q_UNUSED(dt);
1025
1026 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
1027 QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
1028 }
1029 };
1030 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1031 Private::HeaderWeek, new WeekFormatter ); // Custom parameters
1032
1033 class MonthFormatter : public Private::DateTextFormatter {
1034 public:
1035 ~MonthFormatter() override {}
1036
1037 QString format( const QDateTime& dt ) override {
1039 }
1040 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
1041 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1042 QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
1043 }
1044 };
1045 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1046 Private::HeaderMonth, new MonthFormatter ); // Custom parameters
1047}
1048
1049
1050void DateTimeGrid::paintMonthScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
1051 qreal offset, QWidget* widget )
1052{
1053 class MonthFormatter : public Private::DateTextFormatter {
1054 public:
1055 ~MonthFormatter() override {}
1056
1057 QString format( const QDateTime& dt ) override {
1059 }
1060 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
1061 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
1062 QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
1063 }
1064 };
1065 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1066 Private::HeaderMonth, new MonthFormatter ); // Custom parameters
1067
1068 class YearFormatter : public Private::DateTextFormatter {
1069 public:
1070 ~YearFormatter() override {}
1071
1072 QString format( const QDateTime& dt ) override {
1073 return QString::number( dt.date().year() );
1074 }
1075 QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) override {
1076 return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
1077 QSizeF( dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0 ) ).toRect();
1078 }
1079 };
1080 d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
1081 Private::HeaderYear, new YearFormatter ); // Custom parameters
1082}
1083
1084
1085void DateTimeGrid::drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date)
1086{
1087 Q_UNUSED(date);
1088 if (d->timeLine->options() & DateTimeTimeLine::Background) {
1089 d->drawTimeLine(painter, rect);
1090 }
1091}
1092
1093
1094void DateTimeGrid::drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date)
1095{
1096 Q_UNUSED(date);
1097 if (d->timeLine->options() & DateTimeTimeLine::Foreground) {
1098 d->drawTimeLine(painter, rect);
1099 }
1100}
1101
1102
1103QRectF DateTimeGrid::computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const
1104{
1105 qreal topLeft = d->dateTimeToChartX(from);
1106 qreal topRight = d->dateTimeToChartX(to);
1107
1108 return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
1109}
1110
1111
1112QPair<QDateTime, QDateTime> DateTimeGrid::dateTimeRange(const QRectF& rect) const
1113{
1115 QDateTime end;
1116
1117 start = d->chartXtoDateTime(rect.left());
1118 end = d->chartXtoDateTime(rect.right());
1119
1120 return qMakePair(start, end);
1121}
1122
1124{
1125 int offset = (int)dayWidth();
1126
1127 assert( offset>0 );
1128
1129 // Figure out the date at the extreme left
1130 QDate date = d->chartXtoDateTime(rect.left()).date();
1131
1132 // We need to paint from one end to the other
1133 int startx = rect.left();
1134 int endx = rect.right();
1135
1136 // Save the painter state
1137 paint->save();
1138
1139 // Paint the first date column
1140 while (1)
1141 {
1142 QDate nextDate = d->chartXtoDateTime(startx+1).date();
1143 if (date != nextDate)
1144 {
1145 QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
1146 dayRect = dayRect.adjusted(1, 0, 0, 0);
1147 drawDayBackground(paint, dayRect, date);
1148 break;
1149 }
1150
1151 ++startx;
1152 }
1153
1154 // Paint the remaining dates
1155 for (int i=startx; i<endx; i+=offset)
1156 {
1157 date = d->chartXtoDateTime(i+1).date();
1158
1159 QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
1160 dayRect = dayRect.adjusted(1, 0, 0, 0);
1161 drawDayBackground(paint, dayRect, date);
1162 }
1163
1164 // Restore the painter state
1165 paint->restore();
1166}
1167
1169{
1170 int offset = (int)dayWidth();
1171
1172 // Figure out the date at the extreme left
1173 QDate date = d->chartXtoDateTime(rect.left()).date();
1174
1175 // We need to paint from one end to the other
1176 int startx = rect.left();
1177 int endx = rect.right();
1178
1179 // Save the painter state
1180 paint->save();
1181
1182 // Paint the first date column
1183 while (1)
1184 {
1185 QDate nextDate = d->chartXtoDateTime(startx+1).date();
1186 if (date != nextDate)
1187 {
1188 QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
1189 dayRect = dayRect.adjusted(1, 0, 0, 0);
1190 drawDayForeground(paint, dayRect, date);
1191 break;
1192 }
1193
1194 ++startx;
1195 }
1196
1197 // Paint the remaining dates
1198 for (int i=startx; i<endx; i+=offset)
1199 {
1200 date = d->chartXtoDateTime(i+1).date();
1201
1202 QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
1203 dayRect = dayRect.adjusted(1, 0, 0, 0);
1204 drawDayForeground(paint, dayRect, date);
1205 }
1206
1207 // Restore the painter state
1208 paint->restore();
1209}
1210
1211
1213{
1214 return d->timeLine;
1215}
1216
1217void DateTimeGrid::Private::drawTimeLine(QPainter* painter, const QRectF& rect)
1218{
1219 qreal x = dateTimeToChartX(timeLine->dateTime());
1220 if (rect.contains(x, rect.top())) {
1221 painter->save();
1222 painter->setPen(timeLine->pen());
1223 painter->drawLine(x, rect.top(), x, rect.bottom());
1224 painter->restore();
1225 }
1226}
1227
1228#undef d
1229
1230#ifndef KDAB_NO_UNIT_TESTS
1231
1232#include <QStandardItemModel>
1233#include "unittest/test.h"
1234
1235static std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
1236{
1237#ifdef QT_NO_STL
1238 os << dt.toString().toLatin1().constData();
1239#else
1240 os << dt.toString().toStdString();
1241#endif
1242 return os;
1243}
1244
1245KDAB_SCOPED_UNITTEST_SIMPLE( KGantt, DateTimeGrid, "test" ) {
1246 QStandardItemModel model( 3, 2 );
1247 DateTimeGrid grid;
1249 grid.setModel( &model );
1250 QDateTime startdt = dt.addDays( -10 );
1251 grid.setStartDateTime( startdt );
1252
1253 model.setData( model.index( 0, 0 ), dt, StartTimeRole );
1254 model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
1255
1256 model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
1257 model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
1258
1259 Span s = grid.mapToChart( model.index( 0, 0 ) );
1260 //qDebug() << "span="<<s;
1261
1262 assertTrue( s.start()>0 );
1263 assertTrue( s.length()>0 );
1264
1265 assertTrue( startdt == grid.mapToDateTime( grid.mapFromDateTime( startdt ) ) );
1266
1267 grid.mapFromChart( s, model.index( 1, 0 ) );
1268
1269 QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
1270 QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
1271 QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
1272 QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
1273
1274 assertTrue( s1.isValid() );
1275 assertTrue( e1.isValid() );
1276 assertTrue( s2.isValid() );
1277 assertTrue( e2.isValid() );
1278
1279 assertEqual( s1, s2 );
1280 assertEqual( e1, e2 );
1281
1282 assertTrue( grid.isSatisfiedConstraint( Constraint( model.index( 0, 0 ), model.index( 2, 0 ) ) ) );
1283 assertFalse( grid.isSatisfiedConstraint( Constraint( model.index( 2, 0 ), model.index( 0, 0 ) ) ) );
1284
1285 s = grid.mapToChart( model.index( 0, 0 ) );
1286 s.setEnd( s.end()+100000. );
1287 bool rc = grid.mapFromChart( s, model.index( 0, 0 ) );
1288 assertTrue( rc );
1289 assertEqual( s1, model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime() );
1290 Span newspan = grid.mapToChart( model.index( 0, 0 ) );
1291 assertEqual( newspan.start(), s.start() );
1292 assertEqual( newspan.length(), s.length() );
1293
1294 {
1296 qreal dayWidth = 100;
1297 QDate currentDate = QDate::currentDate();
1298 QDateTime dt( QDate(currentDate.year(), 1, 1), QTime( 0, 0, 0, 0 ) );
1299 assert( dt.isValid() );
1300 qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
1301 result += startDateTime.time().msecsTo(dt.time())/1000.;
1302 result *= dayWidth/( 24.*60.*60. );
1303
1304 int days = static_cast<int>( result/dayWidth );
1305 qreal secs = result*( 24.*60.*60. )/dayWidth;
1307 QDateTime result2 = dt2.addDays( days ).addSecs( static_cast<int>(secs-(days*24.*60.*60.) ) ).addMSecs( qRound( ( secs-static_cast<int>( secs ) )*1000. ) );
1308
1309 assertEqual( dt, result2 );
1310 }
1311}
1312
1313#endif /* KDAB_NO_UNIT_TESTS */
1314
1315#include "moc_kganttdatetimegrid.cpp"
Abstract baseclass for grids. A grid is used to convert between QModelIndex'es and gantt chart values...
QAbstractItemModel * model() const
bool isSatisfiedConstraint(const Constraint &c) const
virtual void setModel(QAbstractItemModel *model)
Abstract baseclass for row controllers. A row controller is used by the GraphicsView to nagivate the ...
virtual QModelIndex indexBelow(const QModelIndex &idx) const =0
virtual Span rowGeometry(const QModelIndex &idx) const =0
virtual QModelIndex indexAbove(const QModelIndex &idx) const =0
A class used to represent a dependency.
virtual void paintHourScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
virtual void drawDayForeground(QPainter *painter, const QRectF &rect, const QDate &date)
bool mapFromChart(const Span &span, const QModelIndex &idx, const QList< Constraint > &constraints=QList< Constraint >()) const override
virtual void paintDayScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
DateTimeTimeLine * timeLine() const
void paintHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr) override
QBrush noInformationBrush() const
DateTimeScaleFormatter * userDefinedUpperScale() const
QDateTime startDateTime() const
void setStartDateTime(const QDateTime &dt)
virtual void drawDayBackground(QPainter *painter, const QRectF &rect, const QDate &date)
void drawForeground(QPainter *paint, const QRectF &rect) override
void setRowSeparators(bool enable)
DateTimeScaleFormatter * userDefinedLowerScale() const
qreal mapFromDateTime(const QDateTime &dt) const
void setWeekStart(Qt::DayOfWeek)
Span mapToChart(const QModelIndex &idx) const override
QRectF computeRect(const QDateTime &from, const QDateTime &to, const QRectF &rect) const
Return the rectangle that represents the date-range.
void setNoInformationBrush(const QBrush &brush)
void drawBackground(QPainter *paint, const QRectF &rect) override
QPair< QDateTime, QDateTime > dateTimeRange(const QRectF &rect) const
Return a date-range represented by the rectangle.
QDateTime mapToDateTime(qreal x) const
virtual void paintWeekScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
Qt::DayOfWeek weekStart() const
void setUserDefinedLowerScale(DateTimeScaleFormatter *lower)
virtual void paintMonthScaleHeader(QPainter *painter, const QRectF &headerRect, const QRectF &exposedRect, qreal offset, QWidget *widget=nullptr)
void paintGrid(QPainter *painter, const QRectF &sceneRect, const QRectF &exposedRect, AbstractRowController *rowController=nullptr, QWidget *widget=nullptr) override
QSet< Qt::DayOfWeek > freeDays() const
void setUserDefinedUpperScale(DateTimeScaleFormatter *upper)
void setFreeDaysBrush(const QBrush brush)
void setFreeDays(const QSet< Qt::DayOfWeek > &fd)
virtual QDateTime nextRangeBegin(const QDateTime &datetime) const
virtual QDateTime currentRangeBegin(const QDateTime &datetime) const
DateTimeScaleFormatter(Range range, const QString &formatString, Qt::Alignment alignment=Qt::AlignCenter)
@ Background
Display the timeline in the background.
@ Foreground
Display the timeline in the foreground.
A class representing a start point and a length.
Q_SCRIPTABLE Q_NOREPLY void start()
Global namespace.
@ ItemTypeRole
The item type.
@ StartTimeRole
Start time (or other start value) for a gantt item.
@ EndTimeRole
End time (or other end value) for a gantt item.
QDateTime startDateTime(const QVariant &elem)
QDebug operator<<(QDebug dbg, const PerceptualColor::MultiSpinBoxSection &value)
virtual QVariant data(const QModelIndex &index, int role) const const=0
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
QFontMetrics fontMetrics()
QStyle * style()
const char * constData() const const
QDate addDays(qint64 ndays) const const
QDate addMonths(int nmonths) const const
QDate addYears(int nyears) const const
QDate currentDate()
int day() const const
int dayOfWeek() const const
int dayOfYear() const const
int daysInMonth() const const
int daysInYear() const const
qint64 daysTo(QDate d) const const
int month() const const
int weekNumber(int *yearNumber) const const
int year() const const
QDateTime addDays(qint64 ndays) const const
QDateTime addMSecs(qint64 msecs) const const
QDateTime addMonths(int nmonths) const const
QDateTime addSecs(qint64 s) const const
QDateTime currentDateTime()
QDate date() const const
bool isValid() const const
void setDate(QDate date)
void setTime(QTime time)
QTime time() const const
QDateTime toLocalTime() const const
QString toString(QStringView format, QCalendar cal) const const
QRect boundingRect(QChar ch) const const
QPalette palette()
void append(QList< T > &&value)
bool contains(const AT &value) const const
QString monthName(int month, FormatType type) const const
QString toString(QDate date, FormatType format) const const
QVariant data(int role) const const
bool isValid() const const
const QAbstractItemModel * model() const const
Q_EMITQ_EMIT
const QBrush & brush() const const
void drawLine(const QLine &line)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QPen & pen() const const
void restore()
void save()
void setBrush(Qt::BrushStyle style)
void setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
void setPen(Qt::PenStyle style)
void addRect(const QRectF &rectangle)
const QBrush & midlight() const const
void setBrush(const QBrush &brush)
void setStyle(Qt::PenStyle style)
int height() const const
int top() const const
int width() const const
QRectF adjusted(qreal dx1, qreal dy1, qreal dx2, qreal dy2) const const
qreal bottom() const const
bool contains(const QPointF &point) const const
qreal height() const const
qreal left() const const
qreal right() const const
QRect toAlignedRect() const const
QRect toRect() const const
qreal top() const const
qreal width() const const
qreal x() const const
int height() const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QByteArray toLatin1() const const
std::string toStdString() const const
CT_HeaderSection
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const const=0
void initFrom(const QWidget *widget)
typedef Alignment
IntersectClip
DayOfWeek
PenStyle
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
int hour() const const
int minute() const const
int msecsTo(QTime t) const const
Type type() const const
bool canConvert() const const
QVariant fromValue(T &&value)
bool isValid() const const
QDateTime toDateTime() const const
QString toString() const const
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.