File indexing completed on 2025-03-09 04:45:09
0001 /* 0002 SPDX-FileCopyrightText: 1999 Preston Brown <pbrown@kde.org> 0003 SPDX-FileCopyrightText: 2000, 2001 Cornelius Schumacher <schumacher@kde.org> 0004 SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 0005 SPDX-FileCopyrightText: 2010 Sérgio Martins <iamsergio@gmail.com> 0006 SPDX-FileCopyrightText: 2012-2013 Allen Winter <winter@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0009 */ 0010 0011 // TODO: put a reminder and/or recurs icon on the item? 0012 0013 #include "listview.h" 0014 #include "helper.h" 0015 0016 #include <CalendarSupport/Utils> 0017 0018 #include <Akonadi/CalendarUtils> 0019 #include <Akonadi/IncidenceChanger> 0020 0021 #include <KCalUtils/IncidenceFormatter> 0022 #include <KCalendarCore/Visitor> 0023 0024 #include <KConfig> 0025 #include <KConfigGroup> 0026 0027 #include "calendarview_debug.h" 0028 #include <QBoxLayout> 0029 #include <QHeaderView> 0030 #include <QIcon> 0031 #include <QLocale> 0032 #include <QTreeWidget> 0033 0034 using namespace EventViews; 0035 using namespace KCalendarCore; 0036 using namespace KCalUtils; 0037 0038 enum { 0039 Summary_Column = 0, 0040 StartDateTime_Column, 0041 EndDateTime_Column, 0042 Categories_Column, 0043 Dummy_EOF_Column // Dummy enum value for iteration purposes only. Always keep at the end. 0044 }; 0045 0046 static const QTime DAY_START{00, 00}; 0047 static const QTime DAY_END{23, 59, 59, 999}; 0048 0049 static QString cleanSummary(const QString &summary, const QDateTime &next) 0050 { 0051 QString retStr = summary; 0052 retStr.replace(QLatin1Char('\n'), QLatin1Char(' ')); 0053 0054 if (next.isValid()) { 0055 const QString dateStr = QLocale().toString(next.date(), QLocale::ShortFormat); 0056 retStr = i18nc("%1 is an item summary. %2 is the date when this item reoccurs", "%1 (next: %2)", retStr, dateStr); 0057 } 0058 return retStr; 0059 } 0060 0061 class ListViewItem : public QTreeWidgetItem 0062 { 0063 public: 0064 ListViewItem(const Akonadi::Item &incidence, const Akonadi::CollectionCalendar::Ptr &calendar, QTreeWidget *parent) 0065 : QTreeWidgetItem(parent) 0066 , mTreeWidget(parent) 0067 , mIncidence(incidence) 0068 , mCalendar(calendar) 0069 { 0070 } 0071 0072 QVariant data(int column, int role) const override 0073 { 0074 if (role == Qt::ToolTipRole) { 0075 const auto incidence = mIncidence.payload<KCalendarCore::Incidence::Ptr>(); 0076 return IncidenceFormatter::toolTipStr(Akonadi::CalendarUtils::displayName(mCalendar->model(), mIncidence.parentCollection()), 0077 incidence, 0078 start.date()); 0079 } 0080 0081 return QTreeWidgetItem::data(column, role); 0082 } 0083 0084 bool operator<(const QTreeWidgetItem &other) const override; 0085 0086 QTreeWidget *const mTreeWidget; 0087 const Akonadi::Item mIncidence; 0088 QDateTime start; 0089 QDateTime end; 0090 Akonadi::CollectionCalendar::Ptr mCalendar; 0091 }; 0092 0093 bool ListViewItem::operator<(const QTreeWidgetItem &other) const 0094 { 0095 const auto otheritem = static_cast<const ListViewItem *>(&other); 0096 0097 switch (treeWidget()->sortColumn()) { 0098 case StartDateTime_Column: 0099 // Missing start times are sorted before any defined time. 0100 return otheritem->start.isValid() && (!start.isValid() || start < otheritem->start); 0101 case EndDateTime_Column: 0102 // Missing end times are sorted after any defined time. 0103 return end.isValid() && (!otheritem->end.isValid() || end < otheritem->end); 0104 default: 0105 return QTreeWidgetItem::operator<(other); 0106 } 0107 } 0108 0109 class EventViews::ListViewPrivate 0110 { 0111 public: 0112 ListViewPrivate() = default; 0113 0114 ~ListViewPrivate() = default; 0115 0116 void addIncidences(const Akonadi::CollectionCalendar::Ptr &calendar, const KCalendarCore::Incidence::List &incidenceList, QDate date); 0117 void addIncidence(const Akonadi::CollectionCalendar::Ptr &calendar, const KCalendarCore::Incidence::Ptr &, QDate date); 0118 void addIncidence(const Akonadi::CollectionCalendar::Ptr &calendar, const Akonadi::Item &, QDate date); 0119 ListViewItem *getItemForIncidence(const Akonadi::Item &); 0120 0121 QTreeWidget *mTreeWidget = nullptr; 0122 ListViewItem *mActiveItem = nullptr; 0123 QHash<Akonadi::Item::Id, Akonadi::Item> mItems; 0124 QHash<Akonadi::Item::Id, QDate> mDateList; 0125 QDate mStartDate; 0126 QDate mEndDate; 0127 DateList mSelectedDates; 0128 int mSortColumn = StartDateTime_Column; 0129 Qt::SortOrder mSortOrder = Qt::AscendingOrder; 0130 0131 // if it's non interactive we disable context menu, and incidence editing 0132 bool mIsNonInteractive; 0133 class ListItemVisitor; 0134 }; 0135 0136 /** 0137 This class provides the initialization of a ListViewItem for calendar 0138 components using the Incidence::Visitor. 0139 */ 0140 class ListViewPrivate::ListItemVisitor : public KCalendarCore::Visitor 0141 { 0142 public: 0143 ListItemVisitor(ListViewItem *item, QDate dt) 0144 : mItem(item) 0145 , mStartDate(dt) 0146 { 0147 } 0148 0149 ~ListItemVisitor() override = default; 0150 0151 bool visit(const Event::Ptr &) override; 0152 bool visit(const Todo::Ptr &) override; 0153 bool visit(const Journal::Ptr &) override; 0154 bool visit(const FreeBusy::Ptr &) override 0155 { 0156 // to inhibit hidden virtual compile warning 0157 return true; 0158 } 0159 0160 private: 0161 ListViewItem *mItem = nullptr; 0162 QDate mStartDate; 0163 }; 0164 0165 bool ListViewPrivate::ListItemVisitor::visit(const Event::Ptr &e) 0166 { 0167 QIcon eventPxmp; 0168 if (e->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) { 0169 eventPxmp = QIcon::fromTheme(QStringLiteral("view-calendar-wedding-anniversary")); 0170 } else if (e->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES")) { 0171 eventPxmp = QIcon::fromTheme(QStringLiteral("view-calendar-birthday")); 0172 } else { 0173 eventPxmp = QIcon::fromTheme(e->iconName()); 0174 } 0175 mItem->setIcon(Summary_Column, eventPxmp); 0176 0177 QDateTime next; 0178 if (e->recurs()) { 0179 const qint64 duration = e->dtStart().secsTo(e->dtEnd()); 0180 QDateTime kdt(mStartDate, DAY_START); 0181 kdt = kdt.addMSecs(-1); 0182 mItem->start = e->recurrence()->getNextDateTime(kdt).toLocalTime(); 0183 mItem->end = mItem->start.addSecs(duration); 0184 next = e->recurrence()->getNextDateTime(mItem->start).toLocalTime(); 0185 } else { 0186 mItem->start = e->dtStart().toLocalTime(); 0187 mItem->end = e->dtEnd().toLocalTime(); 0188 } 0189 0190 mItem->setText(Summary_Column, cleanSummary(e->summary(), next)); 0191 0192 if (e->allDay()) { 0193 mItem->start.setTime(DAY_START); 0194 mItem->end.setTime(DAY_END); 0195 mItem->setText(StartDateTime_Column, QLocale().toString(mItem->start.date(), QLocale::ShortFormat)); 0196 mItem->setText(EndDateTime_Column, QLocale().toString(mItem->end.date(), QLocale::ShortFormat)); 0197 } else { 0198 mItem->setText(StartDateTime_Column, QLocale().toString(mItem->start, QLocale::ShortFormat)); 0199 mItem->setText(EndDateTime_Column, QLocale().toString(mItem->end, QLocale::ShortFormat)); 0200 } 0201 0202 mItem->setText(Categories_Column, e->categoriesStr()); 0203 0204 return true; 0205 } 0206 0207 bool ListViewPrivate::ListItemVisitor::visit(const Todo::Ptr &t) 0208 { 0209 mItem->setIcon(Summary_Column, QIcon::fromTheme(t->iconName())); 0210 0211 if (t->recurs()) { 0212 QDateTime kdt(mStartDate, DAY_START); 0213 kdt = kdt.addMSecs(-1); 0214 mItem->start = t->recurrence()->getNextDateTime(kdt).toLocalTime(); 0215 if (t->hasDueDate()) { 0216 const qint64 duration = t->dtStart().secsTo(t->dtDue()); 0217 mItem->end = mItem->start.addSecs(duration); 0218 } else { 0219 mItem->end = QDateTime(); 0220 } 0221 } else { 0222 mItem->start = t->hasStartDate() ? t->dtStart().toLocalTime() : QDateTime(); 0223 mItem->end = t->hasDueDate() ? t->dtDue().toLocalTime() : QDateTime(); 0224 } 0225 if (t->allDay()) { 0226 mItem->start.setTime(DAY_START); 0227 mItem->end.setTime(DAY_END); 0228 } 0229 0230 mItem->setText(Summary_Column, cleanSummary(t->summary(), QDateTime())); 0231 0232 if (t->hasStartDate()) { 0233 if (t->allDay()) { 0234 mItem->setText(StartDateTime_Column, QLocale().toString(t->dtStart().toLocalTime().date(), QLocale::ShortFormat)); 0235 } else { 0236 mItem->setText(StartDateTime_Column, QLocale().toString(t->dtStart().toLocalTime(), QLocale::ShortFormat)); 0237 } 0238 } else { 0239 mItem->setText(StartDateTime_Column, QStringLiteral("---")); 0240 } 0241 0242 if (t->hasDueDate()) { 0243 if (t->allDay()) { 0244 mItem->setText(EndDateTime_Column, QLocale().toString(t->dtDue().toLocalTime().date(), QLocale::ShortFormat)); 0245 } else { 0246 mItem->setText(EndDateTime_Column, QLocale().toString(t->dtDue().toLocalTime(), QLocale::ShortFormat)); 0247 } 0248 } else { 0249 mItem->setText(EndDateTime_Column, QStringLiteral("---")); 0250 } 0251 mItem->setText(Categories_Column, t->categoriesStr()); 0252 0253 return true; 0254 } 0255 0256 bool ListViewPrivate::ListItemVisitor::visit(const Journal::Ptr &j) 0257 { 0258 mItem->setIcon(Summary_Column, QIcon::fromTheme(j->iconName())); 0259 0260 mItem->start = j->dtStart(); 0261 mItem->end = QDateTime(); 0262 0263 if (j->summary().isEmpty()) { 0264 mItem->setText(Summary_Column, cleanSummary(j->description().section(QLatin1Char('\n'), 0, 0), QDateTime())); 0265 } else { 0266 mItem->setText(Summary_Column, cleanSummary(j->summary(), QDateTime())); 0267 } 0268 if (j->allDay()) { 0269 mItem->start.setTime(DAY_START); 0270 mItem->setText(StartDateTime_Column, QLocale().toString(j->dtStart().toLocalTime().date(), QLocale::ShortFormat)); 0271 } else { 0272 mItem->setText(StartDateTime_Column, QLocale().toString(j->dtStart().toLocalTime(), QLocale::ShortFormat)); 0273 } 0274 mItem->setText(EndDateTime_Column, QStringLiteral("---")); 0275 mItem->setText(Categories_Column, j->categoriesStr()); 0276 0277 return true; 0278 } 0279 0280 ListView::ListView(QWidget *parent, bool nonInteractive) 0281 : EventView(parent) 0282 , d(std::make_unique<ListViewPrivate>()) 0283 { 0284 d->mActiveItem = nullptr; 0285 d->mIsNonInteractive = nonInteractive; 0286 0287 d->mTreeWidget = new QTreeWidget(this); 0288 d->mTreeWidget->setColumnCount(4); 0289 d->mTreeWidget->setSortingEnabled(true); 0290 d->mTreeWidget->headerItem()->setText(Summary_Column, i18n("Summary")); 0291 d->mTreeWidget->headerItem()->setText(StartDateTime_Column, i18n("Start Date/Time")); 0292 d->mTreeWidget->headerItem()->setText(EndDateTime_Column, i18n("End Date/Time")); 0293 d->mTreeWidget->headerItem()->setText(Categories_Column, i18n("Tags")); 0294 0295 d->mTreeWidget->setWordWrap(true); 0296 d->mTreeWidget->setAllColumnsShowFocus(true); 0297 d->mTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); 0298 d->mTreeWidget->setRootIsDecorated(false); 0299 0300 QBoxLayout *layoutTop = new QVBoxLayout(this); 0301 layoutTop->setContentsMargins(0, 0, 0, 0); 0302 layoutTop->addWidget(d->mTreeWidget); 0303 0304 QObject::connect(d->mTreeWidget, 0305 qOverload<const QModelIndex &>(&QTreeWidget::doubleClicked), 0306 this, 0307 qOverload<const QModelIndex &>(&ListView::defaultItemAction)); 0308 QObject::connect(d->mTreeWidget, &QTreeWidget::customContextMenuRequested, this, &ListView::popupMenu); 0309 QObject::connect(d->mTreeWidget, &QTreeWidget::itemSelectionChanged, this, &ListView::processSelectionChange); 0310 QObject::connect(d->mTreeWidget->header(), &QHeaderView::sortIndicatorChanged, this, &ListView::slotSortIndicatorChanged); 0311 0312 d->mSelectedDates.append(QDate::currentDate()); 0313 0314 updateView(); 0315 } 0316 0317 ListView::~ListView() = default; 0318 0319 int ListView::currentDateCount() const 0320 { 0321 return d->mSelectedDates.count(); 0322 } 0323 0324 Akonadi::Item::List ListView::selectedIncidences() const 0325 { 0326 Akonadi::Item::List eventList; 0327 QTreeWidgetItem *item = d->mTreeWidget->selectedItems().isEmpty() ? nullptr : d->mTreeWidget->selectedItems().first(); 0328 if (item) { 0329 auto i = static_cast<ListViewItem *>(item); 0330 eventList.append(i->mIncidence); 0331 } 0332 return eventList; 0333 } 0334 0335 DateList ListView::selectedIncidenceDates() const 0336 { 0337 return d->mSelectedDates; 0338 } 0339 0340 void ListView::updateView() 0341 { 0342 static int maxLen = 38; 0343 0344 /* Set the width of the summary column to show 'maxlen' chars, at most */ 0345 int width = qMin(maxLen * fontMetrics().averageCharWidth(), maxLen * 12); 0346 width += 24; // for the icon 0347 0348 d->mTreeWidget->setColumnWidth(Summary_Column, width); 0349 for (int col = StartDateTime_Column; col < Dummy_EOF_Column; ++col) { 0350 d->mTreeWidget->resizeColumnToContents(col); 0351 } 0352 d->mTreeWidget->sortItems(d->mSortColumn, d->mSortOrder); 0353 } 0354 0355 void ListView::showDates(const QDate &start, const QDate &end, const QDate &preferredMonth) 0356 { 0357 Q_UNUSED(preferredMonth) 0358 clear(); 0359 0360 d->mStartDate = start; 0361 d->mEndDate = end; 0362 0363 const QString startStr = QLocale().toString(start, QLocale::ShortFormat); 0364 const QString endStr = QLocale().toString(end, QLocale::ShortFormat); 0365 0366 d->mTreeWidget->headerItem()->setText(Summary_Column, i18n("Summary [%1 - %2]", startStr, endStr)); 0367 0368 QDate date = start; 0369 while (date <= end) { 0370 for (const auto &calendar : calendars()) { 0371 d->addIncidences(calendar, calendar->incidences(date), date); 0372 } 0373 d->mSelectedDates.append(date); 0374 date = date.addDays(1); 0375 } 0376 0377 updateView(); 0378 0379 Q_EMIT incidenceSelected(Akonadi::Item(), QDate()); 0380 } 0381 0382 void ListView::showAll() 0383 { 0384 for (const auto &calendar : calendars()) { 0385 d->addIncidences(calendar, calendar->incidences(), QDate()); 0386 } 0387 } 0388 0389 void ListViewPrivate::addIncidences(const Akonadi::CollectionCalendar::Ptr &calendar, const KCalendarCore::Incidence::List &incidences, QDate date) 0390 { 0391 for (const KCalendarCore::Incidence::Ptr &incidence : incidences) { 0392 addIncidence(calendar, incidence, date); 0393 } 0394 } 0395 0396 void ListViewPrivate::addIncidence(const Akonadi::CollectionCalendar::Ptr &calendar, const Akonadi::Item &item, QDate date) 0397 { 0398 Q_ASSERT(calendar); 0399 if (item.isValid() && item.hasPayload<KCalendarCore::Incidence::Ptr>()) { 0400 addIncidence(calendar, item.payload<KCalendarCore::Incidence::Ptr>(), date); 0401 } 0402 } 0403 0404 void ListViewPrivate::addIncidence(const Akonadi::CollectionCalendar::Ptr &calendar, const KCalendarCore::Incidence::Ptr &incidence, QDate date) 0405 { 0406 if (!incidence) { 0407 return; 0408 } 0409 0410 Akonadi::Item aitem = calendar->item(incidence); 0411 0412 if (!aitem.isValid() || mItems.contains(aitem.id())) { 0413 return; 0414 } 0415 0416 mDateList.insert(aitem.id(), date); 0417 mItems.insert(aitem.id(), aitem); 0418 Incidence::Ptr tinc = incidence; 0419 0420 if (tinc->customProperty("KABC", "BIRTHDAY") == QLatin1StringView("YES") || tinc->customProperty("KABC", "ANNIVERSARY") == QLatin1StringView("YES")) { 0421 const int years = EventViews::yearDiff(tinc->dtStart().date(), mEndDate); 0422 if (years > 0) { 0423 tinc = Incidence::Ptr(incidence->clone()); 0424 tinc->setReadOnly(false); 0425 tinc->setSummary(i18np("%2 (1 year)", "%2 (%1 years)", years, cleanSummary(incidence->summary(), QDateTime()))); 0426 tinc->setReadOnly(true); 0427 } 0428 } 0429 auto item = new ListViewItem(aitem, calendar, mTreeWidget); 0430 0431 ListItemVisitor v(item, mStartDate); 0432 if (!tinc->accept(v, tinc)) { 0433 delete item; 0434 return; 0435 } 0436 0437 item->setData(0, Qt::UserRole, QVariant(aitem.id())); 0438 } 0439 0440 void ListView::showIncidences(const Akonadi::Item::List &itemList, const QDate &date) 0441 { 0442 clear(); 0443 for (const auto &item : itemList) { 0444 const auto calendar = calendar3(item); 0445 if (calendar) { 0446 d->addIncidence(calendar, Akonadi::CalendarUtils::incidence(item), date); 0447 } 0448 } 0449 updateView(); 0450 0451 // After new creation of list view no events are selected. 0452 Q_EMIT incidenceSelected(Akonadi::Item(), date); 0453 } 0454 0455 void ListView::changeIncidenceDisplay(const Akonadi::Item &aitem, int action) 0456 { 0457 const Incidence::Ptr incidence = Akonadi::CalendarUtils::incidence(aitem); 0458 const auto calendar = calendar3(aitem); 0459 0460 ListViewItem *item = nullptr; 0461 const QDate f = d->mSelectedDates.constFirst(); 0462 const QDate l = d->mSelectedDates.constLast(); 0463 0464 QDate date; 0465 if (CalendarSupport::hasTodo(aitem)) { 0466 date = Akonadi::CalendarUtils::todo(aitem)->dtDue().toLocalTime().date(); 0467 } else { 0468 date = incidence->dtStart().toLocalTime().date(); 0469 } 0470 0471 switch (action) { 0472 case Akonadi::IncidenceChanger::ChangeTypeCreate: 0473 if (date >= f && date <= l) { 0474 d->addIncidence(calendar, aitem, date); 0475 } 0476 break; 0477 case Akonadi::IncidenceChanger::ChangeTypeModify: 0478 item = d->getItemForIncidence(aitem); 0479 if (item) { 0480 delete item; 0481 d->mItems.remove(aitem.id()); 0482 d->mDateList.remove(aitem.id()); 0483 } 0484 if (date >= f && date <= l) { 0485 d->addIncidence(calendar, aitem, date); 0486 } 0487 break; 0488 case Akonadi::IncidenceChanger::ChangeTypeDelete: 0489 item = d->getItemForIncidence(aitem); 0490 delete item; 0491 break; 0492 default: 0493 qCDebug(CALENDARVIEW_LOG) << "Illegal action" << action; 0494 } 0495 } 0496 0497 ListViewItem *ListViewPrivate::getItemForIncidence(const Akonadi::Item &aitem) 0498 { 0499 int index = 0; 0500 while (QTreeWidgetItem *it = mTreeWidget->topLevelItem(index)) { 0501 auto item = static_cast<ListViewItem *>(it); 0502 if (item->mIncidence.id() == aitem.id()) { 0503 return item; 0504 } 0505 ++index; 0506 } 0507 0508 return nullptr; 0509 } 0510 0511 void ListView::slotSortIndicatorChanged(int logicalIndex, Qt::SortOrder order) 0512 { 0513 d->mSortColumn = logicalIndex; 0514 d->mSortOrder = order; 0515 } 0516 0517 void ListView::defaultItemAction(const QModelIndex &index) 0518 { 0519 if (!d->mIsNonInteractive) { 0520 // Get the first column, it has our Akonadi::Id 0521 const QModelIndex col0Idx = d->mTreeWidget->model()->index(index.row(), 0); 0522 Akonadi::Item::Id id = d->mTreeWidget->model()->data(col0Idx, Qt::UserRole).toLongLong(); 0523 defaultAction(d->mItems.value(id)); 0524 } 0525 } 0526 0527 void ListView::defaultItemAction(const Akonadi::Item::Id id) 0528 { 0529 if (!d->mIsNonInteractive) { 0530 defaultAction(d->mItems.value(id)); 0531 } 0532 } 0533 0534 void ListView::popupMenu(const QPoint &point) 0535 { 0536 d->mActiveItem = static_cast<ListViewItem *>(d->mTreeWidget->itemAt(point)); 0537 0538 if (d->mActiveItem && !d->mIsNonInteractive) { 0539 const Akonadi::Item aitem = d->mActiveItem->mIncidence; 0540 const auto calendar = calendar3(aitem); 0541 // FIXME: For recurring incidences we don't know the date of this 0542 // occurrence, there's no reference to it at all! 0543 0544 Q_EMIT showIncidencePopupSignal(calendar, aitem, Akonadi::CalendarUtils::incidence(aitem)->dtStart().date()); 0545 } else { 0546 Q_EMIT showNewEventPopupSignal(); 0547 } 0548 } 0549 0550 void ListView::readSettings(KConfig *config) 0551 { 0552 KConfigGroup cfgGroup = config->group(QStringLiteral("ListView Layout")); 0553 readSettings(cfgGroup); 0554 } 0555 0556 void EventViews::ListView::readSettings(const KConfigGroup &cfgGroup) 0557 { 0558 const QByteArray state = cfgGroup.readEntry("ViewState", QByteArray()); 0559 d->mTreeWidget->header()->restoreState(state); 0560 d->mSortColumn = cfgGroup.readEntry("SortColumn", static_cast<int>(StartDateTime_Column)); 0561 d->mSortOrder = static_cast<Qt::SortOrder>(cfgGroup.readEntry("SortOrder", static_cast<int>(Qt::AscendingOrder))); 0562 } 0563 0564 void ListView::writeSettings(KConfig *config) 0565 { 0566 KConfigGroup cfgGroup = config->group(QStringLiteral("ListView Layout")); 0567 } 0568 0569 void EventViews::ListView::writeSettings(KConfigGroup &cfgGroup) 0570 { 0571 const QByteArray state = d->mTreeWidget->header()->saveState(); 0572 cfgGroup.writeEntry("ViewState", state); 0573 cfgGroup.writeEntry("SortColumn", d->mSortColumn); 0574 cfgGroup.writeEntry("SortOrder", static_cast<int>(d->mSortOrder)); 0575 } 0576 0577 void ListView::processSelectionChange() 0578 { 0579 if (!d->mIsNonInteractive) { 0580 ListViewItem *item; 0581 if (d->mTreeWidget->selectedItems().isEmpty()) { 0582 item = nullptr; 0583 } else { 0584 item = static_cast<ListViewItem *>(d->mTreeWidget->selectedItems().first()); 0585 } 0586 0587 if (!item) { 0588 Q_EMIT incidenceSelected(Akonadi::Item(), QDate()); 0589 } else { 0590 Q_EMIT incidenceSelected(item->mIncidence, d->mDateList.value(item->mIncidence.id())); 0591 } 0592 } 0593 } 0594 0595 void ListView::clearSelection() 0596 { 0597 d->mTreeWidget->clearSelection(); 0598 } 0599 0600 void ListView::clear() 0601 { 0602 d->mSelectedDates.clear(); 0603 d->mTreeWidget->clear(); 0604 d->mDateList.clear(); 0605 d->mItems.clear(); 0606 } 0607 0608 QSize ListView::sizeHint() const 0609 { 0610 const QSize s = EventView::sizeHint(); 0611 return {s.width() + style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 1, s.height()}; 0612 } 0613 0614 #include "moc_listview.cpp"