11#include "agendaview.h"
13#include "agendaitem.h"
14#include "alternatelabel.h"
15#include "calendardecoration.h"
16#include "decorationlabel.h"
18#include "timelabels.h"
19#include "timelabelszone.h"
21#include "calendarview_debug.h"
23#include <Akonadi/CalendarUtils>
24#include <Akonadi/EntityTreeModel>
25#include <Akonadi/IncidenceChanger>
26#include <CalendarSupport/CollectionSelection>
27#include <CalendarSupport/KCalPrefs>
28#include <CalendarSupport/Utils>
30#include <KCalendarCore/CalFilter>
31#include <KCalendarCore/CalFormat>
32#include <KCalendarCore/OccurrenceIterator>
36#include <KPluginFactory>
37#include <KSqueezedTextLabel>
39#include <KLocalizedString>
40#include <QApplication>
53using namespace std::chrono_literals;
64class AgendaHeaderLayout :
public QLayout
68 ~AgendaHeaderLayout()
override;
71 int count()
const override;
78 QSize sizeHint()
const override;
79 QSize minimumSize()
const override;
81 void invalidate()
override;
82 void setGeometry(
const QRect &rect)
override;
85 void updateCache()
const;
90 mutable bool mIsDirty =
false;
91 mutable QSize mSizeHint;
92 mutable QSize mMinSize;
95AgendaHeaderLayout::AgendaHeaderLayout(
QWidget *parent)
100AgendaHeaderLayout::~AgendaHeaderLayout()
113int AgendaHeaderLayout::count()
const
115 return mItems.
size();
118QLayoutItem *AgendaHeaderLayout::itemAt(
int index)
const
120 return mItems.
value(index);
125 if (index < 0 || index >= mItems.
size()) {
129 auto item = mItems.
takeAt(index);
136void AgendaHeaderLayout::invalidate()
142void AgendaHeaderLayout::setGeometry(
const QRect &rect)
153 const int contentWidth = rect.
width() - margins.
left() - margins.
right();
154 const double agendaGridSpacingX =
static_cast<double>(contentWidth) / mItems.
size();
155 int x = margins.
left();
156 const int contentHeight = rect.
height() - margins.
top() - margins.
bottom();
157 const int y = rect.
y() + margins.
top();
158 for (
int i = 0; i < mItems.
size(); ++i) {
159 auto item = mItems.
at(i);
160 const int nextX = margins.
left() +
static_cast<int>((i + 1) * agendaGridSpacingX);
161 const int width = nextX - x;
167QSize AgendaHeaderLayout::sizeHint()
const
175QSize AgendaHeaderLayout::minimumSize()
const
183void AgendaHeaderLayout::updateCache()
const
185 QSize maxItemSizeHint(0, 0);
186 QSize maxItemMinSize(0, 0);
187 for (
auto &item : mItems) {
188 maxItemSizeHint = maxItemSizeHint.expandedTo(item->
sizeHint());
189 maxItemMinSize = maxItemMinSize.expandedTo(item->
minimumSize());
192 const int horizontalMargins = margins.
left() + margins.
right();
193 const int verticalMargins = margins.
top() + margins.
bottom();
194 mSizeHint =
QSize(maxItemSizeHint.width() * mItems.
size() + horizontalMargins, maxItemSizeHint.height() + verticalMargins);
195 mMinSize =
QSize(maxItemMinSize.width() * mItems.
size() + horizontalMargins, maxItemMinSize.height() + verticalMargins);
201class AgendaHeader :
public QWidget
210 void setCalendarName(
const QString &calendarName);
211 void setAgenda(Agenda *agenda);
213 void setWeekWidth(
int width);
214 void updateDayLabelSizes();
215 void updateMargins();
223 void addDay(
const DecorationList &decoList,
QDate date,
bool withDayLabel);
225 void placeDecorations(
const DecorationList &decoList,
QDate date,
QWidget *labelBox,
bool forWeek);
226 void loadDecorations(
const QStringList &decorations,
const QStringList &whiteList, DecorationList &decoList);
229 const bool mIsSideBySide;
231 Agenda *mAgenda =
nullptr;
234 AgendaHeaderLayout *mDayLabelsLayout =
nullptr;
235 QWidget *mWeekLabelBox =
nullptr;
240AgendaHeader::AgendaHeader(
bool isSideBySide,
QWidget *parent)
242 , mIsSideBySide(isSideBySide)
245 layout->setContentsMargins(0, 0, 0, 0);
250 layout->addWidget(mCalendarNameLabel);
253 auto *daysWidget =
new QWidget(
this);
254 layout->addWidget(daysWidget);
257 daysLayout->setContentsMargins(0, 0, 0, 0);
258 daysLayout->setSpacing(SPACING);
260 if (!mIsSideBySide) {
261 mWeekLabelBox =
new QWidget(daysWidget);
262 auto weekLabelBoxLayout =
new QVBoxLayout(mWeekLabelBox);
263 weekLabelBoxLayout->setContentsMargins(0, 0, 0, 0);
264 weekLabelBoxLayout->setSpacing(0);
265 daysLayout->addWidget(mWeekLabelBox);
268 mDayLabels =
new QWidget(daysWidget);
269 mDayLabelsLayout =
new AgendaHeaderLayout(mDayLabels);
270 mDayLabelsLayout->setContentsMargins(0, 0, 0, 0);
271 daysLayout->addWidget(mDayLabels);
272 daysLayout->setStretchFactor(mDayLabels, 1);
275void AgendaHeader::setAgenda(Agenda *agenda)
280void AgendaHeader::setCalendarName(
const QString &calendarName)
282 if (mCalendarNameLabel) {
283 mCalendarNameLabel->
setText(calendarName);
287void AgendaHeader::updateMargins()
289 const int frameWidth = mAgenda ? mAgenda->scrollArea()->
frameWidth() : 0;
290 const int scrollBarWidth = (mIsSideBySide || !mAgenda || !mAgenda->verticalScrollBar()->
isVisible()) ? 0 : mAgenda->verticalScrollBar()->
width();
292 const int leftSpacing = SPACING + frameWidth;
293 const int rightSpacing = scrollBarWidth + frameWidth;
294 mDayLabelsLayout->
setContentsMargins(isLTR ? leftSpacing : rightSpacing, 0, isLTR ? rightSpacing : leftSpacing, 0);
297void AgendaHeader::updateDayLabelSizes()
299 if (mDateDayLabels.
isEmpty()) {
303 AlternateLabel::TextType overallType = AlternateLabel::Extensive;
304 for (
auto label :
std::as_const(mDateDayLabels)) {
305 AlternateLabel::TextType
type =
label->largestFittingTextType();
306 if (type < overallType) {
312 for (
auto label :
std::as_const(mDateDayLabels)) {
313 label->setFixedType(overallType);
317void AgendaHeader::resizeEvent(
QResizeEvent *resizeEvent)
320 updateDayLabelSizes();
323void AgendaHeader::setWeekWidth(
int width)
325 if (!mWeekLabelBox) {
332void AgendaHeader::clear()
335 qDeleteAll(childWidgets);
338 qDeleteAll(childWidgets);
340 mDateDayLabels.
clear();
348 loadDecorations(decoNames, enabledPlugins, decos);
349 const bool hasDecos = !decos.
isEmpty();
351 for (
const QDate &date : dates) {
352 addDay(decos, date, withDayLabel);
357 placeDecorations(decos, dates.
first(), mWeekLabelBox,
true);
368void AgendaHeader::addDay(
const DecorationList &decoList,
QDate date,
bool withDayLabel)
370 auto topDayLabelBox =
new QWidget(mDayLabels);
371 auto topDayLabelBoxLayout =
new QVBoxLayout(topDayLabelBox);
372 topDayLabelBoxLayout->setContentsMargins(0, 0, 0, 0);
373 topDayLabelBoxLayout->setSpacing(0);
375 mDayLabelsLayout->
addWidget(topDayLabelBox);
380 QString longstr =
i18nc(
"short_weekday short_monthname date (e.g. Mon Aug 13)",
387 auto dayLabel =
new AlternateLabel(shortstr, longstr, veryLongStr, topDayLabelBox);
388 topDayLabelBoxLayout->addWidget(dayLabel);
393 dayLabel->setFont(
font);
395 mDateDayLabels.
append(dayLabel);
398 const QStringList texts = CalendarSupport::holiday(date);
399 for (
const QString &text : texts) {
402 topDayLabelBoxLayout->addWidget(label);
407 placeDecorations(decoList, date, topDayLabelBox,
false);
410void AgendaHeader::placeDecorations(
const DecorationList &decoList,
QDate date,
QWidget *labelBox,
bool forWeek)
415 auto decoHBox =
new QWidget(labelBox);
420 decoHBox->setMinimumWidth(1);
423 auto label =
new DecorationLabel(it, decoHBox);
425 label->setMinimumWidth(1);
432void AgendaHeader::loadDecorations(
const QStringList &decorations,
const QStringList &whiteList, DecorationList &decoList)
434 for (
const QString &decoName : decorations) {
437 if (deco !=
nullptr) {
446 auto result = KPluginFactory::instantiatePlugin<CalendarDecoration::Decoration>(
KPluginMetaData(QStringLiteral(
"pim6/korganizer/") + name));
449 return result.plugin;
451 qCDebug(CALENDARVIEW_LOG) <<
"Factory creation failed" << result.errorString;
456class EventViews::EventIndicatorPrivate
459 EventIndicatorPrivate(EventIndicator *parent, EventIndicator::Location loc)
463 mEnabled.
resize(mColumns);
467 ch =
QChar(mLocation == EventIndicator::Top ? 0x21e1 : 0x21e3);
477 p.setPen(q->
palette().text().color());
478 p.drawText(-rect.
left(), -rect.
top(), ch);
481 void adjustGeometry()
487 rect.
setTop(mLocation == EventIndicator::Top ? 0 : q->parentWidget()->height() - rect.height());
493 const EventIndicator::Location mLocation;
498 EventIndicator *
const q;
501EventIndicator::EventIndicator(Location loc,
QWidget *parent)
503 , d(new EventIndicatorPrivate(this, loc))
506 setFixedHeight(d->mPixmap.height());
510EventIndicator::~EventIndicator() =
default;
516 const double cellWidth =
static_cast<double>(
width()) / d->mColumns;
518 const uint pixmapOffset = isRightToLeft ? 0 : (cellWidth - d->mPixmap.width());
519 for (
int i = 0; i < d->mColumns; ++i) {
520 if (d->mEnabled[i]) {
521 const int xOffset = (isRightToLeft ? (d->mColumns - 1 - i) : i) * cellWidth;
522 painter.drawPixmap(xOffset + pixmapOffset, 0, d->mPixmap);
535void EventIndicator::changeColumns(
int columns)
537 d->mColumns = columns;
538 d->mEnabled.resize(d->mColumns);
545void EventIndicator::enableColumn(
int column,
bool enable)
547 Q_ASSERT(column < d->mEnabled.count());
548 d->mEnabled[column] = enable;
559 explicit AgendaViewPrivate(
AgendaView *parent,
bool isInteractive,
bool isSideBySide)
562 , mIsSideBySide(isSideBySide)
563 , mIsInteractive(isInteractive)
564 , mViewCalendar(MultiViewCalendar::Ptr(new MultiViewCalendar()))
566 mViewCalendar->mAgendaView = q;
572 AgendaHeader *mTopDayLabelsFrame =
nullptr;
573 AgendaHeader *mBottomDayLabelsFrame =
nullptr;
574 QWidget *mAllDayFrame =
nullptr;
576 QWidget *mTimeBarHeaderFrame =
nullptr;
580 Agenda *mAllDayAgenda =
nullptr;
581 Agenda *mAgenda =
nullptr;
583 TimeLabelsZone *mTimeLabelsZone =
nullptr;
588 EventIndicator *mEventIndicatorTop =
nullptr;
589 EventIndicator *mEventIndicatorBottom =
nullptr;
598 bool mTimeSpanInAllDay =
true;
599 bool mAllowAgendaUpdate =
true;
603 const bool mIsSideBySide;
605 QWidget *mDummyAllDayLeft =
nullptr;
606 bool mUpdateAllDayAgenda =
true;
607 bool mUpdateAgenda =
true;
609 bool mUpdateEventIndicatorsScheduled =
false;
627 void changeColumns(
int numColumns);
647 void updateAllDayRightSpacer();
662 const auto start1 = one->dtStart();
663 const auto start2 = two->dtStart();
667 if (start1.isValid() ^ start2.isValid()) {
671 if (end1.isValid() ^ end2.isValid()) {
675 if (start1.isValid() && start1 != start2) {
679 if (end1.isValid() && end1 != end2) {
689 return allDayAgendaItems.
isEmpty() ? mAgenda->agendaItems(uid) : allDayAgendaItems;
702 if (todo &&
todo->isOverdue()) {
715 if (!todo && mSelectedDates.
last().daysTo(
incidence->dtStart().date()) > 2) {
720 if (todo && mSelectedDates.
last().daysTo(
todo->dtDue().date()) > 2) {
728void AgendaViewPrivate::changeColumns(
int numColumns)
735 mEventIndicatorTop->changeColumns(numColumns);
736 mEventIndicatorBottom->changeColumns(numColumns);
744 if (
start.isValid() &&
end.isValid() && end >=
start &&
start.daysTo(end) < AgendaView::MAX_DAY_COUNT) {
747 while (date <= end) {
760 if (!incidence || !mViewCalendar->isValid(incidence)) {
761 qCWarning(CALENDARVIEW_LOG) <<
"invalid incidence or item not found." <<
incidence;
765 q->removeIncidence(incidence);
766 q->displayIncidence(incidence,
false);
767 mAgenda->checkScrollBoundaries();
773 if (!incidence || !mViewCalendar->isValid(incidence)) {
774 qCCritical(CALENDARVIEW_LOG) <<
"AgendaViewPrivate::calendarIncidenceAdded() Invalid incidence or item:" <<
incidence;
780 const auto cal = q->
calendar2(incidence);
782 if (
auto mainIncidence = cal->incidence(
incidence->uid())) {
784 reevaluateIncidence(mainIncidence);
785 }
else if (q->displayIncidence(incidence,
false)) {
788 mAgenda->checkScrollBoundaries();
789 q->scheduleUpdateEventIndicators();
795 reevaluateIncidence(incidence);
796 }
else if (q->displayIncidence(incidence,
false)) {
798 mAgenda->checkScrollBoundaries();
799 q->scheduleUpdateEventIndicators();
805 if (!incidence ||
incidence->uid().isEmpty()) {
806 qCCritical(CALENDARVIEW_LOG) <<
"AgendaView::calendarIncidenceChanged() Invalid incidence or empty UID. " <<
incidence;
823 if (datesEqual(originalIncidence, incidence)) {
826 agendaItem->update();
832 if (
incidence->hasRecurrenceId() && mViewCalendar->isValid(incidence)) {
834 const auto cal = q->
calendar2(incidence);
837 reevaluateIncidence(mainIncidence ? mainIncidence :
incidence);
840 reevaluateIncidence(incidence);
850 if (!incidence ||
incidence->uid().isEmpty()) {
851 qCWarning(CALENDARVIEW_LOG) <<
"invalid incidence or empty uid: " <<
incidence;
856 q->removeIncidence(incidence);
861 if (mViewCalendar->isValid(
incidence->uid())) {
866 reevaluateIncidence(mainIncidence);
870 }
else if (mightBeVisible(incidence)) {
873 mAgenda->checkScrollBoundaries();
874 q->scheduleUpdateEventIndicators();
887 const int incidenceOperations = AgendaView::IncidencesAdded | AgendaView::IncidencesEdited | AgendaView::IncidencesDeleted;
890 if ((ones ^ incidenceOperations) & changes) {
891 mUpdateAllDayAgenda =
true;
892 mUpdateAgenda =
true;
893 }
else if (incidence) {
894 mUpdateAllDayAgenda = mUpdateAllDayAgenda |
incidence->allDay();
895 mUpdateAgenda = mUpdateAgenda | !
incidence->allDay();
898 q->EventView::setChanges(changes);
901void AgendaViewPrivate::clearView()
903 if (mUpdateAllDayAgenda) {
904 mAllDayAgenda->clear();
919 if (!q->filterByCollectionSelection(incidence)) {
926 const QDate insertAtDate = insertAtDateTime.
date();
929 const int curCol = qMax(mSelectedDates.
first().daysTo(insertAtDate), qint64(0));
932 if (curCol >= mSelectedDates.
count()) {
936 if (mMinY.
count() <= curCol) {
940 if (mMaxY.
count() <= curCol) {
945 mMinY[curCol] = mAgenda->timeToY(
QTime(23, 59)) + 1;
946 mMaxY[curCol] = mAgenda->timeToY(
QTime(0, 0)) - 1;
951 const QDate firstVisibleDate = mSelectedDates.
first();
953 if (!
event->allDay() && dtEnd >
event->dtStart()) {
959 if (insertAtDate < firstVisibleDate) {
960 beginX = curCol + firstVisibleDate.
daysTo(insertAtDate);
961 endX = beginX + duration;
964 endX = beginX + duration;
967 if (!
todo->hasDueDate()) {
970 beginX = endX = curCol;
976 if (todo &&
todo->isOverdue() && today >= insertAtDate) {
977 mAllDayAgenda->insertAllDayItem(incidence, recurrenceId, curCol, curCol, createSelected);
979 mAllDayAgenda->insertAllDayItem(incidence, recurrenceId, beginX, endX, createSelected);
985 const QTime startTime = insertAtDateTime.
time();
989 const int durationOfFirstOccurrence =
event->dtStart().
secsTo(
event->dtEnd());
990 QTime endTime = startTime.
addSecs(durationOfFirstOccurrence);
992 const int startY = mAgenda->timeToY(startTime);
994 if (endTime ==
QTime(0, 0, 0)) {
995 endTime =
QTime(23, 59, 59);
997 const int endY = mAgenda->timeToY(endTime) - 1;
998 if ((beginX <= 0 && curCol == 0) || beginX == curCol) {
999 mAgenda->insertMultiItem(incidence, recurrenceId, beginX, endX, startY, endY, createSelected);
1001 if (beginX == curCol) {
1002 mMaxY[curCol] = mAgenda->timeToY(
QTime(23, 59));
1003 if (startY < mMinY[curCol]) {
1004 mMinY[curCol] = startY;
1006 }
else if (endX == curCol) {
1007 mMinY[curCol] = mAgenda->timeToY(
QTime(0, 0));
1008 if (endY > mMaxY[curCol]) {
1009 mMaxY[curCol] = endY;
1012 mMinY[curCol] = mAgenda->timeToY(
QTime(0, 0));
1013 mMaxY[curCol] = mAgenda->timeToY(
QTime(23, 59));
1024 const QTime startTime = insertAtDateTime.
time();
1031 const int durationOfFirstOccurrence =
event->dtStart().secsTo(
event->dtEnd());
1032 QTime endTime = startTime.
addSecs(durationOfFirstOccurrence);
1034 startY = mAgenda->timeToY(startTime);
1035 if (durationOfFirstOccurrence != 0 && endTime ==
QTime(0, 0, 0)) {
1040 endY = mAgenda->timeToY(endTime) - 1;
1044 if (
todo->recurs()) {
1049 t =
todo->dtDue().toLocalTime().time();
1052 if (t ==
QTime(0, 0) && !
todo->recurs()) {
1059 const int halfHour = 1800;
1060 if (t.
addSecs(-halfHour) < t) {
1061 startY = mAgenda->timeToY(t.
addSecs(-halfHour));
1062 endY = mAgenda->timeToY(t) - 1;
1065 endY = mAgenda->timeToY(t.
addSecs(halfHour)) - 1;
1068 if (endY < startY) {
1071 mAgenda->insertItem(incidence, recurrenceId, curCol, startY, endY, 1, 1, createSelected);
1072 if (startY < mMinY[curCol]) {
1073 mMinY[curCol] = startY;
1075 if (endY > mMaxY[curCol]) {
1076 mMaxY[curCol] = endY;
1081void AgendaViewPrivate::updateAllDayRightSpacer()
1083 if (!mAllDayRightSpacer) {
1088 auto verticalAgendaScrollBar = mAgenda->verticalScrollBar();
1089 int margin = verticalAgendaScrollBar->
isVisible() ? verticalAgendaScrollBar->width() : 0;
1092 margin -= mAgenda->scrollArea()->
frameWidth();
1102 , d(new AgendaViewPrivate(this, isInteractive, isSideBySide))
1109 , d(new AgendaViewPrivate(this, isInteractive, isSideBySide))
1111 setPreferences(prefs);
1117 d->mSelectedDates = AgendaViewPrivate::generateDateList(
start, end);
1120 d->mMainLayout->setContentsMargins(0, 0, 0, 0);
1123 d->mTopDayLabelsFrame =
new AgendaHeader(d->mIsSideBySide,
this);
1124 d->mMainLayout->addWidget(d->mTopDayLabelsFrame);
1128 d->mMainLayout->addWidget(d->mSplitterAgenda, 1);
1131 d->mAllDayFrame =
new QWidget(d->mSplitterAgenda);
1132 auto allDayFrameLayout =
new QHBoxLayout(d->mAllDayFrame);
1133 allDayFrameLayout->setContentsMargins(0, 0, 0, 0);
1134 allDayFrameLayout->setSpacing(SPACING);
1137 if (!d->mIsSideBySide) {
1138 d->mTimeBarHeaderFrame =
new QWidget(d->mAllDayFrame);
1139 allDayFrameLayout->addWidget(d->mTimeBarHeaderFrame);
1140 auto timeBarHeaderFrameLayout =
new QHBoxLayout(d->mTimeBarHeaderFrame);
1141 timeBarHeaderFrameLayout->setContentsMargins(0, 0, 0, 0);
1142 timeBarHeaderFrameLayout->setSpacing(0);
1143 d->mDummyAllDayLeft =
new QWidget(d->mAllDayFrame);
1144 allDayFrameLayout->addWidget(d->mDummyAllDayLeft);
1148 auto allDayScrollArea =
new AgendaScrollArea(
true,
this, d->mIsInteractive, d->mAllDayFrame);
1149 allDayFrameLayout->addWidget(allDayScrollArea);
1150 d->mAllDayAgenda = allDayScrollArea->agenda();
1153 auto agendaFrame =
new QWidget(d->mSplitterAgenda);
1155 agendaLayout->setContentsMargins(0, 0, 0, 0);
1156 agendaLayout->setSpacing(SPACING);
1159 auto scrollArea =
new AgendaScrollArea(
false,
this, d->mIsInteractive, agendaFrame);
1160 d->mAgenda = scrollArea->agenda();
1161 d->mAgenda->verticalScrollBar()->installEventFilter(
this);
1162 d->mAgenda->setCalendar(d->mViewCalendar);
1164 d->mAllDayAgenda->setCalendar(d->mViewCalendar);
1167 d->mEventIndicatorTop =
new EventIndicator(EventIndicator::Top, scrollArea->viewport());
1168 d->mEventIndicatorBottom =
new EventIndicator(EventIndicator::Bottom, scrollArea->viewport());
1171 d->mTimeLabelsZone =
new TimeLabelsZone(
this, preferences(), d->mAgenda);
1177 agendaLayout->addLayout(timeLabelsZoneLayout);
1178 agendaLayout->addWidget(scrollArea);
1180 timeLabelsZoneLayout->addSpacing(scrollArea->frameWidth());
1181 timeLabelsZoneLayout->addWidget(d->mTimeLabelsZone);
1182 timeLabelsZoneLayout->addSpacing(scrollArea->frameWidth());
1185 connect(d->mAgenda, &Agenda::zoomView,
this, &AgendaView::zoomView);
1188 connect(d->mAgenda, &Agenda::lowerYChanged,
this, &AgendaView::updateEventIndicatorTop);
1189 connect(d->mAgenda, &Agenda::upperYChanged,
this, &AgendaView::updateEventIndicatorBottom);
1191 if (d->mIsSideBySide) {
1192 d->mTimeLabelsZone->hide();
1196 d->mBottomDayLabelsFrame =
new AgendaHeader(d->mIsSideBySide,
this);
1197 d->mBottomDayLabelsFrame->hide();
1199 d->mTopDayLabelsFrame->setAgenda(d->mAgenda);
1200 d->mBottomDayLabelsFrame->setAgenda(d->mAgenda);
1202 if (!d->mIsSideBySide) {
1204 d->mAllDayFrame->layout()->addItem(d->mAllDayRightSpacer);
1207 updateTimeBarWidth();
1224 connectAgenda(d->mAgenda, d->mAllDayAgenda);
1225 connectAgenda(d->mAllDayAgenda, d->mAgenda);
1228AgendaView::~AgendaView()
1231 if (cal->getCalendar()) {
1232 cal->getCalendar()->unregisterObserver(d.get());
1239 EventView::addCalendar(calendar);
1241 if (!d->mViewCalendar->calendarForCollection(calendar->collection()).isNull()) {
1246 view->mCalendar = calendar;
1247 view->mAgendaView =
this;
1253 EventView::removeCalendar(calendar);
1255 auto cal = std::find_if(d->mViewCalendar->mSubCalendars.cbegin(), d->mViewCalendar->mSubCalendars.cend(), [calendar](
const auto &subcal) {
1256 if (auto akonadiCal = qSharedPointerDynamicCast<AkonadiViewCalendar>(subcal); akonadiCal) {
1258 return akonadiCal->mCalendar->collection() == calendar->collection();
1263 if (cal != d->mViewCalendar->mSubCalendars.end()) {
1264 calendar->unregisterObserver(d.get());
1265 d->mViewCalendar->removeCalendar(*cal);
1266 setChanges(EventViews::EventView::ResourcesChanged);
1270void AgendaView::showEvent(
QShowEvent *showEvent)
1275 d->mTopDayLabelsFrame->updateMargins();
1276 d->mBottomDayLabelsFrame->updateMargins();
1277 d->updateAllDayRightSpacer();
1283 d->mTopDayLabelsFrame->updateMargins();
1284 d->mBottomDayLabelsFrame->updateMargins();
1285 d->updateAllDayRightSpacer();
1292 const auto cal = d->mViewCalendar->findCalendar(incidence);
1294 return cal->getCalendar();
1301 const auto cal = d->mViewCalendar->findCalendar(incidenceIdentifier);
1303 return cal->getCalendar();
1310 const bool isFirstCalendar = d->mViewCalendar->calendarCount() == 0;
1312 d->mViewCalendar->addCalendar(cal);
1313 cal->getCalendar()->registerObserver(d.get());
1316 if (isFirstCalendar) {
1317 changes |= EventView::DatesChanged;
1324void AgendaView::connectAgenda(Agenda *agenda, Agenda *otherAgenda)
1326 connect(agenda, &Agenda::showNewEventPopupSignal,
this, &AgendaView::showNewEventPopupSignal);
1328 connect(agenda, &Agenda::showIncidencePopupSignal,
this, &AgendaView::slotShowIncidencePopup);
1330 agenda->setCalendar(d->mViewCalendar);
1334 connect(agenda, &Agenda::newStartSelectSignal, otherAgenda, &Agenda::clearSelection);
1335 connect(agenda, &Agenda::newStartSelectSignal,
this, &AgendaView::timeSpanSelectionChanged);
1337 connect(agenda, &Agenda::editIncidenceSignal,
this, &AgendaView::slotEditIncidence);
1338 connect(agenda, &Agenda::showIncidenceSignal,
this, &AgendaView::slotShowIncidence);
1339 connect(agenda, &Agenda::deleteIncidenceSignal,
this, &AgendaView::slotDeleteIncidence);
1347 connect(agenda, &Agenda::incidenceSelected, otherAgenda, &Agenda::deselectItem);
1348 connect(agenda, &Agenda::incidenceSelected,
this, &AgendaView::slotIncidenceSelected);
1352 qOverload<const KCalendarCore::Incidence::List &, const QPoint &, bool>(&Agenda::droppedIncidences),
1356 qOverload<
const QList<QUrl> &,
const QPoint &,
bool>(&Agenda::droppedIncidences),
1365 Q_EMIT incidenceSelected(item, date);
1374 const auto calendar = calendar3(item);
1375 Q_EMIT showIncidencePopupSignal(calendar, item, date);
1403void AgendaView::zoomInVertically()
1405 if (!d->mIsSideBySide) {
1406 preferences()->setHourSize(preferences()->hourSize() + 1);
1408 d->mAgenda->updateConfig();
1409 d->mAgenda->checkScrollBoundaries();
1411 d->mTimeLabelsZone->updateAll();
1416void AgendaView::zoomOutVertically()
1418 if (preferences()->hourSize() > 4 || d->mIsSideBySide) {
1419 if (!d->mIsSideBySide) {
1420 preferences()->setHourSize(preferences()->hourSize() - 1);
1422 d->mAgenda->updateConfig();
1423 d->mAgenda->checkScrollBoundaries();
1425 d->mTimeLabelsZone->updateAll();
1431void AgendaView::zoomInHorizontally(
QDate date)
1435 QDate dateToZoom = date;
1439 begin = d->mSelectedDates.first();
1440 ndays =
begin.daysTo(d->mSelectedDates.constLast());
1444 dateToZoom = d->mAgenda->selectedIncidenceDate();
1449 newBegin =
begin.addDays(1);
1451 Q_EMIT zoomViewHorizontally(newBegin, count);
1455 newBegin = dateToZoom;
1458 newBegin = dateToZoom.
addDays(-ndays / 2 + 1);
1461 Q_EMIT zoomViewHorizontally(newBegin, count);
1465void AgendaView::zoomOutHorizontally(
QDate date)
1469 QDate dateToZoom = date;
1473 begin = d->mSelectedDates.first();
1474 ndays =
begin.daysTo(d->mSelectedDates.constLast());
1478 dateToZoom = d->mAgenda->selectedIncidenceDate();
1482 newBegin =
begin.addDays(-1);
1485 newBegin = dateToZoom.
addDays(-ndays / 2 - 1);
1489 if (abs(count) >= 31) {
1490 qCDebug(CALENDARVIEW_LOG) <<
"change to the month view?";
1493 Q_EMIT zoomViewHorizontally(newBegin, count);
1500 static QDate zoomDate;
1501 static auto t =
new QTimer(
this);
1506 const QDate date = d->mAgenda->selectedIncidenceDate();
1510 if (!t->isActive()) {
1511 zoomDate = d->mSelectedDates[
pos.x()];
1513 t->setSingleShot(
true);
1517 zoomOutHorizontally(zoomDate);
1519 zoomInHorizontally(zoomDate);
1523 const QPoint posConstentsOld = d->mAgenda->gridToContents(
pos);
1525 zoomOutVertically();
1529 const QPoint posConstentsNew = d->mAgenda->gridToContents(
pos);
1530 d->mAgenda->verticalScrollBar()->scroll(0, posConstentsNew.
y() - posConstentsOld.
y());
1538 if (!force && d->mSaveSelectedDates == d->mSelectedDates) {
1541 d->mSaveSelectedDates = d->mSelectedDates;
1543 const QStringList topStrDecos = preferences()->decorationsAtAgendaViewTop();
1544 const QStringList botStrDecos = preferences()->decorationsAtAgendaViewBottom();
1545 const QStringList selectedPlugins = preferences()->selectedPlugins();
1547 const bool hasTopDecos = d->mTopDayLabelsFrame->createDayLabels(d->mSelectedDates,
true, topStrDecos, selectedPlugins);
1548 const bool hasBottomDecos = d->mBottomDayLabelsFrame->createDayLabels(d->mSelectedDates,
false, botStrDecos, selectedPlugins);
1553 d->mSplitterAgenda->insertWidget(0, d->mTopDayLabelsFrame);
1555 d->mTopDayLabelsFrame->setParent(
this);
1556 d->mMainLayout->insertWidget(0, d->mTopDayLabelsFrame);
1559 if (hasBottomDecos) {
1561 d->mBottomDayLabelsFrame->setParent(d->mSplitterAgenda);
1562 d->mBottomDayLabelsFrame->show();
1564 d->mBottomDayLabelsFrame->setParent(
this);
1565 d->mBottomDayLabelsFrame->hide();
1569void AgendaView::enableAgendaUpdate(
bool enable)
1571 d->mAllowAgendaUpdate = enable;
1576 return d->mSelectedDates.count();
1585 selected.
append(d->mViewCalendar->item(agendaitem));
1590 selected.
append(d->mViewCalendar->item(dayitem));
1601 qd = d->mAgenda->selectedIncidenceDate();
1606 qd = d->mAllDayAgenda->selectedIncidenceDate();
1620 if (
start.secsTo(end) == 15 * 60) {
1623 QTime defaultDuration(CalendarSupport::KCalPrefs::instance()->defaultDuration().time());
1624 int addSecs = (defaultDuration.
hour() * 3600) + (defaultDuration.
minute() * 60);
1625 end =
start.addSecs(addSecs);
1648 return secs <= 24 * 60 * 60 / d->mAgenda->rows();
1652void AgendaView::updateView()
1661void AgendaView::updateConfig()
1665 if (d->mAgenda && d->mAllDayAgenda) {
1666 d->mAgenda->updateConfig();
1667 d->mAllDayAgenda->updateConfig();
1668 d->mTimeLabelsZone->setPreferences(preferences());
1669 d->mTimeLabelsZone->updateAll();
1670 updateTimeBarWidth();
1678void AgendaView::createTimeBarHeaders()
1680 qDeleteAll(d->mTimeBarHeaders);
1681 d->mTimeBarHeaders.clear();
1684 QFont labelFont = d->mTimeLabelsZone->preferences()->agendaTimeLabelsFont();
1687 const auto lst = d->mTimeLabelsZone->timeLabels();
1689 auto timeLabel =
static_cast<TimeLabels *
>(area->widget());
1690 auto label =
new QLabel(timeLabel->header().replace(
QLatin1Char(
'/'), QStringLiteral(
"/ ")), d->mTimeBarHeaderFrame);
1691 d->mTimeBarHeaderFrame->layout()->addWidget(label);
1692 label->setFont(labelFont);
1694 label->setContentsMargins(0, 0, 0, 0);
1695 label->setWordWrap(
true);
1696 label->setToolTip(timeLabel->headerToolTip());
1697 d->mTimeBarHeaders.append(label);
1702void AgendaView::updateTimeBarWidth()
1704 if (d->mIsSideBySide) {
1708 createTimeBarHeaders();
1711 QFont labelFont = d->mTimeLabelsZone->preferences()->agendaTimeLabelsFont();
1715 int width = d->mTimeLabelsZone->preferedTimeLabelsWidth();
1716 for (
QLabel *l :
std::as_const(d->mTimeBarHeaders)) {
1717 const auto lst = l->text().split(
QLatin1Char(
' '));
1718 for (
const QString &word : lst) {
1719 width = qMax(
width, fm.boundingRect(word).width());
1726 const int timeBarWidth =
width * d->mTimeBarHeaders.count();
1728 d->mTimeBarHeaderFrame->setFixedWidth(timeBarWidth - SPACING);
1729 d->mTimeLabelsZone->setFixedWidth(timeBarWidth);
1730 if (d->mDummyAllDayLeft) {
1731 d->mDummyAllDayLeft->setFixedWidth(0);
1734 d->mTopDayLabelsFrame->setWeekWidth(timeBarWidth);
1735 d->mBottomDayLabelsFrame->setWeekWidth(timeBarWidth);
1758 qCDebug(CALENDARVIEW_LOG) << item->text() <<
"; item->cellXLeft(): " << item->cellXLeft() <<
"; item->cellYTop(): " << item->cellYTop()
1759 <<
"; item->lastMultiItem(): " << item->lastMultiItem() <<
"; item->itemPos(): " << item->itemPos()
1760 <<
"; item->itemCount(): " << item->itemCount();
1770 if (item->cellXLeft() < 0) {
1771 thisDate = (d->mSelectedDates.first()).addDays(item->cellXLeft());
1773 thisDate = d->mSelectedDates[item->cellXLeft()];
1779 if (item->cellXLeft() >= 0) {
1780 daysOffset = item->occurrenceDate().
daysTo(thisDate);
1787 if ((!aitem.
isValid() && !addIncidence) || !incidence || !changer()) {
1788 qCWarning(CALENDARVIEW_LOG) <<
"changer is " << changer() <<
" and incidence is " << incidence.
data();
1792 QTime startTime(0, 0, 0);
1793 QTime endTime(0, 0, 0);
1794 if (incidence->allDay()) {
1795 daysLength = item->cellWidth() - 1;
1797 startTime = d->mAgenda->gyToTime(item->cellYTop());
1798 if (item->lastMultiItem()) {
1799 endTime = d->mAgenda->gyToTime(item->lastMultiItem()->cellYBottom() + 1);
1800 daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft();
1801 }
else if (item->itemPos() == item->itemCount() && item->itemCount() > 1) {
1812 endTime = d->mAgenda->gyToTime(item->cellYBottom() + 1);
1813 daysLength = item->itemCount() - 1;
1814 startTime = incidence->dtStart().time();
1815 }
else if (item->itemPos() == 1 && item->itemCount() > 1) {
1818 daysLength = item->itemCount() - 1;
1820 endTime = d->mAgenda->gyToTime(item->cellYBottom() + 1);
1826 startDt = incidence->dtStart();
1830 startDt = startDt.
addDays(daysOffset);
1831 if (!incidence->allDay()) {
1834 endDt = startDt.
addDays(daysLength);
1835 if (!incidence->allDay()) {
1838 if (incidence->dtStart().toLocalTime() == startDt && ev->dtEnd().
toLocalTime() == endDt) {
1850 incidence->setDtStart(copyTimeSpec(startDt, incidence->dtStart()));
1853 endDt.
setTime(td->allDay() ?
QTime(00, 00, 00) : endTime);
1855 if (td->dtDue(
true).toLocalTime() == endDt) {
1861 const auto shift = td->dtDue(
true).secsTo(endDt);
1862 startDt = td->dtStart(
true).
addSecs(shift);
1863 if (td->hasStartDate()) {
1864 td->setDtStart(copyTimeSpec(startDt, incidence->dtStart()));
1867 td->setDtRecurrence(td->dtRecurrence().addSecs(shift));
1869 td->setDtDue(copyTimeSpec(endDt, td->dtDue()),
true);
1872 if (!incidence->hasRecurrenceId()) {
1873 item->setOccurrenceDateTime(startDt);
1879 result = changer()->createIncidence(incidence, collection,
this) != -1;
1883 result = changer()->modifyIncidence(aitem, oldIncidence,
this) != -1;
1897 enableAgendaUpdate(
false);
1902 if (incidence->recurs() || incidence->hasRecurrenceId()) {
1903 d->mUpdateItem = aitem;
1907 enableAgendaUpdate(
true);
1912 if (d->mSelectedDates.isEmpty()) {
1915 return d->mSelectedDates.first();
1920 if (d->mSelectedDates.isEmpty()) {
1923 return d->mSelectedDates.last();
1928 Q_UNUSED(preferredMonth)
1929 if (!d->mSelectedDates.isEmpty() && d->mSelectedDates.first() ==
start && d->mSelectedDates.last() == end) {
1933 if (!
start.isValid() || !end.isValid() ||
start > end ||
start.daysTo(end) > MAX_DAY_COUNT) {
1934 qCWarning(CALENDARVIEW_LOG) <<
"got bizarre parameters: " <<
start << end <<
" - aborting here";
1938 d->mSelectedDates = d->generateDateList(
start, end);
1943 d->mTimeLabelsZone->update();
1955 const auto &cal = d->mViewCalendar->calendarForCollection(aitem.storageCollectionId());
1956 if (cal && cal->filter()) {
1959 cal->setFilter(
nullptr);
1970 end.toTimeZone(
start.timeZone());
1977 d->mAgenda->selectItem(first);
1982 if (
changes() == NothingChanged) {
1986 const QString selectedAgendaId = d->mAgenda->lastSelectedItemUid();
1987 const QString selectedAllDayAgendaId = d->mAllDayAgenda->lastSelectedItemUid();
1989 enableAgendaUpdate(
true);
1992 if (d->mViewCalendar->calendarCount() == 0) {
2003 if (
changes().testFlag(DatesChanged)) {
2004 d->mAllDayAgenda->changeColumns(d->mSelectedDates.count());
2005 d->mAgenda->changeColumns(d->mSelectedDates.count());
2006 d->changeColumns(d->mSelectedDates.count());
2011 d->mAgenda->setDateList(d->mSelectedDates);
2016 bool somethingReselected =
false;
2020 Q_ASSERT(incidence);
2021 const bool wasSelected = (incidence->uid() == selectedAgendaId) || (incidence->uid() == selectedAllDayAgendaId);
2023 if ((incidence->allDay() && d->mUpdateAllDayAgenda) || (!incidence->allDay() && d->mUpdateAgenda)) {
2024 displayIncidence(incidence, wasSelected);
2028 somethingReselected =
true;
2032 d->mAgenda->checkScrollBoundaries();
2041 d->mUpdateAgenda =
false;
2042 d->mUpdateAllDayAgenda =
false;
2044 if (!somethingReselected) {
2055 if (incidence->hasRecurrenceId()) {
2059 if (cal && cal->incidence(incidence->uid())) {
2065 if (todo && (!preferences()->showTodosAgendaView() || !
todo->hasDueDate())) {
2076 if (!d->mightBeVisible(incidence)) {
2080 std::vector<QDateTime> dateTimeList;
2085 bool alreadyAddedToday =
false;
2091 const int secsToAdd =
incidence->allDay() ? 0 : -1;
2092 const int eventDuration =
event ? incDtStart.
daysTo(incDtEnd.
addSecs(secsToAdd)) : 0;
2097 const QDateTime startDateTimeWithOffset = firstVisibleDateTime.
addDays(-eventDuration);
2100 while (rIt.hasNext()) {
2102 auto occurrenceDate = rIt.occurrenceStartDate().toLocalTime();
2103 if (
const auto todo = CalendarSupport::todo(rIt.incidence())) {
2105 occurrenceDate = occurrenceDate.addSecs(
todo->dtStart().secsTo(
todo->dtDue()));
2107 const bool makesDayBusy = preferences()->colorAgendaBusyDays() && makesWholeDayBusy(rIt.incidence());
2113 if (occurrenceDate.date() == today) {
2114 alreadyAddedToday =
true;
2116 d->insertIncidence(rIt.incidence(), rIt.recurrenceId(), occurrenceDate, createSelected);
2122 if (todo &&
todo->hasDueDate() && !
todo->isOverdue()) {
2124 dateToAdd =
todo->dtDue().toLocalTime();
2129 dateToAdd = dateToAdd.
addSecs(-1);
2132 incidenceEnd = dateToAdd;
2134 dateToAdd = incDtStart;
2135 incidenceEnd = incDtEnd;
2144 if (dateToAdd <= lastVisibleDateTime && incidenceEnd > firstVisibleDateTime) {
2145 dateTimeList.push_back(dateToAdd);
2151 if (todo &&
todo->isOverdue() && dateTimeToday >= firstVisibleDateTime && dateTimeToday <= lastVisibleDateTime) {
2154 if (!alreadyAddedToday) {
2155 dateTimeList.push_back(dateTimeToday);
2159 const bool makesDayBusy = preferences()->colorAgendaBusyDays() && makesWholeDayBusy(incidence);
2160 for (
auto t = dateTimeList.begin(); t != dateTimeList.end(); ++t) {
2166 d->insertIncidence(incidence, t->toLocalTime(), t->toLocalTime(), createSelected);
2170 if (
event && makesDayBusy &&
event->isMultiDay()) {
2171 const QDate lastVisibleDate = d->mSelectedDates.last();
2172 for (
QDate date =
event->dtStart().date(); date <=
event->dtEnd().date() && date <= lastVisibleDate; date = date.
addDays(1)) {
2178 return !dateTimeList.empty();
2181void AgendaView::updateEventIndicatorTop(
int newY)
2183 for (
int i = 0; i < d->mMinY.size(); ++i) {
2184 d->mEventIndicatorTop->enableColumn(i, newY > d->mMinY[i]);
2186 d->mEventIndicatorTop->update();
2189void AgendaView::updateEventIndicatorBottom(
int newY)
2191 for (
int i = 0; i < d->mMaxY.size(); ++i) {
2192 d->mEventIndicatorBottom->enableColumn(i, newY <= d->mMaxY[i]);
2194 d->mEventIndicatorBottom->update();
2203#ifdef AKONADI_PORT_DISABLED
2205 if (gpos.
x() < 0 || gpos.
y() < 0) {
2209 const QDate day = d->mSelectedDates[gpos.
x()];
2210 const QTime time = d->mAgenda->gyToTime(gpos.
y());
2211 KDateTime newTime(day, time, preferences()->timeSpec());
2212 newTime.setDateOnly(allDay);
2214 Todo::Ptr
todo = Akonadi::CalendarUtils4::todo(todoItem);
2219 qCDebug(CALENDARVIEW_LOG) <<
"Drop existing Todo";
2220 Todo::Ptr oldTodo(existingTodo->clone());
2222 existingTodo->setDtDue(newTime);
2223 existingTodo->setAllDay(allDay);
2224 changer()->modifyIncidence(existingTodoItem, oldTodo,
this);
2227 i18n(
"Unable to modify this to-do, "
2228 "because it cannot be locked."));
2231 qCDebug(CALENDARVIEW_LOG) <<
"Drop new Todo";
2232 todo->setDtDue(newTime);
2233 todo->setAllDay(allDay);
2234 if (!changer()->addIncidence(todo,
this)) {
2240 qCDebug(CALENDARVIEW_LOG) <<
"AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
2248 if (
auto todo = CalendarSupport::todo(incidence)) {
2253 auto duration =
todo->dtStart().daysTo(
todo->dtDue());
2254 dtStart = dt.
addDays(-duration);
2258 todo->setDtDue(dt,
true);
2259 todo->setDtStart(dtStart);
2260 }
else if (
auto event = CalendarSupport::event(incidence)) {
2261 auto duration =
event->dtStart().secsTo(
event->dtEnd());
2262 if (duration == 0) {
2263 auto defaultDuration = CalendarSupport::KCalPrefs::instance()->defaultDuration().time();
2264 duration = (defaultDuration.hour() * 3600) + (defaultDuration.minute() * 60);
2266 event->setDtEnd(dt.
addSecs(duration));
2267 event->setDtStart(dt);
2275 if (gpos.
x() < 0 || gpos.
y() < 0) {
2279 const QDate day = d->mSelectedDates[gpos.
x()];
2280 const QTime time = d->mAgenda->gyToTime(gpos.
y());
2284 const Akonadi::Item existingItem = d->mViewCalendar->item(incidence);
2285 const bool existsInSameCollection = existingItem.
isValid();
2287 if (existingItem.
isValid() && existsInSameCollection) {
2290 if (newIncidence->dtStart() == newTime && newIncidence->allDay() == allDay) {
2296 setDateTime(newIncidence, newTime, allDay);
2298 (void)changer()->modifyIncidence(existingItem, oldIncidence,
this);
2301 setDateTime(incidence, newTime, allDay);
2304 const bool added = -1 != changer()->createIncidence(incidence,
Akonadi::Collection(),
this);
2309 (void)changer()->deleteIncidence(existingItem);
2318 const Akonadi::Item item = d->mViewCalendar->item(incidence);
2326 if (
QDrag *drag = CalendarSupport::createDrag(incidence,
this)) {
2331void AgendaView::readSettings()
2334 readSettings(config.data());
2337void AgendaView::readSettings(
const KConfig *config)
2346 d->mSplitterAgenda->setSizes(sizes);
2351void AgendaView::writeSettings(
KConfig *config)
2356 group.
writeEntry(
"Separator AgendaView", list);
2361 if (d->mSelectedDates.isEmpty() || !d->mSelectedDates[0].isValid()) {
2366 busyDayMask.
resize(d->mSelectedDates.count());
2368 for (
int i = 0; i < d->mSelectedDates.count(); ++i) {
2369 busyDayMask[i] = !d->mBusyDays[d->mSelectedDates[i]].isEmpty();
2377 if (d->mSelectedDates.isEmpty() || !d->mSelectedDates[0].isValid()) {
2381 d->mHolidayMask.resize(d->mSelectedDates.count() + 1);
2383 const QList<QDate> workDays = CalendarSupport::workDays(d->mSelectedDates.constFirst().addDays(-1), d->mSelectedDates.last());
2384 for (
int i = 0; i < d->mSelectedDates.count(); ++i) {
2385 d->mHolidayMask[i] = !workDays.
contains(d->mSelectedDates[i]);
2390 bool showDay = !workDays.
contains(d->mSelectedDates[0].addDays(-1));
2391 d->mHolidayMask[d->mSelectedDates.count()] = showDay;
2393 d->mAgenda->setHolidayMask(&d->mHolidayMask);
2394 d->mAllDayAgenda->setHolidayMask(&d->mHolidayMask);
2399 d->mAgenda->deselectItem();
2400 d->mAllDayAgenda->deselectItem();
2406 d->mTimeSpanInAllDay =
true;
2411 if (d->mSelectedDates.isEmpty()) {
2415 d->mTimeSpanInAllDay =
false;
2417 const QDate dayStart = d->mSelectedDates[qBound(0,
start.x(), (
int)d->mSelectedDates.size() - 1)];
2418 const QDate dayEnd = d->mSelectedDates[qBound(0, end.x(), (
int)d->mSelectedDates.size() - 1)];
2420 const QTime timeStart = d->mAgenda->gyToTime(
start.y());
2421 const QTime timeEnd = d->mAgenda->gyToTime(end.y() + 1);
2423 d->mTimeSpanBegin =
QDateTime(dayStart, timeStart);
2424 d->mTimeSpanEnd =
QDateTime(dayEnd, timeEnd);
2429 return d->mTimeSpanBegin;
2434 return d->mTimeSpanEnd;
2439 return d->mTimeSpanInAllDay;
2444 d->mTimeSpanBegin.setDate(
QDate());
2445 d->mTimeSpanEnd.setDate(
QDate());
2446 d->mTimeSpanInAllDay =
false;
2453 d->mAllDayAgenda->removeIncidence(incidence);
2454 d->mAgenda->removeIncidence(incidence);
2456 if (!incidence->hasRecurrenceId() && d->mViewCalendar->isValid(incidence->uid())) {
2459 const auto cal =
calendar2(incidence->uid());
2463 if (exception->allDay()) {
2464 d->mAllDayAgenda->removeIncidence(exception);
2466 d->mAgenda->removeIncidence(exception);
2475 d->mUpdateEventIndicatorsScheduled =
false;
2476 d->mMinY = d->mAgenda->minContentsY();
2477 d->mMaxY = d->mAgenda->maxContentsY();
2479 d->mAgenda->checkScrollBoundaries();
2480 updateEventIndicatorTop(d->mAgenda->visibleContentsYMin());
2481 updateEventIndicatorBottom(d->mAgenda->visibleContentsYMax());
2487 d->mAgenda->setIncidenceChanger(changer);
2488 d->mAllDayAgenda->setIncidenceChanger(changer);
2491void AgendaView::clearTimeSpanSelection()
2493 d->mAgenda->clearSelection();
2494 d->mAllDayAgenda->clearSelection();
2498Agenda *AgendaView::agenda()
const
2503Agenda *AgendaView::allDayAgenda()
const
2505 return d->mAllDayAgenda;
2510 return d->mSplitterAgenda;
2531void AgendaView::alignAgendas()
2534 if (d->mDummyAllDayLeft) {
2535 d->mDummyAllDayLeft->setFixedWidth(d->mTimeLabelsZone->width() - d->mTimeBarHeaderFrame->width() - SPACING);
2547void AgendaView::setTitle(
const QString &title)
2549 d->mTopDayLabelsFrame->setCalendarName(title);
2552void AgendaView::scheduleUpdateEventIndicators()
2554 if (!d->mUpdateEventIndicatorsScheduled) {
2555 d->mUpdateEventIndicatorsScheduled =
true;
2560#include "agendaview.moc"
2562#include "moc_agendaview.cpp"
static Collection updatedCollection(const QAbstractItemModel *model, qint64 collectionId)
void setPayload(const T &p)
This class describes the widgets that represent the various calendar items in the agenda view.
AgendaView is the agenda-like view that displays events in a single or multi-day view.
void updateEventIndicators()
Updates the event indicators after a certain incidence was modified or removed.
KCalendarCore::DateList selectedIncidenceDates() const override
returns the currently selected incidence's dates
void clearSelection() override
Clear selection.
void setIncidenceChanger(Akonadi::IncidenceChanger *changer) override
Assign a new incidence change helper object.
int currentDateCount() const override
Returns number of currently shown dates.
QDateTime selectionStart() const override
start-datetime of selection
bool eventDurationHint(QDateTime &startDt, QDateTime &endDt, bool &allDay) const override
return the default start/end date/time for new events
bool selectedIsSingleCell() const
returns if only a single cell is selected, or a range of cells
void deleteSelectedDateTime()
make selected start/end invalid
void setChanges(EventView::Changes) override
Notifies the view that there are pending changes so a redraw is needed.
bool selectedIsAllDay() const
returns true if selection is for whole day
void createDayLabels(bool force)
Create labels for the selected dates.
QDate endDate() const
Last shown day.
void fillAgenda()
Fill agenda using the current set value for the start date.
void updateEventDates(AgendaItem *item, bool addIncidence, Akonadi::Collection::Id collectionId)
Update event belonging to agenda item If the incidence is multi-day, item is the first one.
void showDates(const QDate &start, const QDate &end, const QDate &preferredMonth=QDate()) override
void newTimeSpanSelected(const QPoint &start, const QPoint &end)
Updates data for selected timespan.
void setHolidayMasks()
Set the masks on the agenda widgets indicating, which days are holidays.
virtual KCalendarCore::Calendar::Ptr calendar2(const KCalendarCore::Incidence::Ptr &incidence) const
Return calendar object for a concrete incidence.
QDateTime selectionEnd() const override
end-datetime of selection
QDate startDate() const
First shown day.
void showIncidences(const Akonadi::Item::List &incidenceList, const QDate &date) override
Shows given incidences.
void newTimeSpanSelectedAllDay(const QPoint &start, const QPoint &end)
Updates data for selected timespan for all day event.
void slotIncidencesDropped(const KCalendarCore::Incidence::List &incidences, const QPoint &, bool)
reschedule the todo to the given x- and y- coordinates.
Akonadi::Item::List selectedIncidences() const override
returns the currently selected events
This class provides the interface for a date dependent decoration.
Class for calendar decoration elements.
EventView is the abstract base class from which all other calendar views for event data are derived.
void showIncidenceSignal(const Akonadi::Item &)
instructs the receiver to show the incidence in read-only mode.
void newEventSignal()
instructs the receiver to create a new event in given collection.
void deleteIncidenceSignal(const Akonadi::Item &)
instructs the receiver to delete the Incidence in some manner; some possibilities include automatical...
Changes changes() const
Returns if there are pending changes and a redraw is needed.
void editIncidenceSignal(const Akonadi::Item &)
instructs the receiver to begin editing the incidence specified in some manner.
virtual void setIncidenceChanger(Akonadi::IncidenceChanger *changer)
Assign a new incidence change helper object.
virtual void calendarIncidenceDeleted(const Incidence::Ptr &incidence, const Calendar *calendar)
KConfigGroup group(const QString &group)
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
static KIconLoader * global()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void setText(const QString &text)
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Todo::Ptr todo(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Type type(const QSqlDatabase &db)
Namespace EventViews provides facilities for displaying incidences, including events,...
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const QList< QKeySequence > & begin()
QString label(StandardShortcut id)
const QList< QKeySequence > & end()
QDate addDays(qint64 ndays) const const
int dayOfWeek() const const
qint64 daysTo(QDate d) const const
bool isValid(int year, int month, int day)
QDateTime toTimeSpec(Qt::TimeSpec spec) const const
QDateTime addDays(qint64 ndays) const const
QDateTime addMSecs(qint64 msecs) const const
QDateTime addSecs(qint64 s) const const
qint64 daysTo(const QDateTime &other) const const
bool isValid() const const
int offsetFromUtc() const const
qint64 secsTo(const QDateTime &other) const const
Qt::TimeSpec timeSpec() const const
QTimeZone timeZone() const const
QDateTime toLocalTime() const const
QDateTime toOffsetFromUtc(int offsetSeconds) const const
QDateTime toTimeZone(const QTimeZone &timeZone) const const
int pointSize() const const
void setBold(bool enable)
void setPointSize(int pointSize)
QMargins contentsMargins() const const
virtual void invalidate() override
void setContentsMargins(const QMargins &margins)
virtual void setGeometry(const QRect &r) override
virtual void setSpacing(int)
virtual QSize minimumSize() const const=0
virtual void setGeometry(const QRect &r)=0
virtual QSize sizeHint() const const=0
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
bool contains(const AT &value) const const
qsizetype count() const const
bool isEmpty() const const
void reserve(qsizetype size)
void resize(qsizetype size)
qsizetype size() const const
T value(qsizetype i) const const
QString toString(QDate date, FormatType format) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QList< T > findChildren(Qt::FindChildOptions options) const const
void installEventFilter(QObject *filterObj)
QObject * parent() const const
void fill(const QColor &color)
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
void setHeight(int height)
QSharedPointer< T > create(Args &&... args)
QSharedPointer< X > dynamicCast() const const
void changeSize(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy)
QString number(double n, char format, int precision)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
SH_ScrollView_FrameOnlyAroundContents
virtual int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const const=0
QTime addMSecs(int ms) const const
QTime addSecs(int s) const const
int secsTo(QTime t) const const
QTimeZone systemTimeZone()