33 #include <calendarsupport/utils.h>
35 #include <Akonadi/ItemFetchJob>
36 #include <Akonadi/ItemFetchScope>
38 #include <KCalendarSystem>
42 #include <QMouseEvent>
50 const int KODayMatrix::NOSELECTION = -1000;
51 const int KODayMatrix::NUMDAYS = 42;
54 :
QFrame( parent ), mStartDate(), mPendingChanges( false )
57 mDays =
new QDate[NUMDAYS];
58 mDayLabels =
new QString[NUMDAYS];
60 mTodayMarginWidth = 2;
61 mSelEnd = mSelStart = NOSELECTION;
65 mHighlightEvents =
true;
66 mHighlightTodos =
false;
67 mHighlightJournals =
false;
73 mCalendar->unregisterObserver(
this );
74 mCalendar->disconnect(
this );
78 mCalendar->registerObserver(
this );
80 setAcceptDrops( mCalendar != 0 );
84 QColor KODayMatrix::getShadedColor(
const QColor &color )
const
90 color.getHsv( &h, &s, &v );
93 shaded.setHsv( h, s, v );
101 mCalendar->unregisterObserver(
this );
105 delete [] mDayLabels;
110 if ( mSelStart == NOSELECTION ) {
117 for (
int i = i0; i < 0; ++i ) {
118 selDays.append( mDays[0].addDays( i ) );
124 if ( mSelEnd > NUMDAYS-1 ) {
125 for (
int i = i0; i <= NUMDAYS - 1; ++i ) {
126 selDays.append( mDays[i] );
128 for (
int i = NUMDAYS; i < mSelEnd; ++i ) {
129 selDays.append( mDays[0].addDays( i ) );
133 for (
int i = i0; i <= mSelEnd; ++i ) {
134 selDays.append( mDays[i] );
141 if ( mStartDate.isValid() ) {
142 mSelStart = mStartDate.daysTo( start );
143 mSelEnd = mStartDate.daysTo( end );
149 mSelEnd = mSelStart = NOSELECTION;
154 if ( !mStartDate.isValid() ) {
159 for (
int i = 0; i < NUMDAYS; ++i ) {
160 mDays[i] = mStartDate.addDays( i );
161 mDayLabels[i] = QString::number(
KOGlobals::self()->calendarSystem()->day( mDays[i] ) );
164 if ( mDays[i].year() == QDate::currentDate().year() &&
165 mDays[i].month() == QDate::currentDate().month() &&
166 mDays[i].day() == QDate::currentDate().day() ) {
179 mPendingChanges =
true;
184 if ( !actdate.isValid() || NUMDAYS < 1 ) {
188 bool daychanged =
false;
192 if ( actdate != mStartDate ) {
195 if ( mSelStart != NOSELECTION ) {
196 int tmp = actdate.daysTo( mStartDate );
198 if ( mSelStart + tmp < NUMDAYS && mSelEnd + tmp >= 0 ) {
202 if ( mSelStart > NUMDAYS || mSelStart < 0 ) {
203 mSelStart = mSelStart + tmp;
205 if ( mSelEnd > NUMDAYS || mSelEnd < 0 ) {
206 mSelEnd = mSelEnd + tmp;
211 mStartDate = actdate;
221 if ( !daychanged && !mPendingChanges ) {
230 for (
int i = 0; i < NUMDAYS; ++i ) {
232 QStringList holidays = holidaysByDate[mDays[i]];
236 KGlobal::locale()->weekDayOfPray() ) ||
237 !holidays.isEmpty() ) {
238 if ( !holidays.isEmpty() ) {
239 holiStr = holidays.join( i18nc(
"delimiter for joining holiday names",
"," ) );
241 if ( holiStr.isEmpty() ) {
242 holiStr = QLatin1String(
"");
245 mHolidays[i] = holiStr;
257 if ( mHighlightEvents ) {
261 if ( mHighlightTodos ) {
265 if ( mHighlightJournals ) {
269 mPendingChanges =
false;
272 void KODayMatrix::updateJournals()
274 const KCalCore::Incidence::List incidences = mCalendar->incidences();
276 foreach (
const KCalCore::Incidence::Ptr &inc, incidences ) {
278 QDate d = inc->dtStart().toTimeSpec( mCalendar->timeSpec() ).date();
279 if ( inc->type() == KCalCore::Incidence::TypeJournal &&
281 d <= mDays[NUMDAYS-1] &&
282 !mEvents.contains( d ) ) {
285 if ( mEvents.count() == NUMDAYS ) {
301 void KODayMatrix::updateTodos()
303 const KCalCore::Todo::List incidences = mCalendar->todos();
305 foreach (
const KCalCore::Todo::Ptr &t, incidences ) {
306 if ( mEvents.count() == NUMDAYS ) {
311 if ( t->hasDueDate() ) {
312 ushort recurType = t->recurrenceType();
319 KCalCore::DateTimeList timeDateList =
320 t->recurrence()->timesInInterval(
321 KDateTime( mDays[0], mCalendar->timeSpec() ),
322 KDateTime( mDays[NUMDAYS-1], mCalendar->timeSpec() ) );
324 foreach (
const KDateTime &dt, timeDateList ) {
325 d = dt.toTimeSpec( mCalendar->timeSpec() ).date();
326 if ( !mEvents.contains( d ) ) {
332 d = t->dtDue().toTimeSpec( mCalendar->timeSpec() ).date();
333 if ( d >= mDays[0] && d <= mDays[NUMDAYS-1] && !mEvents.contains( d ) ) {
341 void KODayMatrix::updateEvents()
343 if ( mEvents.count() == NUMDAYS ) {
344 mPendingChanges =
false;
348 KCalCore::Event::List eventlist = mCalendar->events( mDays[0], mDays[NUMDAYS-1],
349 mCalendar->timeSpec() );
351 Q_FOREACH (
const KCalCore::Event::Ptr &
event, eventlist ) {
352 if ( mEvents.count() == NUMDAYS ) {
358 const ushort recurType =
event->recurrenceType();
359 const KDateTime dtStart =
event->dtStart().toTimeSpec( mCalendar->timeSpec() );
364 const int secsToAdd =
event->allDay() ? 0 : -1;
365 const KDateTime dtEnd =
event->dtEnd().toTimeSpec( mCalendar->timeSpec() ).addSecs( secsToAdd );
367 if ( !( recurType == KCalCore::Recurrence::rDaily && !
KOPrefs::instance()->mDailyRecur ) &&
370 KCalCore::DateTimeList timeDateList;
371 const bool isRecurrent =
event->recurs();
372 const int eventDuration = dtStart.daysTo( dtEnd );
376 timeDateList =
event->recurrence()->timesInInterval(
377 KDateTime( mDays[0], mCalendar->timeSpec() ),
378 KDateTime( mDays[NUMDAYS-1], mCalendar->timeSpec() ) );
380 if ( dtStart.date() >= mDays[0] ) {
381 timeDateList.append( dtStart );
384 timeDateList.append( KDateTime( mDays[0], mCalendar->timeSpec() ) );
388 KCalCore::DateTimeList::iterator t;
389 for ( t=timeDateList.begin(); t != timeDateList.end(); ++t ) {
391 QDate d = t->toTimeSpec( mCalendar->timeSpec() ).date();
396 occurrenceEnd = d.addDays( eventDuration );
398 occurrenceEnd = dtEnd.date();
405 }
while ( d <= occurrenceEnd && j < NUMDAYS );
409 mPendingChanges =
false;
414 if ( offset < 0 || offset > NUMDAYS - 1 ) {
417 return mDays[offset];
422 if ( offset < 0 || offset > NUMDAYS - 1 ) {
425 return mHolidays[offset];
428 int KODayMatrix::getDayIndexFrom(
int x,
int y )
const
430 return 7 * ( y / mDaySize.height() ) +
432 6 - x / mDaySize.width() : x / mDaySize.width() );
437 Q_UNUSED( incidence );
438 mPendingChanges =
true;
443 Q_UNUSED( incidence );
444 mPendingChanges =
true;
449 Q_UNUSED( incidence );
450 mPendingChanges =
true;
455 bool highlightJournals ) {
458 if ( highlightTodos != mHighlightTodos ||
459 highlightEvents != mHighlightEvents ||
460 highlightJournals != mHighlightJournals ) {
461 mHighlightEvents = highlightEvents;
462 mHighlightTodos = highlightTodos;
463 mHighlightJournals = highlightJournals;
464 mPendingChanges =
true;
470 mPendingChanges =
true;
479 if (
KOPrefs::instance()->mEnableToolTips && event->type() == QEvent::ToolTip ) {
480 QHelpEvent *helpEvent =
static_cast<QHelpEvent*
>(
event );
483 QRect sz = frameRect();
484 int dheight = sz.height() * 7 / 42;
485 int dwidth = sz.width() / 7;
486 int row = helpEvent->pos().y() / dheight;
487 int col = helpEvent->pos().x() / dwidth;
491 if ( !tipText.isEmpty() ) {
492 QToolTip::showText( helpEvent->globalPos(), tipText );
494 QToolTip::hideText();
497 return QWidget::event( event );
502 mSelStart = getDayIndexFrom( e->x(), e->y() );
503 if ( e->button() == Qt::RightButton ) {
504 popupMenu( mDays[mSelStart] ) ;
505 }
else if ( e->button() == Qt::LeftButton ) {
506 if ( mSelStart > NUMDAYS - 1 ) {
507 mSelStart = NUMDAYS - 1;
509 mSelInit = mSelStart;
513 void KODayMatrix::popupMenu(
const QDate &date )
516 popup.addTitle( date.toString() );
517 QAction *newEventAction = popup.addAction(
518 KIcon( QLatin1String(
"appointment-new") ), i18n(
"New E&vent..." ) );
519 QAction *newTodoAction = popup.addAction(
520 KIcon( QLatin1String(
"task-new") ), i18n(
"New &To-do..." ) );
521 QAction *newJournalAction = popup.addAction(
522 KIcon( QLatin1String(
"journal-new") ), i18n(
"New &Journal..." ) );
523 QAction *ret = popup.exec( QCursor::pos() );
524 if ( ret == newEventAction ) {
526 }
else if ( ret == newTodoAction ) {
528 }
else if ( ret == newJournalAction ) {
535 if ( e->button() != Qt::LeftButton ) {
539 int tmp = getDayIndexFrom( e->x(), e->y() );
540 if ( tmp > NUMDAYS - 1 ) {
544 if ( mSelInit > tmp ) {
546 if ( tmp != mSelStart ) {
551 mSelStart = mSelInit;
554 if ( tmp != mSelEnd ) {
560 KCalCore::DateList daylist;
561 if ( mSelStart < 0 ) {
564 for (
int i = mSelStart; i <= mSelEnd; ++i ) {
565 daylist.append( mDays[i] );
567 emit
selected( static_cast<const KCalCore::DateList>(daylist) );
572 int tmp = getDayIndexFrom( e->x(), e->y() );
573 if ( tmp > NUMDAYS - 1 ) {
577 if ( mSelInit > tmp ) {
579 if ( tmp != mSelStart ) {
584 mSelStart = mSelInit;
587 if ( tmp != mSelEnd ) {
609 e->acceptProposedAction();
610 const QMimeData *md = e->mimeData();
611 if ( !CalendarSupport::canDecode( md ) ) {
624 const QMimeData *md = e->mimeData();
625 if ( !CalendarSupport::canDecode( md ) ) {
645 QList<QUrl> urls = ( e->mimeData()->urls() );
647 if ( urls.isEmpty() ) {
653 if ( urls.count() >= 1 ) {
654 KUrl res = urls.at( 0 );
656 Akonadi::ItemFetchJob *job =
new Akonadi::ItemFetchJob( Akonadi::Item::fromUrl( res ) );
657 job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent );
658 job->fetchScope().fetchFullPayload();
659 Akonadi::Item::List items;
661 items = job->items();
663 bool exist = items.at( 0 ).isValid();
666 Qt::KeyboardModifiers keyboardModifiers = e->keyboardModifiers();
668 if ( keyboardModifiers & Qt::ControlModifier ) {
670 }
else if ( keyboardModifiers & Qt::ShiftModifier ) {
673 QAction *copy = 0, *move = 0;
674 KMenu *menu =
new KMenu(
this );
676 move = menu->addAction(
KOGlobals::self()->smallIcon( QLatin1String(
"edit-paste") ), i18n(
"&Move" ) );
678 copy = menu->addAction(
KOGlobals::self()->smallIcon( QLatin1String(
"edit-copy") ), i18n(
"&Copy" ) );
681 move = menu->addAction(
KOGlobals::self()->smallIcon( QLatin1String(
"list-add") ), i18n(
"&Add" ) );
683 menu->addSeparator();
685 menu->addAction(
KOGlobals::self()->smallIcon( QLatin1String(
"process-stop") ), i18n(
"&Cancel" ) );
686 QAction *a = menu->exec( QCursor::pos() );
689 }
else if ( a == move ) {
697 int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
715 const QRect rect = frameRect();
716 const int dayHeight = mDaySize.height();
717 const int dayWidth = mDaySize.width();
719 int selectionWidth, selectionHeight;
722 QPalette pal = palette();
727 p.fillRect( 0, 0, rect.width(), rect.height(), QBrush( pal.color( QPalette::Base ) ) );
730 p.setPen( pal.color( QPalette::Mid ) );
731 p.drawRect( 0, 0, rect.width() - 1, rect.height() - 1 );
736 if ( mSelStart != NOSELECTION ) {
740 if ( row < 0 && mSelEnd > 0 ) {
743 column = mSelStart - row * 7;
746 if ( row < 6 && row >= 0 ) {
747 if ( row == mSelEnd / 7 ) {
750 ( 7 - ( mSelEnd - mSelStart + 1 ) - column ) * dayWidth :
753 ( mSelEnd - mSelStart + 1 ) * dayWidth, dayHeight, selectionColor );
756 p.fillRect( isRTL ? 0 : column * dayWidth, row * dayHeight,
757 ( 7 - column ) * dayWidth, dayHeight, selectionColor );
759 selectionHeight = mSelEnd / 7 - row;
760 if ( selectionHeight + row >= 6 ) {
761 selectionHeight = 6 - row;
763 if ( selectionHeight > 1 ) {
764 p.fillRect( 0, ( row + 1 ) * dayHeight, 7 * dayWidth,
765 ( selectionHeight - 1 ) * dayHeight, selectionColor );
768 if ( mSelEnd / 7 < 6 ) {
769 selectionWidth = mSelEnd - 7 * ( mSelEnd / 7 ) + 1;
771 ( 7 - selectionWidth ) * dayWidth :
773 ( row + selectionHeight ) * dayHeight,
774 selectionWidth * dayWidth, dayHeight, selectionColor );
781 const QColor textColor = pal.color( QPalette::Text );
782 const QColor textColorShaded = getShadedColor( textColor );
783 QColor actcol = textColorShaded;
788 for (
int i = 0; i < NUMDAYS; ++i ) {
790 column = isRTL ? 6 - ( i - row * 7 ) : i - row * 7;
794 if ( actcol == textColorShaded ) {
797 actcol = textColorShaded;
803 if ( i == mSelEnd + 1 ) {
807 const bool holiday = !workDays.contains( mDays[i] );
809 const QColor holidayColorShaded =
815 QPen todayPen( p.pen() );
817 todayPen.setWidth( mTodayMarginWidth );
820 if ( actcol == textColor ) {
823 todayPen.setColor( holidayColorShaded );
827 if ( i >= mSelStart && i <= mSelEnd ) {
828 const QColor grey(QLatin1String(
"grey") );
829 todayPen.setColor( grey );
831 p.setPen( todayPen );
832 p.drawRect( column * dayWidth, row * dayHeight, dayWidth, dayHeight );
837 if ( mEvents.contains( mDays[i] ) ) {
838 QFont myFont = font();
839 myFont.setBold(
true );
845 if ( actcol == textColor ) {
848 p.setPen( holidayColorShaded );
853 if ( i >= mSelStart && i <= mSelEnd && !holiday ) {
854 p.setPen( Qt::white );
857 p.drawText( column * dayWidth, row * dayHeight, dayWidth, dayHeight,
858 Qt::AlignHCenter | Qt::AlignVCenter, mDayLabels[i]);
865 if ( mEvents.contains( mDays[i] ) > 0 ) {
866 QFont myFont = font();
867 myFont.setBold(
false );
880 QRect sz = frameRect();
881 mDaySize.setHeight( sz.height() * 7 / NUMDAYS );
882 mDaySize.setWidth( sz.width() / 7 );
890 calSys->setDate( d, calSys->year( month ), calSys->month( month ), 1 );
892 const int dayOfWeek = calSys->dayOfWeek( d );
893 const int weekstart = KGlobal::locale()->weekStartDay();
895 d = d.addDays( -( 7 + dayOfWeek - weekstart ) % 7 );
897 if ( dayOfWeek == weekstart ) {
901 return qMakePair( d, d.addDays( NUMDAYS-1 ) );
904 #include "kodaymatrix.moc"
void clearSelection()
Clear all selections.
~KODayMatrix()
destructor that deallocates all dynamically allocated private members.
void incidenceDropped(const Akonadi::Item &item, const QDate &dt)
Emitted if the user has dropped an incidence (event or todo) inside the matrix.
static QPair< QDate, QDate > matrixLimits(const QDate &month)
returns the first and last date of the 6*7 matrix that displays month
void resizeEvent(QResizeEvent *)
QMap< QDate, QStringList > holiday(const QDate &start, const QDate &end) const
void dragLeaveEvent(QDragLeaveEvent *e)
void newTodoSignal(const QDate &date)
const QDate & getDate(int offset) const
Returns the QDate object associated with day indexed by the supplied offset.
void calendarIncidenceDeleted(const KCalCore::Incidence::Ptr &incidence)
void dragEnterEvent(QDragEnterEvent *e)
QColor agendaGridHighlightColor() const
Get Highlight color.
void setHighlightMode(bool highlightEvents, bool highlightTodos, bool highlightJournals)
Sets which incidences should be highlighted.
void calendarIncidenceAdded(const KCalCore::Incidence::Ptr &incidence)
Reimplemented from Akonadi::ETMCalendar They set mPendingChanges to true.
void updateIncidences()
Update incidence states of dates.
void setSelectedDaysFrom(const QDate &start, const QDate &end)
Sets the actual to be displayed selection in the day matrix starting from start and ending with end...
QString getHolidayLabel(int offset) const
Returns the official name of this holy day or 0 if there is no label for this day.
void mouseReleaseEvent(QMouseEvent *e)
void mousePressEvent(QMouseEvent *e)
void calendarIncidenceChanged(const KCalCore::Incidence::Ptr &incidence)
void updateView()
Recalculates all the flags of the days in the matrix like holidays or events on a day (Actually calls...
void selected(const KCalCore::DateList &daylist)
Emitted if the user selects a block of days with the mouse by dragging a rectangle inside the matrix...
void dropEvent(QDropEvent *e)
void incidenceDroppedMove(const Akonadi::Item &item, const QDate &dt)
Emitted if the user has dropped an event inside the matrix and chose to move it instead of copy...
void dragMoveEvent(QDragMoveEvent *e)
void resourcesChanged()
Handle resource changes.
const KCalendarSystem * calendarSystem() const
static KOGlobals * self()
QList< QDate > workDays(const QDate &start, const QDate &end) const
Returns a list containing work days between start and .
static bool reverseLayout()
void setCalendar(const Akonadi::ETMCalendar::Ptr &)
Associate a calendar with this day matrix.
void paintEvent(QPaintEvent *ev)
static KOPrefs * instance()
Get instance of KOPrefs.
void addSelectedDaysTo(KCalCore::DateList &)
Adds all actual selected days from mSelStart to mSelEnd to the supplied DateList. ...
KODayMatrix(QWidget *parent)
constructor to create a day matrix widget.
void newEventSignal(const QDate &date)
void recalculateToday()
Calculates which square in the matrix should be hiighted to indicate the square is on "today"...
void mouseMoveEvent(QMouseEvent *e)
void newJournalSignal(const QDate &date)