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;
66class AgendaHeaderLayout :
public QLayout
70 ~AgendaHeaderLayout()
override;
73 int count()
const override;
80 QSize sizeHint()
const override;
81 QSize minimumSize()
const override;
83 void invalidate()
override;
84 void setGeometry(
const QRect &rect)
override;
87 void updateCache()
const;
92 mutable bool mIsDirty =
false;
93 mutable QSize mSizeHint;
94 mutable QSize mMinSize;
97AgendaHeaderLayout::AgendaHeaderLayout(
QWidget *parent)
102AgendaHeaderLayout::~AgendaHeaderLayout()
115int AgendaHeaderLayout::count()
const
117 return mItems.
size();
120QLayoutItem *AgendaHeaderLayout::itemAt(
int index)
const
122 return mItems.
value(index);
127 if (index < 0 || index >= mItems.
size()) {
131 auto item = mItems.
takeAt(index);
138void AgendaHeaderLayout::invalidate()
144void AgendaHeaderLayout::setGeometry(
const QRect &rect)
155 const int contentWidth = rect.
width() - margins.
left() - margins.
right();
156 const double agendaGridSpacingX =
static_cast<double>(contentWidth) / mItems.
size();
157 int x = margins.
left();
158 const int contentHeight = rect.
height() - margins.
top() - margins.
bottom();
159 const int y = rect.
y() + margins.
top();
160 for (
int i = 0; i < mItems.
size(); ++i) {
161 auto item = mItems.
at(i);
162 const int nextX = margins.
left() +
static_cast<int>((i + 1) * agendaGridSpacingX);
163 const int width = nextX - x;
169QSize AgendaHeaderLayout::sizeHint()
const
177QSize AgendaHeaderLayout::minimumSize()
const
185void AgendaHeaderLayout::updateCache()
const
187 QSize maxItemSizeHint(0, 0);
188 QSize maxItemMinSize(0, 0);
189 for (
auto &item : mItems) {
190 maxItemSizeHint = maxItemSizeHint.expandedTo(item->
sizeHint());
191 maxItemMinSize = maxItemMinSize.expandedTo(item->
minimumSize());
194 const int horizontalMargins = margins.
left() + margins.
right();
195 const int verticalMargins = margins.
top() + margins.
bottom();
196 mSizeHint =
QSize(maxItemSizeHint.width() * mItems.size() + horizontalMargins, maxItemSizeHint.height() + verticalMargins);
197 mMinSize =
QSize(maxItemMinSize.width() * mItems.size() + horizontalMargins, maxItemMinSize.height() + verticalMargins);
203class AgendaHeader :
public QWidget
212 void setCalendarName(
const QString &calendarName);
213 void setAgenda(Agenda *agenda);
215 void setWeekWidth(
int width);
216 void updateDayLabelSizes();
217 void updateMargins();
225 void addDay(
const DecorationList &decoList,
QDate date,
bool withDayLabel);
227 void placeDecorations(
const DecorationList &decoList,
QDate date,
QWidget *labelBox,
bool forWeek);
228 void loadDecorations(
const QStringList &decorations,
const QStringList &whiteList, DecorationList &decoList);
231 const bool mIsSideBySide;
233 Agenda *mAgenda =
nullptr;
236 AgendaHeaderLayout *mDayLabelsLayout =
nullptr;
237 QWidget *mWeekLabelBox =
nullptr;
242AgendaHeader::AgendaHeader(
bool isSideBySide,
QWidget *parent)
244 , mIsSideBySide(isSideBySide)
247 layout->setContentsMargins({});
252 layout->addWidget(mCalendarNameLabel);
255 auto *daysWidget =
new QWidget(
this);
256 layout->addWidget(daysWidget);
259 daysLayout->setContentsMargins({});
260 daysLayout->setSpacing(SPACING);
262 if (!mIsSideBySide) {
263 mWeekLabelBox =
new QWidget(daysWidget);
264 auto weekLabelBoxLayout =
new QVBoxLayout(mWeekLabelBox);
265 weekLabelBoxLayout->setContentsMargins({});
266 weekLabelBoxLayout->setSpacing(0);
267 daysLayout->addWidget(mWeekLabelBox);
270 mDayLabels =
new QWidget(daysWidget);
271 mDayLabelsLayout =
new AgendaHeaderLayout(mDayLabels);
272 mDayLabelsLayout->setContentsMargins({});
273 daysLayout->addWidget(mDayLabels);
274 daysLayout->setStretchFactor(mDayLabels, 1);
277void AgendaHeader::setAgenda(Agenda *agenda)
282void AgendaHeader::setCalendarName(
const QString &calendarName)
284 if (mCalendarNameLabel) {
285 mCalendarNameLabel->
setText(calendarName);
289void AgendaHeader::updateMargins()
291 const int frameWidth = mAgenda ? mAgenda->scrollArea()->
frameWidth() : 0;
292 const int scrollBarWidth = (mIsSideBySide || !mAgenda || !mAgenda->verticalScrollBar()->
isVisible()) ? 0 : mAgenda->verticalScrollBar()->
width();
294 const int leftSpacing = SPACING + frameWidth;
295 const int rightSpacing = scrollBarWidth + frameWidth;
296 mDayLabelsLayout->
setContentsMargins(isLTR ? leftSpacing : rightSpacing, 0, isLTR ? rightSpacing : leftSpacing, 0);
299void AgendaHeader::updateDayLabelSizes()
301 if (mDateDayLabels.
isEmpty()) {
305 AlternateLabel::TextType overallType = AlternateLabel::Extensive;
306 for (
auto label : std::as_const(mDateDayLabels)) {
307 AlternateLabel::TextType
type =
label->largestFittingTextType();
308 if (type < overallType) {
314 for (
auto label : std::as_const(mDateDayLabels)) {
315 label->setFixedType(overallType);
319void AgendaHeader::resizeEvent(
QResizeEvent *resizeEvent)
322 updateDayLabelSizes();
325void AgendaHeader::setWeekWidth(
int width)
327 if (!mWeekLabelBox) {
334void AgendaHeader::clear()
337 qDeleteAll(childWidgets);
340 qDeleteAll(childWidgets);
342 mDateDayLabels.
clear();
350 loadDecorations(decoNames, enabledPlugins, decos);
351 const bool hasDecos = !decos.
isEmpty();
353 for (
const QDate &date : dates) {
354 addDay(decos, date, withDayLabel);
359 placeDecorations(decos, dates.first(), mWeekLabelBox,
true);
370void AgendaHeader::addDay(
const DecorationList &decoList,
QDate date,
bool withDayLabel)
372 auto topDayLabelBox =
new QWidget(mDayLabels);
373 auto topDayLabelBoxLayout =
new QVBoxLayout(topDayLabelBox);
374 topDayLabelBoxLayout->setContentsMargins({});
375 topDayLabelBoxLayout->setSpacing(0);
377 mDayLabelsLayout->
addWidget(topDayLabelBox);
382 QString longstr =
i18nc(
"short_weekday short_monthname date (e.g. Mon Aug 13)",
389 auto dayLabel =
new AlternateLabel(shortstr, longstr, veryLongStr, topDayLabelBox);
390 topDayLabelBoxLayout->addWidget(dayLabel);
395 dayLabel->setFont(
font);
397 mDateDayLabels.
append(dayLabel);
400 const QStringList texts = CalendarSupport::holiday(date);
401 for (
const QString &text : texts) {
404 topDayLabelBoxLayout->addWidget(label);
409 placeDecorations(decoList, date, topDayLabelBox,
false);
412void AgendaHeader::placeDecorations(
const DecorationList &decoList,
QDate date,
QWidget *labelBox,
bool forWeek)
417 auto decoHBox =
new QWidget(labelBox);
422 decoHBox->setMinimumWidth(1);
425 auto label =
new DecorationLabel(it, decoHBox);
427 label->setMinimumWidth(1);
434void AgendaHeader::loadDecorations(
const QStringList &decorations,
const QStringList &whiteList, DecorationList &decoList)
436 for (
const QString &decoName : decorations) {
439 if (deco !=
nullptr) {
448 auto result = KPluginFactory::instantiatePlugin<CalendarDecoration::Decoration>(
KPluginMetaData(QStringLiteral(
"pim6/korganizer/") + name));
451 return result.plugin;
453 qCDebug(CALENDARVIEW_LOG) <<
"Factory creation failed" << result.errorString;
458class EventViews::EventIndicatorPrivate
461 EventIndicatorPrivate(EventIndicator *parent, EventIndicator::Location loc)
465 mEnabled.
resize(mColumns);
469 ch =
QChar(mLocation == EventIndicator::Top ? 0x21e1 : 0x21e3);
479 p.setPen(q->
palette().text().color());
480 p.drawText(-rect.
left(), -rect.
top(), ch);
483 void adjustGeometry()
495 const EventIndicator::Location mLocation;
500 EventIndicator *
const q;
503EventIndicator::EventIndicator(Location loc,
QWidget *parent)
505 , d(new EventIndicatorPrivate(this, loc))
508 setFixedHeight(d->mPixmap.height());
512EventIndicator::~EventIndicator() =
default;
518 const double cellWidth =
static_cast<double>(
width()) / d->mColumns;
520 const uint pixmapOffset = isRightToLeft ? 0 : (cellWidth - d->mPixmap.width());
521 for (
int i = 0; i < d->mColumns; ++i) {
522 if (d->mEnabled[i]) {
523 const int xOffset = (isRightToLeft ? (d->mColumns - 1 - i) : i) * cellWidth;
524 painter.drawPixmap(xOffset + pixmapOffset, 0, d->mPixmap);
537void EventIndicator::changeColumns(
int columns)
539 d->mColumns = columns;
540 d->mEnabled.resize(d->mColumns);
547void EventIndicator::enableColumn(
int column,
bool enable)
549 Q_ASSERT(column < d->mEnabled.count());
550 d->mEnabled[column] = enable;
561 explicit AgendaViewPrivate(
AgendaView *parent,
bool isInteractive,
bool isSideBySide)
564 , mIsSideBySide(isSideBySide)
565 , mIsInteractive(isInteractive)
566 , mViewCalendar(MultiViewCalendar::Ptr(new MultiViewCalendar()))
568 mViewCalendar->mAgendaView = q;
574 AgendaHeader *mTopDayLabelsFrame =
nullptr;
575 AgendaHeader *mBottomDayLabelsFrame =
nullptr;
576 QWidget *mAllDayFrame =
nullptr;
578 QWidget *mTimeBarHeaderFrame =
nullptr;
582 Agenda *mAllDayAgenda =
nullptr;
583 Agenda *mAgenda =
nullptr;
585 TimeLabelsZone *mTimeLabelsZone =
nullptr;
590 EventIndicator *mEventIndicatorTop =
nullptr;
591 EventIndicator *mEventIndicatorBottom =
nullptr;
600 bool mTimeSpanInAllDay =
true;
601 bool mAllowAgendaUpdate =
true;
605 const bool mIsSideBySide;
607 QWidget *mDummyAllDayLeft =
nullptr;
608 bool mUpdateAllDayAgenda =
true;
609 bool mUpdateAgenda =
true;
611 bool mUpdateEventIndicatorsScheduled =
false;
629 void changeColumns(
int numColumns);
649 void updateAllDayRightSpacer();
664 const auto start1 = one->dtStart();
665 const auto start2 = two->dtStart();
669 if (start1.isValid() ^ start2.isValid()) {
673 if (end1.isValid() ^ end2.isValid()) {
677 if (start1.isValid() && start1 != start2) {
681 if (end1.isValid() && end1 != end2) {
691 return allDayAgendaItems.
isEmpty() ? mAgenda->agendaItems(uid) : allDayAgendaItems;
704 if (todo &&
todo->isOverdue()) {
717 if (!todo && mSelectedDates.
last().daysTo(
incidence->dtStart().date()) > 2) {
722 if (todo && mSelectedDates.
last().daysTo(
todo->dtDue().date()) > 2) {
730void AgendaViewPrivate::changeColumns(
int numColumns)
737 mEventIndicatorTop->changeColumns(numColumns);
738 mEventIndicatorBottom->changeColumns(numColumns);
746 if (
start.isValid() &&
end.isValid() && end >=
start &&
start.daysTo(end) < AgendaView::MAX_DAY_COUNT) {
749 while (date <= end) {
762 if (!incidence || !mViewCalendar->isValid(incidence)) {
763 qCWarning(CALENDARVIEW_LOG) <<
"invalid incidence or item not found." <<
incidence;
767 q->removeIncidence(incidence);
768 q->displayIncidence(incidence,
false);
769 mAgenda->checkScrollBoundaries();
775 if (!incidence || !mViewCalendar->isValid(incidence)) {
776 qCCritical(CALENDARVIEW_LOG) <<
"AgendaViewPrivate::calendarIncidenceAdded() Invalid incidence or item:" <<
incidence;
782 const auto cal = q->
calendar2(incidence);
784 if (
auto mainIncidence = cal->incidence(
incidence->uid())) {
786 reevaluateIncidence(mainIncidence);
787 }
else if (q->displayIncidence(incidence,
false)) {
790 mAgenda->checkScrollBoundaries();
791 q->scheduleUpdateEventIndicators();
797 reevaluateIncidence(incidence);
798 }
else if (q->displayIncidence(incidence,
false)) {
800 mAgenda->checkScrollBoundaries();
801 q->scheduleUpdateEventIndicators();
807 if (!incidence ||
incidence->uid().isEmpty()) {
808 qCCritical(CALENDARVIEW_LOG) <<
"AgendaView::calendarIncidenceChanged() Invalid incidence or empty UID. " <<
incidence;
825 if (datesEqual(originalIncidence, incidence)) {
828 agendaItem->update();
834 if (
incidence->hasRecurrenceId() && mViewCalendar->isValid(incidence)) {
836 const auto cal = q->
calendar2(incidence);
839 reevaluateIncidence(mainIncidence ? mainIncidence : incidence);
842 reevaluateIncidence(incidence);
852 if (!incidence ||
incidence->uid().isEmpty()) {
853 qCWarning(CALENDARVIEW_LOG) <<
"invalid incidence or empty uid: " <<
incidence;
858 q->removeIncidence(incidence);
863 if (mViewCalendar->isValid(
incidence->uid())) {
868 reevaluateIncidence(mainIncidence);
872 }
else if (mightBeVisible(incidence)) {
875 mAgenda->checkScrollBoundaries();
876 q->scheduleUpdateEventIndicators();
889 const int incidenceOperations = AgendaView::IncidencesAdded | AgendaView::IncidencesEdited | AgendaView::IncidencesDeleted;
892 if ((ones ^ incidenceOperations) & changes) {
893 mUpdateAllDayAgenda =
true;
894 mUpdateAgenda =
true;
895 }
else if (incidence) {
896 mUpdateAllDayAgenda = mUpdateAllDayAgenda |
incidence->allDay();
897 mUpdateAgenda = mUpdateAgenda | !
incidence->allDay();
900 q->EventView::setChanges(changes);
903void AgendaViewPrivate::clearView()
905 if (mUpdateAllDayAgenda) {
906 mAllDayAgenda->clear();
921 if (!q->filterByCollectionSelection(incidence)) {
928 const QDate insertAtDate = insertAtDateTime.
date();
931 const int curCol = qMax(mSelectedDates.
first().daysTo(insertAtDate), qint64(0));
934 if (curCol >= mSelectedDates.
count()) {
938 if (mMinY.
count() <= curCol) {
942 if (mMaxY.
count() <= curCol) {
947 mMinY[curCol] = mAgenda->timeToY(
QTime(23, 59)) + 1;
948 mMaxY[curCol] = mAgenda->timeToY(
QTime(0, 0)) - 1;
953 const QDate firstVisibleDate = mSelectedDates.
first();
955 if (!
event->allDay() && dtEnd >
event->dtStart()) {
961 if (insertAtDate < firstVisibleDate) {
962 beginX = curCol + firstVisibleDate.
daysTo(insertAtDate);
963 endX = beginX + duration;
966 endX = beginX + duration;
969 if (!
todo->hasDueDate()) {
972 beginX = endX = curCol;
978 if (todo &&
todo->isOverdue() && today >= insertAtDate) {
979 mAllDayAgenda->insertAllDayItem(incidence, recurrenceId, curCol, curCol, createSelected);
981 mAllDayAgenda->insertAllDayItem(incidence, recurrenceId, beginX, endX, createSelected);
987 const QTime startTime = insertAtDateTime.
time();
991 const int durationOfFirstOccurrence =
event->dtStart().
secsTo(
event->dtEnd());
992 QTime endTime = startTime.
addSecs(durationOfFirstOccurrence);
994 const int startY = mAgenda->timeToY(startTime);
996 if (endTime ==
QTime(0, 0, 0)) {
997 endTime =
QTime(23, 59, 59);
999 const int endY = mAgenda->timeToY(endTime) - 1;
1000 if ((beginX <= 0 && curCol == 0) || beginX == curCol) {
1001 mAgenda->insertMultiItem(incidence, recurrenceId, beginX, endX, startY, endY, createSelected);
1003 if (beginX == curCol) {
1004 mMaxY[curCol] = mAgenda->timeToY(
QTime(23, 59));
1005 if (startY < mMinY[curCol]) {
1006 mMinY[curCol] = startY;
1008 }
else if (endX == curCol) {
1009 mMinY[curCol] = mAgenda->timeToY(
QTime(0, 0));
1010 if (endY > mMaxY[curCol]) {
1011 mMaxY[curCol] = endY;
1014 mMinY[curCol] = mAgenda->timeToY(
QTime(0, 0));
1015 mMaxY[curCol] = mAgenda->timeToY(
QTime(23, 59));
1026 const QTime startTime = insertAtDateTime.
time();
1033 const int durationOfFirstOccurrence =
event->dtStart().secsTo(
event->dtEnd());
1034 QTime endTime = startTime.
addSecs(durationOfFirstOccurrence);
1036 startY = mAgenda->timeToY(startTime);
1037 if (durationOfFirstOccurrence != 0 && endTime ==
QTime(0, 0, 0)) {
1042 endY = mAgenda->timeToY(endTime) - 1;
1046 if (
todo->recurs()) {
1051 t =
todo->dtDue().toLocalTime().time();
1054 if (t ==
QTime(0, 0) && !
todo->recurs()) {
1061 const int halfHour = 1800;
1062 if (t.
addSecs(-halfHour) < t) {
1063 startY = mAgenda->timeToY(t.
addSecs(-halfHour));
1064 endY = mAgenda->timeToY(t) - 1;
1067 endY = mAgenda->timeToY(t.
addSecs(halfHour)) - 1;
1070 if (endY < startY) {
1073 mAgenda->insertItem(incidence, recurrenceId, curCol, startY, endY, 1, 1, createSelected);
1074 if (startY < mMinY[curCol]) {
1075 mMinY[curCol] = startY;
1077 if (endY > mMaxY[curCol]) {
1078 mMaxY[curCol] = endY;
1083void AgendaViewPrivate::updateAllDayRightSpacer()
1085 if (!mAllDayRightSpacer) {
1090 auto verticalAgendaScrollBar = mAgenda->verticalScrollBar();
1091 int margin = verticalAgendaScrollBar->
isVisible() ? verticalAgendaScrollBar->width() : 0;
1094 margin -= mAgenda->scrollArea()->
frameWidth();
1104 , d(new AgendaViewPrivate(this, isInteractive, isSideBySide))
1111 , d(new AgendaViewPrivate(this, isInteractive, isSideBySide))
1113 setPreferences(prefs);
1119 d->mSelectedDates = AgendaViewPrivate::generateDateList(
start, end);
1122 d->mMainLayout->setContentsMargins({});
1125 d->mTopDayLabelsFrame =
new AgendaHeader(d->mIsSideBySide,
this);
1126 d->mMainLayout->addWidget(d->mTopDayLabelsFrame);
1130 d->mMainLayout->addWidget(d->mSplitterAgenda, 1);
1133 d->mAllDayFrame =
new QWidget(d->mSplitterAgenda);
1134 auto allDayFrameLayout =
new QHBoxLayout(d->mAllDayFrame);
1135 allDayFrameLayout->setContentsMargins({});
1136 allDayFrameLayout->setSpacing(SPACING);
1139 if (!d->mIsSideBySide) {
1140 d->mTimeBarHeaderFrame =
new QWidget(d->mAllDayFrame);
1141 allDayFrameLayout->addWidget(d->mTimeBarHeaderFrame);
1142 auto timeBarHeaderFrameLayout =
new QHBoxLayout(d->mTimeBarHeaderFrame);
1143 timeBarHeaderFrameLayout->setContentsMargins({});
1144 timeBarHeaderFrameLayout->setSpacing(0);
1145 d->mDummyAllDayLeft =
new QWidget(d->mAllDayFrame);
1146 allDayFrameLayout->addWidget(d->mDummyAllDayLeft);
1150 auto allDayScrollArea =
new AgendaScrollArea(
true,
this, d->mIsInteractive, d->mAllDayFrame);
1151 allDayFrameLayout->addWidget(allDayScrollArea);
1152 d->mAllDayAgenda = allDayScrollArea->agenda();
1155 auto agendaFrame =
new QWidget(d->mSplitterAgenda);
1157 agendaLayout->setContentsMargins({});
1158 agendaLayout->setSpacing(SPACING);
1161 auto scrollArea =
new AgendaScrollArea(
false,
this, d->mIsInteractive, agendaFrame);
1162 d->mAgenda = scrollArea->agenda();
1163 d->mAgenda->verticalScrollBar()->installEventFilter(
this);
1164 d->mAgenda->setCalendar(d->mViewCalendar);
1166 d->mAllDayAgenda->setCalendar(d->mViewCalendar);
1169 d->mEventIndicatorTop =
new EventIndicator(EventIndicator::Top, scrollArea->viewport());
1170 d->mEventIndicatorBottom =
new EventIndicator(EventIndicator::Bottom, scrollArea->viewport());
1173 d->mTimeLabelsZone =
new TimeLabelsZone(
this, preferences(), d->mAgenda);
1179 agendaLayout->addLayout(timeLabelsZoneLayout);
1180 agendaLayout->addWidget(scrollArea);
1182 timeLabelsZoneLayout->addSpacing(scrollArea->frameWidth());
1183 timeLabelsZoneLayout->addWidget(d->mTimeLabelsZone);
1184 timeLabelsZoneLayout->addSpacing(scrollArea->frameWidth());
1187 connect(d->mAgenda, &Agenda::zoomView,
this, &AgendaView::zoomView);
1190 connect(d->mAgenda, &Agenda::lowerYChanged,
this, &AgendaView::updateEventIndicatorTop);
1191 connect(d->mAgenda, &Agenda::upperYChanged,
this, &AgendaView::updateEventIndicatorBottom);
1193 if (d->mIsSideBySide) {
1194 d->mTimeLabelsZone->hide();
1198 d->mBottomDayLabelsFrame =
new AgendaHeader(d->mIsSideBySide,
this);
1199 d->mBottomDayLabelsFrame->hide();
1201 d->mTopDayLabelsFrame->setAgenda(d->mAgenda);
1202 d->mBottomDayLabelsFrame->setAgenda(d->mAgenda);
1204 if (!d->mIsSideBySide) {
1206 d->mAllDayFrame->layout()->addItem(d->mAllDayRightSpacer);
1209 updateTimeBarWidth();
1226 connectAgenda(d->mAgenda, d->mAllDayAgenda);
1227 connectAgenda(d->mAllDayAgenda, d->mAgenda);
1230AgendaView::~AgendaView()
1232 for (
const ViewCalendar::Ptr &cal : std::as_const(d->mViewCalendar->mSubCalendars)) {
1233 if (cal->getCalendar()) {
1234 cal->getCalendar()->unregisterObserver(d.get());
1241 EventView::addCalendar(calendar);
1243 if (!d->mViewCalendar->calendarForCollection(calendar->collection()).isNull()) {
1248 view->mCalendar = calendar;
1249 view->mAgendaView =
this;
1255 EventView::removeCalendar(calendar);
1257 auto cal = std::find_if(d->mViewCalendar->mSubCalendars.cbegin(), d->mViewCalendar->mSubCalendars.cend(), [calendar](
const auto &subcal) {
1258 if (auto akonadiCal = qSharedPointerDynamicCast<AkonadiViewCalendar>(subcal); akonadiCal) {
1260 return akonadiCal->mCalendar->collection() == calendar->collection();
1265 if (cal != d->mViewCalendar->mSubCalendars.end()) {
1266 calendar->unregisterObserver(d.get());
1267 d->mViewCalendar->removeCalendar(*cal);
1268 setChanges(EventViews::EventView::ResourcesChanged);
1272void AgendaView::showEvent(
QShowEvent *showEvent)
1277 d->mTopDayLabelsFrame->updateMargins();
1278 d->mBottomDayLabelsFrame->updateMargins();
1279 d->updateAllDayRightSpacer();
1285 d->mTopDayLabelsFrame->updateMargins();
1286 d->mBottomDayLabelsFrame->updateMargins();
1287 d->updateAllDayRightSpacer();
1294 const auto cal = d->mViewCalendar->findCalendar(incidence);
1296 return cal->getCalendar();
1303 const auto cal = d->mViewCalendar->findCalendar(incidenceIdentifier);
1305 return cal->getCalendar();
1312 const bool isFirstCalendar = d->mViewCalendar->calendarCount() == 0;
1314 d->mViewCalendar->addCalendar(cal);
1315 cal->getCalendar()->registerObserver(d.get());
1318 if (isFirstCalendar) {
1319 changes |= EventView::DatesChanged;
1326void AgendaView::connectAgenda(Agenda *agenda, Agenda *otherAgenda)
1328 connect(agenda, &Agenda::showNewEventPopupSignal,
this, &AgendaView::showNewEventPopupSignal);
1330 connect(agenda, &Agenda::showIncidencePopupSignal,
this, &AgendaView::slotShowIncidencePopup);
1332 agenda->setCalendar(d->mViewCalendar);
1336 connect(agenda, &Agenda::newStartSelectSignal, otherAgenda, &Agenda::clearSelection);
1337 connect(agenda, &Agenda::newStartSelectSignal,
this, &AgendaView::timeSpanSelectionChanged);
1339 connect(agenda, &Agenda::editIncidenceSignal,
this, &AgendaView::slotEditIncidence);
1340 connect(agenda, &Agenda::showIncidenceSignal,
this, &AgendaView::slotShowIncidence);
1341 connect(agenda, &Agenda::deleteIncidenceSignal,
this, &AgendaView::slotDeleteIncidence);
1349 connect(agenda, &Agenda::incidenceSelected, otherAgenda, &Agenda::deselectItem);
1350 connect(agenda, &Agenda::incidenceSelected,
this, &AgendaView::slotIncidenceSelected);
1354 qOverload<const KCalendarCore::Incidence::List &, const QPoint &, bool>(&Agenda::droppedIncidences),
1358 qOverload<
const QList<QUrl> &,
const QPoint &,
bool>(&Agenda::droppedIncidences),
1367 Q_EMIT incidenceSelected(item, date);
1376 const auto calendar = calendar3(item);
1377 Q_EMIT showIncidencePopupSignal(calendar, item, date);
1405void AgendaView::zoomInVertically()
1407 if (!d->mIsSideBySide) {
1408 preferences()->setHourSize(preferences()->hourSize() + 1);
1410 d->mAgenda->updateConfig();
1411 d->mAgenda->checkScrollBoundaries();
1413 d->mTimeLabelsZone->updateAll();
1418void AgendaView::zoomOutVertically()
1420 if (preferences()->hourSize() > 4 || d->mIsSideBySide) {
1421 if (!d->mIsSideBySide) {
1422 preferences()->setHourSize(preferences()->hourSize() - 1);
1424 d->mAgenda->updateConfig();
1425 d->mAgenda->checkScrollBoundaries();
1427 d->mTimeLabelsZone->updateAll();
1433void AgendaView::zoomInHorizontally(
QDate date)
1437 QDate dateToZoom = date;
1441 begin = d->mSelectedDates.first();
1442 ndays =
begin.daysTo(d->mSelectedDates.constLast());
1446 dateToZoom = d->mAgenda->selectedIncidenceDate();
1451 newBegin =
begin.addDays(1);
1453 Q_EMIT zoomViewHorizontally(newBegin, count);
1457 newBegin = dateToZoom;
1460 newBegin = dateToZoom.
addDays(-ndays / 2 + 1);
1463 Q_EMIT zoomViewHorizontally(newBegin, count);
1467void AgendaView::zoomOutHorizontally(
QDate date)
1471 QDate dateToZoom = date;
1475 begin = d->mSelectedDates.first();
1476 ndays =
begin.daysTo(d->mSelectedDates.constLast());
1480 dateToZoom = d->mAgenda->selectedIncidenceDate();
1484 newBegin =
begin.addDays(-1);
1487 newBegin = dateToZoom.
addDays(-ndays / 2 - 1);
1491 if (abs(count) >= 31) {
1492 qCDebug(CALENDARVIEW_LOG) <<
"change to the month view?";
1495 Q_EMIT zoomViewHorizontally(newBegin, count);
1502 static QDate zoomDate;
1503 static auto t =
new QTimer(
this);
1508 const QDate date = d->mAgenda->selectedIncidenceDate();
1512 if (!t->isActive()) {
1513 zoomDate = d->mSelectedDates[
pos.x()];
1515 t->setSingleShot(
true);
1519 zoomOutHorizontally(zoomDate);
1521 zoomInHorizontally(zoomDate);
1525 const QPoint posConstentsOld = d->mAgenda->gridToContents(
pos);
1527 zoomOutVertically();
1531 const QPoint posConstentsNew = d->mAgenda->gridToContents(
pos);
1532 d->mAgenda->verticalScrollBar()->scroll(0, posConstentsNew.
y() - posConstentsOld.
y());
1540 if (!force && d->mSaveSelectedDates == d->mSelectedDates) {
1543 d->mSaveSelectedDates = d->mSelectedDates;
1545 const QStringList topStrDecos = preferences()->decorationsAtAgendaViewTop();
1546 const QStringList botStrDecos = preferences()->decorationsAtAgendaViewBottom();
1547 const QStringList selectedPlugins = preferences()->selectedPlugins();
1549 const bool hasTopDecos = d->mTopDayLabelsFrame->createDayLabels(d->mSelectedDates,
true, topStrDecos, selectedPlugins);
1550 const bool hasBottomDecos = d->mBottomDayLabelsFrame->createDayLabels(d->mSelectedDates,
false, botStrDecos, selectedPlugins);
1555 d->mSplitterAgenda->insertWidget(0, d->mTopDayLabelsFrame);
1557 d->mTopDayLabelsFrame->setParent(
this);
1558 d->mMainLayout->insertWidget(0, d->mTopDayLabelsFrame);
1561 if (hasBottomDecos) {
1563 d->mBottomDayLabelsFrame->setParent(d->mSplitterAgenda);
1564 d->mBottomDayLabelsFrame->show();
1566 d->mBottomDayLabelsFrame->setParent(
this);
1567 d->mBottomDayLabelsFrame->hide();
1571void AgendaView::enableAgendaUpdate(
bool enable)
1573 d->mAllowAgendaUpdate = enable;
1578 return d->mSelectedDates.count();
1587 selected.
append(d->mViewCalendar->item(agendaitem));
1592 selected.
append(d->mViewCalendar->item(dayitem));
1603 qd = d->mAgenda->selectedIncidenceDate();
1608 qd = d->mAllDayAgenda->selectedIncidenceDate();
1622 if (
start.secsTo(end) == 15 * 60) {
1625 QTime defaultDuration(CalendarSupport::KCalPrefs::instance()->defaultDuration().time());
1626 int addSecs = (defaultDuration.
hour() * 3600) + (defaultDuration.
minute() * 60);
1627 end =
start.addSecs(addSecs);
1638 if (startDt == endDt) {
1639 QTime defaultDuration(CalendarSupport::KCalPrefs::instance()->defaultDuration().time());
1640 endDt = endDt.
addDuration(std::chrono::hours(defaultDuration.
hour()) + std::chrono::minutes(defaultDuration.
minute()));
1659 return secs <= 24 * 60 * 60 / d->mAgenda->rows();
1663void AgendaView::updateView()
1672void AgendaView::updateConfig()
1676 if (d->mAgenda && d->mAllDayAgenda) {
1677 d->mAgenda->updateConfig();
1678 d->mAllDayAgenda->updateConfig();
1679 d->mTimeLabelsZone->setPreferences(preferences());
1680 d->mTimeLabelsZone->updateAll();
1681 updateTimeBarWidth();
1689void AgendaView::createTimeBarHeaders()
1691 qDeleteAll(d->mTimeBarHeaders);
1692 d->mTimeBarHeaders.clear();
1695 QFont labelFont = d->mTimeLabelsZone->preferences()->agendaTimeLabelsFont();
1698 const auto lst = d->mTimeLabelsZone->timeLabels();
1700 auto timeLabel =
static_cast<TimeLabels *
>(area->widget());
1701 auto label =
new QLabel(timeLabel->header().replace(
QLatin1Char(
'/'), QStringLiteral(
"/ ")), d->mTimeBarHeaderFrame);
1702 d->mTimeBarHeaderFrame->layout()->addWidget(label);
1703 label->setFont(labelFont);
1705 label->setContentsMargins({});
1706 label->setWordWrap(
true);
1707 label->setToolTip(timeLabel->headerToolTip());
1708 d->mTimeBarHeaders.append(label);
1713void AgendaView::updateTimeBarWidth()
1715 if (d->mIsSideBySide) {
1719 createTimeBarHeaders();
1722 QFont labelFont = d->mTimeLabelsZone->preferences()->agendaTimeLabelsFont();
1726 int width = d->mTimeLabelsZone->preferedTimeLabelsWidth();
1727 for (
QLabel *l : std::as_const(d->mTimeBarHeaders)) {
1728 const auto lst = l->text().split(
QLatin1Char(
' '));
1729 for (
const QString &word : lst) {
1730 width = qMax(
width, fm.boundingRect(word).width());
1737 const int timeBarWidth =
width * d->mTimeBarHeaders.count();
1739 d->mTimeBarHeaderFrame->setFixedWidth(timeBarWidth - SPACING);
1740 d->mTimeLabelsZone->setFixedWidth(timeBarWidth);
1741 if (d->mDummyAllDayLeft) {
1742 d->mDummyAllDayLeft->setFixedWidth(0);
1745 d->mTopDayLabelsFrame->setWeekWidth(timeBarWidth);
1746 d->mBottomDayLabelsFrame->setWeekWidth(timeBarWidth);
1770 qCDebug(CALENDARVIEW_LOG) << item->text() <<
"; item->cellXLeft(): " << item->cellXLeft() <<
"; item->cellYTop(): " << item->cellYTop()
1771 <<
"; item->lastMultiItem(): " << item->lastMultiItem() <<
"; item->itemPos(): " << item->itemPos()
1772 <<
"; item->itemCount(): " << item->itemCount();
1782 if (item->cellXLeft() < 0) {
1783 thisDate = (d->mSelectedDates.first()).
addDays(item->cellXLeft());
1785 thisDate = d->mSelectedDates[item->cellXLeft()];
1791 if (item->cellXLeft() >= 0) {
1792 daysOffset = item->occurrenceDate().
daysTo(thisDate);
1799 if ((!aitem.
isValid() && !addIncidence) || !incidence || !changer()) {
1800 qCWarning(CALENDARVIEW_LOG) <<
"changer is " << changer() <<
" and incidence is " << incidence.
data();
1804 QTime startTime(0, 0, 0);
1805 QTime endTime(0, 0, 0);
1806 if (incidence->allDay()) {
1807 daysLength = item->cellWidth() - 1;
1809 startTime = d->mAgenda->gyToTime(item->cellYTop());
1810 if (item->lastMultiItem()) {
1811 endTime = d->mAgenda->gyToTime(item->lastMultiItem()->cellYBottom() + 1);
1812 daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft();
1813 }
else if (item->itemPos() == item->itemCount() && item->itemCount() > 1) {
1824 endTime = d->mAgenda->gyToTime(item->cellYBottom() + 1);
1825 daysLength = item->itemCount() - 1;
1826 startTime = incidence->dtStart().time();
1827 }
else if (item->itemPos() == 1 && item->itemCount() > 1) {
1830 daysLength = item->itemCount() - 1;
1832 endTime = d->mAgenda->gyToTime(item->cellYBottom() + 1);
1838 startDt = incidence->dtStart();
1842 startDt = startDt.
addDays(daysOffset);
1843 if (!incidence->allDay()) {
1846 endDt = startDt.
addDays(daysLength);
1847 if (!incidence->allDay()) {
1850 if (incidence->dtStart().toLocalTime() == startDt && ev->dtEnd().
toLocalTime() == endDt) {
1862 incidence->setDtStart(copyTimeSpec(startDt, incidence->dtStart()));
1865 endDt.
setTime(td->allDay() ?
QTime(00, 00, 00) : endTime);
1867 if (td->dtDue(
true).toLocalTime() == endDt) {
1873 const auto shift = td->dtDue(
true).secsTo(endDt);
1874 startDt = td->dtStart(
true).
addSecs(shift);
1875 if (td->hasStartDate()) {
1876 td->setDtStart(copyTimeSpec(startDt, incidence->dtStart()));
1879 td->setDtRecurrence(td->dtRecurrence().addSecs(shift));
1881 td->setDtDue(copyTimeSpec(endDt, td->dtDue()),
true);
1884 if (!incidence->hasRecurrenceId()) {
1891 result = changer()->createIncidence(incidence, collection,
this) != -1;
1895 result = changer()->modifyIncidence(aitem, oldIncidence,
this) != -1;
1909 enableAgendaUpdate(
false);
1914 if (incidence->recurs() || incidence->hasRecurrenceId()) {
1915 d->mUpdateItem = aitem;
1919 enableAgendaUpdate(
true);
1924 if (d->mSelectedDates.isEmpty()) {
1927 return d->mSelectedDates.first();
1932 if (d->mSelectedDates.isEmpty()) {
1935 return d->mSelectedDates.last();
1940 Q_UNUSED(preferredMonth)
1941 if (!d->mSelectedDates.isEmpty() && d->mSelectedDates.first() ==
start && d->mSelectedDates.last() == end) {
1945 if (!
start.isValid() || !end.isValid() ||
start > end ||
start.daysTo(end) > MAX_DAY_COUNT) {
1946 qCWarning(CALENDARVIEW_LOG) <<
"got bizarre parameters: " <<
start << end <<
" - aborting here";
1950 d->mSelectedDates = d->generateDateList(
start, end);
1955 d->mTimeLabelsZone->update();
1967 const auto &cal = d->mViewCalendar->calendarForCollection(aitem.storageCollectionId());
1968 if (cal && cal->filter()) {
1971 cal->setFilter(
nullptr);
1982 end.toTimeZone(
start.timeZone());
1989 d->mAgenda->selectItem(first);
1994 if (
changes() == NothingChanged) {
1998 const QString selectedAgendaId = d->mAgenda->lastSelectedItemUid();
1999 const QString selectedAllDayAgendaId = d->mAllDayAgenda->lastSelectedItemUid();
2001 enableAgendaUpdate(
true);
2004 if (d->mViewCalendar->calendarCount() == 0) {
2015 if (
changes().testFlag(DatesChanged)) {
2016 d->mAllDayAgenda->changeColumns(d->mSelectedDates.count());
2017 d->mAgenda->changeColumns(d->mSelectedDates.count());
2018 d->changeColumns(d->mSelectedDates.count());
2023 d->mAgenda->setDateList(d->mSelectedDates);
2028 bool somethingReselected =
false;
2032 Q_ASSERT(incidence);
2033 const bool wasSelected = (incidence->uid() == selectedAgendaId) || (incidence->uid() == selectedAllDayAgendaId);
2035 if ((incidence->allDay() && d->mUpdateAllDayAgenda) || (!incidence->allDay() && d->mUpdateAgenda)) {
2036 displayIncidence(incidence, wasSelected);
2040 somethingReselected =
true;
2044 d->mAgenda->checkScrollBoundaries();
2053 d->mUpdateAgenda =
false;
2054 d->mUpdateAllDayAgenda =
false;
2056 if (!somethingReselected) {
2067 if (incidence->hasRecurrenceId()) {
2071 if (cal && cal->incidence(incidence->uid())) {
2077 if (todo && (!preferences()->showTodosAgendaView() || !
todo->hasDueDate())) {
2088 if (!d->mightBeVisible(incidence)) {
2092 std::vector<QDateTime> dateTimeList;
2097 bool alreadyAddedToday =
false;
2103 const int secsToAdd =
incidence->allDay() ? 0 : -1;
2104 const int eventDuration =
event ? incDtStart.
daysTo(incDtEnd.
addSecs(secsToAdd)) : 0;
2109 const QDateTime startDateTimeWithOffset = firstVisibleDateTime.
addDays(-eventDuration);
2112 while (rIt.hasNext()) {
2114 auto occurrenceDate = rIt.occurrenceStartDate().toLocalTime();
2115 if (
const auto todo = CalendarSupport::todo(rIt.incidence())) {
2117 occurrenceDate = occurrenceDate.addSecs(
todo->dtStart().secsTo(
todo->dtDue()));
2119 const bool makesDayBusy = preferences()->colorAgendaBusyDays() && makesWholeDayBusy(rIt.incidence());
2125 if (occurrenceDate.date() == today) {
2126 alreadyAddedToday =
true;
2128 d->insertIncidence(rIt.incidence(), rIt.recurrenceId(), occurrenceDate, createSelected);
2134 if (todo &&
todo->hasDueDate() && !
todo->isOverdue()) {
2136 dateToAdd =
todo->dtDue().toLocalTime();
2141 dateToAdd = dateToAdd.
addSecs(-1);
2144 incidenceEnd = dateToAdd;
2146 dateToAdd = incDtStart;
2147 incidenceEnd = incDtEnd;
2156 if (dateToAdd <= lastVisibleDateTime && incidenceEnd > firstVisibleDateTime) {
2157 dateTimeList.push_back(dateToAdd);
2163 if (todo &&
todo->isOverdue() && dateTimeToday >= firstVisibleDateTime && dateTimeToday <= lastVisibleDateTime) {
2166 if (!alreadyAddedToday) {
2167 dateTimeList.push_back(dateTimeToday);
2171 const bool makesDayBusy = preferences()->colorAgendaBusyDays() && makesWholeDayBusy(incidence);
2172 for (
auto t = dateTimeList.begin(); t != dateTimeList.end(); ++t) {
2178 d->insertIncidence(incidence, t->toLocalTime(), t->toLocalTime(), createSelected);
2182 if (
event && makesDayBusy &&
event->isMultiDay()) {
2183 const QDate lastVisibleDate = d->mSelectedDates.last();
2184 for (
QDate date =
event->dtStart().date(); date <= event->dtEnd().date() && date <= lastVisibleDate; date = date.
addDays(1)) {
2190 return !dateTimeList.empty();
2193void AgendaView::updateEventIndicatorTop(
int newY)
2195 for (
int i = 0; i < d->mMinY.size(); ++i) {
2196 d->mEventIndicatorTop->enableColumn(i, newY > d->mMinY[i]);
2198 d->mEventIndicatorTop->update();
2201void AgendaView::updateEventIndicatorBottom(
int newY)
2203 for (
int i = 0; i < d->mMaxY.size(); ++i) {
2204 d->mEventIndicatorBottom->enableColumn(i, newY <= d->mMaxY[i]);
2206 d->mEventIndicatorBottom->update();
2215#ifdef AKONADI_PORT_DISABLED
2217 if (gpos.
x() < 0 || gpos.
y() < 0) {
2221 const QDate day = d->mSelectedDates[gpos.
x()];
2222 const QTime time = d->mAgenda->gyToTime(gpos.
y());
2223 KDateTime newTime(day, time, preferences()->timeSpec());
2224 newTime.setDateOnly(allDay);
2226 Todo::Ptr
todo = Akonadi::CalendarUtils4::todo(todoItem);
2231 qCDebug(CALENDARVIEW_LOG) <<
"Drop existing Todo";
2232 Todo::Ptr oldTodo(existingTodo->clone());
2234 existingTodo->setDtDue(newTime);
2235 existingTodo->setAllDay(allDay);
2236 changer()->modifyIncidence(existingTodoItem, oldTodo,
this);
2239 i18n(
"Unable to modify this to-do, "
2240 "because it cannot be locked."));
2243 qCDebug(CALENDARVIEW_LOG) <<
"Drop new Todo";
2244 todo->setDtDue(newTime);
2245 todo->setAllDay(allDay);
2246 if (!changer()->addIncidence(todo,
this)) {
2252 qCDebug(CALENDARVIEW_LOG) <<
"AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
2260 if (
auto todo = CalendarSupport::todo(incidence)) {
2265 auto duration =
todo->dtStart().daysTo(
todo->dtDue());
2266 dtStart = dt.
addDays(-duration);
2270 todo->setDtDue(dt,
true);
2271 todo->setDtStart(dtStart);
2272 }
else if (
auto event = CalendarSupport::event(incidence)) {
2273 auto duration =
event->dtStart().secsTo(
event->dtEnd());
2274 if (duration == 0) {
2275 auto defaultDuration = CalendarSupport::KCalPrefs::instance()->defaultDuration().time();
2276 duration = (defaultDuration.hour() * 3600) + (defaultDuration.minute() * 60);
2278 event->setDtEnd(dt.
addSecs(duration));
2279 event->setDtStart(dt);
2287 if (gpos.
x() < 0 || gpos.
y() < 0) {
2291 const QDate day = d->mSelectedDates[gpos.
x()];
2292 const QTime time = d->mAgenda->gyToTime(gpos.
y());
2296 const Akonadi::Item existingItem = d->mViewCalendar->item(incidence);
2297 const bool existsInSameCollection = existingItem.
isValid();
2299 if (existingItem.
isValid() && existsInSameCollection) {
2302 if (newIncidence->dtStart() == newTime && newIncidence->allDay() == allDay) {
2308 setDateTime(newIncidence, newTime, allDay);
2310 (void)changer()->modifyIncidence(existingItem, oldIncidence,
this);
2313 setDateTime(incidence, newTime, allDay);
2316 const bool added = -1 != changer()->createIncidence(incidence,
Akonadi::Collection(),
this);
2321 (void)changer()->deleteIncidence(existingItem);
2330 const Akonadi::Item item = d->mViewCalendar->item(incidence);
2338 if (
QDrag *drag = CalendarSupport::createDrag(incidence,
this)) {
2343void AgendaView::readSettings()
2346 readSettings(config.data());
2349void AgendaView::readSettings(
const KConfig *config)
2358 d->mSplitterAgenda->setSizes(sizes);
2363void AgendaView::writeSettings(
KConfig *config)
2368 group.
writeEntry(
"Separator AgendaView", list);
2373 if (d->mSelectedDates.isEmpty() || !d->mSelectedDates[0].isValid()) {
2378 busyDayMask.
resize(d->mSelectedDates.count());
2380 for (
int i = 0; i < d->mSelectedDates.count(); ++i) {
2381 busyDayMask[i] = !d->mBusyDays[d->mSelectedDates[i]].isEmpty();
2389 if (d->mSelectedDates.isEmpty() || !d->mSelectedDates[0].isValid()) {
2393 d->mHolidayMask.resize(d->mSelectedDates.count() + 1);
2395 const QList<QDate> workDays = CalendarSupport::workDays(d->mSelectedDates.constFirst().addDays(-1), d->mSelectedDates.last());
2396 for (
int i = 0; i < d->mSelectedDates.count(); ++i) {
2397 d->mHolidayMask[i] = !workDays.
contains(d->mSelectedDates[i]);
2402 bool showDay = !workDays.
contains(d->mSelectedDates[0].addDays(-1));
2403 d->mHolidayMask[d->mSelectedDates.count()] = showDay;
2405 d->mAgenda->setHolidayMask(&d->mHolidayMask);
2406 d->mAllDayAgenda->setHolidayMask(&d->mHolidayMask);
2411 d->mAgenda->deselectItem();
2412 d->mAllDayAgenda->deselectItem();
2418 d->mTimeSpanInAllDay =
true;
2423 if (d->mSelectedDates.isEmpty()) {
2427 d->mTimeSpanInAllDay =
false;
2429 const QDate dayStart = d->mSelectedDates[qBound(0,
start.x(), (
int)d->mSelectedDates.size() - 1)];
2430 const QDate dayEnd = d->mSelectedDates[qBound(0, end.x(), (
int)d->mSelectedDates.size() - 1)];
2432 const QTime timeStart = d->mAgenda->gyToTime(
start.y());
2433 const QTime timeEnd = d->mAgenda->gyToTime(end.y() + 1);
2435 d->mTimeSpanBegin =
QDateTime(dayStart, timeStart);
2436 d->mTimeSpanEnd =
QDateTime(dayEnd, timeEnd);
2441 return d->mTimeSpanBegin;
2446 return d->mTimeSpanEnd;
2451 return d->mTimeSpanInAllDay;
2456 d->mTimeSpanBegin.setDate(
QDate());
2457 d->mTimeSpanEnd.setDate(
QDate());
2458 d->mTimeSpanInAllDay =
false;
2465 d->mAllDayAgenda->removeIncidence(incidence);
2466 d->mAgenda->removeIncidence(incidence);
2468 if (!incidence->hasRecurrenceId() && d->mViewCalendar->isValid(incidence->uid())) {
2471 const auto cal =
calendar2(incidence->uid());
2475 if (exception->allDay()) {
2476 d->mAllDayAgenda->removeIncidence(exception);
2478 d->mAgenda->removeIncidence(exception);
2487 d->mUpdateEventIndicatorsScheduled =
false;
2488 d->mMinY = d->mAgenda->minContentsY();
2489 d->mMaxY = d->mAgenda->maxContentsY();
2491 d->mAgenda->checkScrollBoundaries();
2492 updateEventIndicatorTop(d->mAgenda->visibleContentsYMin());
2493 updateEventIndicatorBottom(d->mAgenda->visibleContentsYMax());
2499 d->mAgenda->setIncidenceChanger(changer);
2500 d->mAllDayAgenda->setIncidenceChanger(changer);
2503void AgendaView::clearTimeSpanSelection()
2505 d->mAgenda->clearSelection();
2506 d->mAllDayAgenda->clearSelection();
2510Agenda *AgendaView::agenda()
const
2515Agenda *AgendaView::allDayAgenda()
const
2517 return d->mAllDayAgenda;
2522 return d->mSplitterAgenda;
2527 Q_UNUSED(incidence);
2544void AgendaView::alignAgendas()
2547 if (d->mDummyAllDayLeft) {
2548 d->mDummyAllDayLeft->setFixedWidth(d->mTimeLabelsZone->width() - d->mTimeBarHeaderFrame->width() - SPACING);
2560void AgendaView::setTitle(
const QString &title)
2562 d->mTopDayLabelsFrame->setCalendarName(title);
2565void AgendaView::scheduleUpdateEventIndicators()
2567 if (!d->mUpdateEventIndicatorsScheduled) {
2568 d->mUpdateEventIndicatorsScheduled =
true;
2573#include "agendaview.moc"
2575#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.
void setOccurrenceDateTime(const QDateTime &qd)
Update the date of this item's occurrence (not in the event)
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 addDays(qint64 ndays) const const
QDateTime addDuration(std::chrono::milliseconds msecs) 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()