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({});
250 layout->addWidget(mCalendarNameLabel);
253 auto *daysWidget =
new QWidget(
this);
254 layout->addWidget(daysWidget);
257 daysLayout->setContentsMargins({});
258 daysLayout->setSpacing(SPACING);
260 if (!mIsSideBySide) {
261 mWeekLabelBox =
new QWidget(daysWidget);
262 auto weekLabelBoxLayout =
new QVBoxLayout(mWeekLabelBox);
263 weekLabelBoxLayout->setContentsMargins({});
264 weekLabelBoxLayout->setSpacing(0);
265 daysLayout->addWidget(mWeekLabelBox);
268 mDayLabels =
new QWidget(daysWidget);
269 mDayLabelsLayout =
new AgendaHeaderLayout(mDayLabels);
270 mDayLabelsLayout->setContentsMargins({});
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({});
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()
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({});
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({});
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({});
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({});
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()
1230 for (
const ViewCalendar::Ptr &cal : std::as_const(d->mViewCalendar->mSubCalendars)) {
1231 if (cal->getCalendar()) {
1232 cal->getCalendar()->unregisterObserver(d.get());
1237void AgendaView::addCalendar(
const Akonadi::CollectionCalendar::Ptr &calendar)
1239 EventView::addCalendar(calendar);
1241 if (!d->mViewCalendar->calendarForCollection(calendar->collection()).isNull()) {
1246 view->mCalendar = calendar;
1247 view->mAgendaView =
this;
1251void AgendaView::removeCalendar(
const Akonadi::CollectionCalendar::Ptr &calendar)
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);
1636 if (startDt == endDt) {
1637 QTime defaultDuration(CalendarSupport::KCalPrefs::instance()->defaultDuration().time());
1638 endDt = endDt.
addDuration(std::chrono::hours(defaultDuration.
hour()) + std::chrono::minutes(defaultDuration.
minute()));
1657 return secs <= 24 * 60 * 60 / d->mAgenda->rows();
1661void AgendaView::updateView()
1670void AgendaView::updateConfig()
1674 if (d->mAgenda && d->mAllDayAgenda) {
1675 d->mAgenda->updateConfig();
1676 d->mAllDayAgenda->updateConfig();
1677 d->mTimeLabelsZone->setPreferences(preferences());
1678 d->mTimeLabelsZone->updateAll();
1679 updateTimeBarWidth();
1687void AgendaView::createTimeBarHeaders()
1689 qDeleteAll(d->mTimeBarHeaders);
1690 d->mTimeBarHeaders.clear();
1693 QFont labelFont = d->mTimeLabelsZone->preferences()->agendaTimeLabelsFont();
1696 const auto lst = d->mTimeLabelsZone->timeLabels();
1698 auto timeLabel =
static_cast<TimeLabels *
>(area->widget());
1699 auto label =
new QLabel(timeLabel->header().replace(
QLatin1Char(
'/'), QStringLiteral(
"/ ")), d->mTimeBarHeaderFrame);
1700 d->mTimeBarHeaderFrame->layout()->addWidget(label);
1701 label->setFont(labelFont);
1703 label->setContentsMargins({});
1704 label->setWordWrap(
true);
1705 label->setToolTip(timeLabel->headerToolTip());
1706 d->mTimeBarHeaders.append(label);
1711void AgendaView::updateTimeBarWidth()
1713 if (d->mIsSideBySide) {
1717 createTimeBarHeaders();
1720 QFont labelFont = d->mTimeLabelsZone->preferences()->agendaTimeLabelsFont();
1724 int width = d->mTimeLabelsZone->preferedTimeLabelsWidth();
1725 for (
QLabel *l : std::as_const(d->mTimeBarHeaders)) {
1726 const auto lst = l->text().split(
QLatin1Char(
' '));
1727 for (
const QString &word : lst) {
1728 width = qMax(
width, fm.boundingRect(word).width());
1735 const int timeBarWidth =
width * d->mTimeBarHeaders.count();
1737 d->mTimeBarHeaderFrame->setFixedWidth(timeBarWidth - SPACING);
1738 d->mTimeLabelsZone->setFixedWidth(timeBarWidth);
1739 if (d->mDummyAllDayLeft) {
1740 d->mDummyAllDayLeft->setFixedWidth(0);
1743 d->mTopDayLabelsFrame->setWeekWidth(timeBarWidth);
1744 d->mBottomDayLabelsFrame->setWeekWidth(timeBarWidth);
1768 qCDebug(CALENDARVIEW_LOG) << item->text() <<
"; item->cellXLeft(): " << item->cellXLeft() <<
"; item->cellYTop(): " << item->cellYTop()
1769 <<
"; item->lastMultiItem(): " << item->lastMultiItem() <<
"; item->itemPos(): " << item->itemPos()
1770 <<
"; item->itemCount(): " << item->itemCount();
1780 if (item->cellXLeft() < 0) {
1781 thisDate = (d->mSelectedDates.first()).
addDays(item->cellXLeft());
1783 thisDate = d->mSelectedDates[item->cellXLeft()];
1789 if (item->cellXLeft() >= 0) {
1790 daysOffset = item->occurrenceDate().
daysTo(thisDate);
1797 if ((!aitem.
isValid() && !addIncidence) || !incidence || !changer()) {
1798 qCWarning(CALENDARVIEW_LOG) <<
"changer is " << changer() <<
" and incidence is " << incidence.
data();
1802 QTime startTime(0, 0, 0);
1803 QTime endTime(0, 0, 0);
1804 if (incidence->allDay()) {
1805 daysLength = item->cellWidth() - 1;
1807 startTime = d->mAgenda->gyToTime(item->cellYTop());
1808 if (item->lastMultiItem()) {
1809 endTime = d->mAgenda->gyToTime(item->lastMultiItem()->cellYBottom() + 1);
1810 daysLength = item->lastMultiItem()->cellXLeft() - item->cellXLeft();
1811 }
else if (item->itemPos() == item->itemCount() && item->itemCount() > 1) {
1822 endTime = d->mAgenda->gyToTime(item->cellYBottom() + 1);
1823 daysLength = item->itemCount() - 1;
1824 startTime = incidence->dtStart().time();
1825 }
else if (item->itemPos() == 1 && item->itemCount() > 1) {
1828 daysLength = item->itemCount() - 1;
1830 endTime = d->mAgenda->gyToTime(item->cellYBottom() + 1);
1836 startDt = incidence->dtStart();
1840 startDt = startDt.
addDays(daysOffset);
1841 if (!incidence->allDay()) {
1844 endDt = startDt.
addDays(daysLength);
1845 if (!incidence->allDay()) {
1848 if (incidence->dtStart().toLocalTime() == startDt && ev->dtEnd().
toLocalTime() == endDt) {
1860 incidence->setDtStart(copyTimeSpec(startDt, incidence->dtStart()));
1863 endDt.
setTime(td->allDay() ?
QTime(00, 00, 00) : endTime);
1865 if (td->dtDue(
true).toLocalTime() == endDt) {
1871 const auto shift = td->dtDue(
true).secsTo(endDt);
1872 startDt = td->dtStart(
true).
addSecs(shift);
1873 if (td->hasStartDate()) {
1874 td->setDtStart(copyTimeSpec(startDt, incidence->dtStart()));
1877 td->setDtRecurrence(td->dtRecurrence().addSecs(shift));
1879 td->setDtDue(copyTimeSpec(endDt, td->dtDue()),
true);
1882 if (!incidence->hasRecurrenceId()) {
1889 result = changer()->createIncidence(incidence, collection,
this) != -1;
1893 result = changer()->modifyIncidence(aitem, oldIncidence,
this) != -1;
1907 enableAgendaUpdate(
false);
1912 if (incidence->recurs() || incidence->hasRecurrenceId()) {
1913 d->mUpdateItem = aitem;
1917 enableAgendaUpdate(
true);
1922 if (d->mSelectedDates.isEmpty()) {
1925 return d->mSelectedDates.first();
1930 if (d->mSelectedDates.isEmpty()) {
1933 return d->mSelectedDates.last();
1938 Q_UNUSED(preferredMonth)
1939 if (!d->mSelectedDates.isEmpty() && d->mSelectedDates.first() ==
start && d->mSelectedDates.last() == end) {
1943 if (!
start.isValid() || !end.isValid() ||
start > end ||
start.daysTo(end) > MAX_DAY_COUNT) {
1944 qCWarning(CALENDARVIEW_LOG) <<
"got bizarre parameters: " <<
start << end <<
" - aborting here";
1948 d->mSelectedDates = d->generateDateList(
start, end);
1953 d->mTimeLabelsZone->update();
1965 const auto &cal = d->mViewCalendar->calendarForCollection(aitem.storageCollectionId());
1966 if (cal && cal->filter()) {
1969 cal->setFilter(
nullptr);
1980 end.toTimeZone(
start.timeZone());
1987 d->mAgenda->selectItem(first);
1992 if (
changes() == NothingChanged) {
1996 const QString selectedAgendaId = d->mAgenda->lastSelectedItemUid();
1997 const QString selectedAllDayAgendaId = d->mAllDayAgenda->lastSelectedItemUid();
1999 enableAgendaUpdate(
true);
2002 if (d->mViewCalendar->calendarCount() == 0) {
2013 if (
changes().testFlag(DatesChanged)) {
2014 d->mAllDayAgenda->changeColumns(d->mSelectedDates.count());
2015 d->mAgenda->changeColumns(d->mSelectedDates.count());
2016 d->changeColumns(d->mSelectedDates.count());
2021 d->mAgenda->setDateList(d->mSelectedDates);
2026 bool somethingReselected =
false;
2030 Q_ASSERT(incidence);
2031 const bool wasSelected = (incidence->uid() == selectedAgendaId) || (incidence->uid() == selectedAllDayAgendaId);
2033 if ((incidence->allDay() && d->mUpdateAllDayAgenda) || (!incidence->allDay() && d->mUpdateAgenda)) {
2034 displayIncidence(incidence, wasSelected);
2038 somethingReselected =
true;
2042 d->mAgenda->checkScrollBoundaries();
2051 d->mUpdateAgenda =
false;
2052 d->mUpdateAllDayAgenda =
false;
2054 if (!somethingReselected) {
2065 if (incidence->hasRecurrenceId()) {
2069 if (cal && cal->incidence(incidence->uid())) {
2075 if (todo && (!preferences()->showTodosAgendaView() || !
todo->hasDueDate())) {
2086 if (!d->mightBeVisible(incidence)) {
2090 std::vector<QDateTime> dateTimeList;
2095 bool alreadyAddedToday =
false;
2101 const int secsToAdd =
incidence->allDay() ? 0 : -1;
2102 const int eventDuration =
event ? incDtStart.
daysTo(incDtEnd.
addSecs(secsToAdd)) : 0;
2107 const QDateTime startDateTimeWithOffset = firstVisibleDateTime.
addDays(-eventDuration);
2110 while (rIt.hasNext()) {
2112 auto occurrenceDate = rIt.occurrenceStartDate().toLocalTime();
2113 if (
const auto todo = CalendarSupport::todo(rIt.incidence())) {
2115 occurrenceDate = occurrenceDate.addSecs(
todo->dtStart().secsTo(
todo->dtDue()));
2117 const bool makesDayBusy = preferences()->colorAgendaBusyDays() && makesWholeDayBusy(rIt.incidence());
2123 if (occurrenceDate.date() == today) {
2124 alreadyAddedToday =
true;
2126 d->insertIncidence(rIt.incidence(), rIt.recurrenceId(), occurrenceDate, createSelected);
2132 if (todo &&
todo->hasDueDate() && !
todo->isOverdue()) {
2134 dateToAdd =
todo->dtDue().toLocalTime();
2139 dateToAdd = dateToAdd.
addSecs(-1);
2142 incidenceEnd = dateToAdd;
2144 dateToAdd = incDtStart;
2145 incidenceEnd = incDtEnd;
2154 if (dateToAdd <= lastVisibleDateTime && incidenceEnd > firstVisibleDateTime) {
2155 dateTimeList.push_back(dateToAdd);
2161 if (todo &&
todo->isOverdue() && dateTimeToday >= firstVisibleDateTime && dateTimeToday <= lastVisibleDateTime) {
2164 if (!alreadyAddedToday) {
2165 dateTimeList.push_back(dateTimeToday);
2169 const bool makesDayBusy = preferences()->colorAgendaBusyDays() && makesWholeDayBusy(incidence);
2170 for (
auto t = dateTimeList.begin(); t != dateTimeList.end(); ++t) {
2176 d->insertIncidence(incidence, t->toLocalTime(), t->toLocalTime(), createSelected);
2180 if (
event && makesDayBusy &&
event->isMultiDay()) {
2181 const QDate lastVisibleDate = d->mSelectedDates.last();
2182 for (
QDate date =
event->dtStart().date(); date <= event->dtEnd().date() && date <= lastVisibleDate; date = date.
addDays(1)) {
2188 return !dateTimeList.empty();
2191void AgendaView::updateEventIndicatorTop(
int newY)
2193 for (
int i = 0; i < d->mMinY.size(); ++i) {
2194 d->mEventIndicatorTop->enableColumn(i, newY > d->mMinY[i]);
2196 d->mEventIndicatorTop->update();
2199void AgendaView::updateEventIndicatorBottom(
int newY)
2201 for (
int i = 0; i < d->mMaxY.size(); ++i) {
2202 d->mEventIndicatorBottom->enableColumn(i, newY <= d->mMaxY[i]);
2204 d->mEventIndicatorBottom->update();
2213#ifdef AKONADI_PORT_DISABLED
2215 if (gpos.
x() < 0 || gpos.
y() < 0) {
2219 const QDate day = d->mSelectedDates[gpos.
x()];
2220 const QTime time = d->mAgenda->gyToTime(gpos.
y());
2221 KDateTime newTime(day, time, preferences()->timeSpec());
2222 newTime.setDateOnly(allDay);
2224 Todo::Ptr
todo = Akonadi::CalendarUtils4::todo(todoItem);
2229 qCDebug(CALENDARVIEW_LOG) <<
"Drop existing Todo";
2230 Todo::Ptr oldTodo(existingTodo->clone());
2232 existingTodo->setDtDue(newTime);
2233 existingTodo->setAllDay(allDay);
2234 changer()->modifyIncidence(existingTodoItem, oldTodo,
this);
2237 i18n(
"Unable to modify this to-do, "
2238 "because it cannot be locked."));
2241 qCDebug(CALENDARVIEW_LOG) <<
"Drop new Todo";
2242 todo->setDtDue(newTime);
2243 todo->setAllDay(allDay);
2244 if (!changer()->addIncidence(todo,
this)) {
2250 qCDebug(CALENDARVIEW_LOG) <<
"AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
2258 if (
auto todo = CalendarSupport::todo(incidence)) {
2263 auto duration =
todo->dtStart().daysTo(
todo->dtDue());
2264 dtStart = dt.
addDays(-duration);
2268 todo->setDtDue(dt,
true);
2269 todo->setDtStart(dtStart);
2270 }
else if (
auto event = CalendarSupport::event(incidence)) {
2271 auto duration =
event->dtStart().secsTo(
event->dtEnd());
2272 if (duration == 0) {
2273 auto defaultDuration = CalendarSupport::KCalPrefs::instance()->defaultDuration().time();
2274 duration = (defaultDuration.hour() * 3600) + (defaultDuration.minute() * 60);
2276 event->setDtEnd(dt.
addSecs(duration));
2277 event->setDtStart(dt);
2285 if (gpos.
x() < 0 || gpos.
y() < 0) {
2289 const QDate day = d->mSelectedDates[gpos.
x()];
2290 const QTime time = d->mAgenda->gyToTime(gpos.
y());
2294 const Akonadi::Item existingItem = d->mViewCalendar->item(incidence);
2295 const bool existsInSameCollection = existingItem.
isValid();
2297 if (existingItem.
isValid() && existsInSameCollection) {
2300 if (newIncidence->dtStart() == newTime && newIncidence->allDay() == allDay) {
2306 setDateTime(newIncidence, newTime, allDay);
2308 (void)changer()->modifyIncidence(existingItem, oldIncidence,
this);
2311 setDateTime(incidence, newTime, allDay);
2314 const bool added = -1 != changer()->createIncidence(incidence,
Akonadi::Collection(),
this);
2319 (void)changer()->deleteIncidence(existingItem);
2328 const Akonadi::Item item = d->mViewCalendar->item(incidence);
2336 if (
QDrag *drag = CalendarSupport::createDrag(incidence,
this)) {
2341void AgendaView::readSettings()
2344 readSettings(config.data());
2347void AgendaView::readSettings(
const KConfig *config)
2356 d->mSplitterAgenda->setSizes(sizes);
2361void AgendaView::writeSettings(
KConfig *config)
2366 group.
writeEntry(
"Separator AgendaView", list);
2371 if (d->mSelectedDates.isEmpty() || !d->mSelectedDates[0].isValid()) {
2376 busyDayMask.
resize(d->mSelectedDates.count());
2378 for (
int i = 0; i < d->mSelectedDates.count(); ++i) {
2379 busyDayMask[i] = !d->mBusyDays[d->mSelectedDates[i]].isEmpty();
2387 if (d->mSelectedDates.isEmpty() || !d->mSelectedDates[0].isValid()) {
2391 d->mHolidayMask.resize(d->mSelectedDates.count() + 1);
2393 const QList<QDate> workDays = CalendarSupport::workDays(d->mSelectedDates.constFirst().addDays(-1), d->mSelectedDates.last());
2394 for (
int i = 0; i < d->mSelectedDates.count(); ++i) {
2395 d->mHolidayMask[i] = !workDays.
contains(d->mSelectedDates[i]);
2400 bool showDay = !workDays.
contains(d->mSelectedDates[0].addDays(-1));
2401 d->mHolidayMask[d->mSelectedDates.count()] = showDay;
2403 d->mAgenda->setHolidayMask(&d->mHolidayMask);
2404 d->mAllDayAgenda->setHolidayMask(&d->mHolidayMask);
2409 d->mAgenda->deselectItem();
2410 d->mAllDayAgenda->deselectItem();
2416 d->mTimeSpanInAllDay =
true;
2421 if (d->mSelectedDates.isEmpty()) {
2425 d->mTimeSpanInAllDay =
false;
2427 const QDate dayStart = d->mSelectedDates[qBound(0,
start.x(), (
int)d->mSelectedDates.size() - 1)];
2428 const QDate dayEnd = d->mSelectedDates[qBound(0, end.x(), (
int)d->mSelectedDates.size() - 1)];
2430 const QTime timeStart = d->mAgenda->gyToTime(
start.y());
2431 const QTime timeEnd = d->mAgenda->gyToTime(end.y() + 1);
2433 d->mTimeSpanBegin =
QDateTime(dayStart, timeStart);
2434 d->mTimeSpanEnd =
QDateTime(dayEnd, timeEnd);
2439 return d->mTimeSpanBegin;
2444 return d->mTimeSpanEnd;
2449 return d->mTimeSpanInAllDay;
2454 d->mTimeSpanBegin.setDate(
QDate());
2455 d->mTimeSpanEnd.setDate(
QDate());
2456 d->mTimeSpanInAllDay =
false;
2463 d->mAllDayAgenda->removeIncidence(incidence);
2464 d->mAgenda->removeIncidence(incidence);
2466 if (!incidence->hasRecurrenceId() && d->mViewCalendar->isValid(incidence->uid())) {
2469 const auto cal =
calendar2(incidence->uid());
2473 if (exception->allDay()) {
2474 d->mAllDayAgenda->removeIncidence(exception);
2476 d->mAgenda->removeIncidence(exception);
2485 d->mUpdateEventIndicatorsScheduled =
false;
2486 d->mMinY = d->mAgenda->minContentsY();
2487 d->mMaxY = d->mAgenda->maxContentsY();
2489 d->mAgenda->checkScrollBoundaries();
2490 updateEventIndicatorTop(d->mAgenda->visibleContentsYMin());
2491 updateEventIndicatorBottom(d->mAgenda->visibleContentsYMax());
2497 d->mAgenda->setIncidenceChanger(changer);
2498 d->mAllDayAgenda->setIncidenceChanger(changer);
2501void AgendaView::clearTimeSpanSelection()
2503 d->mAgenda->clearSelection();
2504 d->mAllDayAgenda->clearSelection();
2508Agenda *AgendaView::agenda()
const
2513Agenda *AgendaView::allDayAgenda()
const
2515 return d->mAllDayAgenda;
2520 return d->mSplitterAgenda;
2525 Q_UNUSED(incidence);
2542void AgendaView::alignAgendas()
2545 if (d->mDummyAllDayLeft) {
2546 d->mDummyAllDayLeft->setFixedWidth(d->mTimeLabelsZone->width() - d->mTimeBarHeaderFrame->width() - SPACING);
2558void AgendaView::setTitle(
const QString &title)
2560 d->mTopDayLabelsFrame->setCalendarName(title);
2563void AgendaView::scheduleUpdateEventIndicators()
2565 if (!d->mUpdateEventIndicatorsScheduled) {
2566 d->mUpdateEventIndicatorsScheduled =
true;
2571#include "agendaview.moc"
2573#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)
Namespace EventViews provides facilities for displaying incidences, including events,...
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
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()