File indexing completed on 2024-05-12 05:21:22

0001 /*
0002   This file is part of KOrganizer.
0003 
0004   SPDX-FileCopyrightText: 2001, 2002, 2003 Cornelius Schumacher <schumacher@kde.org>
0005   SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
0006 
0007   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0008   SPDX-FileContributor: Sergio Martins <sergio@kdab.com>
0009 
0010   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0011 */
0012 
0013 #include "datenavigatorcontainer.h"
0014 #include "kodaymatrix.h"
0015 #include "koglobals.h"
0016 #include "widgets/kdatenavigator.h"
0017 #include "widgets/navigatorbar.h"
0018 
0019 #include <KLocalizedString>
0020 
0021 #include <QTimer>
0022 
0023 DateNavigatorContainer::DateNavigatorContainer(QWidget *parent)
0024     : QFrame(parent)
0025     , mNavigatorView(new KDateNavigator(this))
0026 {
0027     mNavigatorView->setWhatsThis(
0028         i18n("<qt><p>Select the dates you want to "
0029              "display in KOrganizer's main view here. Hold the "
0030              "mouse button to select more than one day.</p>"
0031              "<p>Press the top buttons to browse to the next "
0032              "/ previous months or years.</p>"
0033              "<p>Each line shows a week. The number in the left "
0034              "column is the number of the week in the year. "
0035              "Press it to select the whole week.</p>"
0036              "</qt>"));
0037 
0038     connectNavigatorView(mNavigatorView);
0039 }
0040 
0041 DateNavigatorContainer::~DateNavigatorContainer()
0042 {
0043     qDeleteAll(mExtraViews);
0044 }
0045 
0046 void DateNavigatorContainer::connectNavigatorView(KDateNavigator *v)
0047 {
0048     connect(v, &KDateNavigator::datesSelected, this, &DateNavigatorContainer::handleDatesSelectedSignal);
0049 
0050     connect(v, &KDateNavigator::incidenceDropped, this, &DateNavigatorContainer::incidenceDropped);
0051     connect(v, &KDateNavigator::incidenceDroppedMove, this, &DateNavigatorContainer::incidenceDroppedMove);
0052 
0053     connect(v, &KDateNavigator::newEventSignal, this, &DateNavigatorContainer::newEventSignal);
0054     connect(v, &KDateNavigator::newTodoSignal, this, &DateNavigatorContainer::newTodoSignal);
0055     connect(v, &KDateNavigator::newJournalSignal, this, &DateNavigatorContainer::newJournalSignal);
0056 
0057     connect(v, &KDateNavigator::weekClicked, this, &DateNavigatorContainer::handleWeekClickedSignal);
0058 
0059     connect(v, &KDateNavigator::goPrevious, this, &DateNavigatorContainer::goPrevious);
0060     connect(v, &KDateNavigator::goNext, this, &DateNavigatorContainer::goNext);
0061 
0062     connect(v, &KDateNavigator::nextYearClicked, this, &DateNavigatorContainer::nextYearClicked);
0063     connect(v, &KDateNavigator::prevYearClicked, this, &DateNavigatorContainer::prevYearClicked);
0064 
0065     connect(v, &KDateNavigator::prevMonthClicked, this, &DateNavigatorContainer::goPrevMonth);
0066     connect(v, &KDateNavigator::nextMonthClicked, this, &DateNavigatorContainer::goNextMonth);
0067 
0068     connect(v, &KDateNavigator::monthSelected, this, &DateNavigatorContainer::monthSelected);
0069     connect(v, &KDateNavigator::yearSelected, this, &DateNavigatorContainer::yearSelected);
0070 }
0071 
0072 void DateNavigatorContainer::addCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
0073 {
0074     mNavigatorView->addCalendar(calendar);
0075     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0076         if (n) {
0077             n->addCalendar(calendar);
0078         }
0079     }
0080     mCalendars.push_back(calendar);
0081 }
0082 
0083 void DateNavigatorContainer::removeCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
0084 {
0085     mNavigatorView->removeCalendar(calendar);
0086     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0087         if (n) {
0088             n->removeCalendar(calendar);
0089         }
0090     }
0091     mCalendars.removeOne(calendar);
0092 }
0093 
0094 // TODO_Recurrence: let the navigators update just once, and tell them that
0095 // if data has changed or just the selection (because then the list of dayss
0096 // with events doesn't have to be updated if the month stayed the same
0097 void DateNavigatorContainer::updateDayMatrix()
0098 {
0099     mNavigatorView->updateDayMatrix();
0100     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0101         if (n) {
0102             n->updateDayMatrix();
0103         }
0104     }
0105 }
0106 
0107 void DateNavigatorContainer::updateToday()
0108 {
0109     mNavigatorView->updateToday();
0110     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0111         if (n) {
0112             n->updateToday();
0113         }
0114     }
0115 }
0116 
0117 void DateNavigatorContainer::setUpdateNeeded()
0118 {
0119     mNavigatorView->setUpdateNeeded();
0120     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0121         if (n) {
0122             n->setUpdateNeeded();
0123         }
0124     }
0125 }
0126 
0127 void DateNavigatorContainer::updateView()
0128 {
0129     mNavigatorView->updateView();
0130     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0131         if (n) {
0132             n->setUpdateNeeded();
0133         }
0134     }
0135 }
0136 
0137 void DateNavigatorContainer::updateConfig()
0138 {
0139     mNavigatorView->updateConfig();
0140     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0141         if (n) {
0142             n->updateConfig();
0143         }
0144     }
0145 }
0146 
0147 void DateNavigatorContainer::selectDates(const KCalendarCore::DateList &dateList, const QDate &preferredMonth)
0148 {
0149     if (!dateList.isEmpty()) {
0150         QDate start(dateList.first());
0151         QDate end(dateList.last());
0152         QDate navfirst(mNavigatorView->startDate());
0153         QDate navsecond; // start of the second shown month if existent
0154         QDate navlast;
0155         if (!mExtraViews.isEmpty()) {
0156             navlast = mExtraViews.last()->endDate();
0157             navsecond = mExtraViews.first()->startDate();
0158         } else {
0159             navlast = mNavigatorView->endDate();
0160             navsecond = navfirst;
0161         }
0162 
0163         // If the datelist crosses months we won't know which month to show
0164         // so we read what's in preferredMonth
0165         const bool changingMonth = preferredMonth.isValid() && mNavigatorView->month().month() != preferredMonth.month();
0166 
0167         if (start < navfirst // <- start should always be visible
0168             || // end is not visible and we have a spare month at the beginning:
0169             (end > navlast && start >= navsecond) || changingMonth) {
0170             if (preferredMonth.isValid()) {
0171                 setBaseDates(preferredMonth);
0172             } else {
0173                 setBaseDates(start);
0174             }
0175         }
0176 
0177         if (!mIgnoreNavigatorUpdates) {
0178             mNavigatorView->selectDates(dateList);
0179             for (KDateNavigator *n : std::as_const(mExtraViews)) {
0180                 if (n) {
0181                     n->selectDates(dateList);
0182                 }
0183             }
0184         }
0185     }
0186 }
0187 
0188 void DateNavigatorContainer::setBaseDates(const QDate &start)
0189 {
0190     QDate baseDate = start;
0191     if (!mIgnoreNavigatorUpdates) {
0192         mNavigatorView->setBaseDate(baseDate);
0193     }
0194 
0195     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0196         baseDate = baseDate.addMonths(1);
0197         if (!mIgnoreNavigatorUpdates) {
0198             n->setBaseDate(baseDate);
0199         }
0200     }
0201 }
0202 
0203 void DateNavigatorContainer::resizeEvent(QResizeEvent *)
0204 {
0205 #if 0
0206     qCDebug(KORGANIZER_LOG) << "DateNavigatorContainer::resizeEvent()";
0207     qCDebug(KORGANIZER_LOG) << "  CURRENT SIZE:" << size();
0208     qCDebug(KORGANIZER_LOG) << "  MINIMUM SIZEHINT:" << minimumSizeHint();
0209     qCDebug(KORGANIZER_LOG) << "  SIZEHINT:" << sizeHint();
0210     qCDebug(KORGANIZER_LOG) << "  MINIMUM SIZE:" << minimumSize();
0211 #endif
0212     QTimer::singleShot(0, this, &DateNavigatorContainer::resizeAllContents);
0213 }
0214 
0215 void DateNavigatorContainer::resizeAllContents()
0216 {
0217     QSize minSize = mNavigatorView->minimumSizeHint();
0218 
0219     //  qCDebug(KORGANIZER_LOG) << "  NAVIGATORVIEW minimumSizeHint:" << minSize;
0220 
0221     int verticalCount = size().height() / minSize.height();
0222     int horizontalCount = size().width() / minSize.width();
0223 
0224     if (horizontalCount != mHorizontalCount || verticalCount != mVerticalCount) {
0225         int count = horizontalCount * verticalCount;
0226         if (count == 0) {
0227             return;
0228         }
0229 
0230         while (count > (mExtraViews.count() + 1)) {
0231             auto n = new KDateNavigator(this);
0232             mExtraViews.append(n);
0233             for (const auto &calendar : mCalendars) {
0234                 n->addCalendar(calendar);
0235             }
0236             connectNavigatorView(n);
0237         }
0238 
0239         while (count < (mExtraViews.count() + 1)) {
0240             delete (mExtraViews.last());
0241             mExtraViews.removeLast();
0242         }
0243 
0244         mHorizontalCount = horizontalCount;
0245         mVerticalCount = verticalCount;
0246         const KCalendarCore::DateList dates = mNavigatorView->selectedDates();
0247         if (!dates.isEmpty()) {
0248             setBaseDates(dates.first());
0249             selectDates(dates);
0250             for (KDateNavigator *n : std::as_const(mExtraViews)) {
0251                 if (n) {
0252                     n->show();
0253                 }
0254             }
0255         }
0256     }
0257 
0258     int height = size().height() / verticalCount;
0259     int width = size().width() / horizontalCount;
0260 
0261     NavigatorBar *bar = mNavigatorView->navigatorBar();
0262     if (horizontalCount > 1) {
0263         bar->showButtons(true, false);
0264     } else {
0265         bar->showButtons(true, true);
0266     }
0267 
0268     mNavigatorView->setGeometry((((KOGlobals::self()->reverseLayout()) ? (horizontalCount - 1) : 0) * width), 0, width, height);
0269     for (int i = 0; i < mExtraViews.count(); ++i) {
0270         int x = (i + 1) % horizontalCount;
0271         int y = (i + 1) / horizontalCount;
0272 
0273         KDateNavigator *view = mExtraViews.at(i);
0274         bar = view->navigatorBar();
0275         if (y > 0) {
0276             bar->showButtons(false, false);
0277         } else {
0278             if (x + 1 == horizontalCount) {
0279                 bar->showButtons(false, true);
0280             } else {
0281                 bar->showButtons(false, false);
0282             }
0283         }
0284         view->setGeometry((((KOGlobals::self()->reverseLayout()) ? (horizontalCount - 1 - x) : x) * width), y * height, width, height);
0285     }
0286 }
0287 
0288 QSize DateNavigatorContainer::minimumSizeHint() const
0289 {
0290     return mNavigatorView->minimumSizeHint();
0291 }
0292 
0293 QSize DateNavigatorContainer::sizeHint() const
0294 {
0295     return mNavigatorView->sizeHint();
0296 }
0297 
0298 void DateNavigatorContainer::setHighlightMode(bool highlightEvents, bool highlightTodos, bool highlightJournals) const
0299 {
0300     mNavigatorView->setHighlightMode(highlightEvents, highlightTodos, highlightJournals);
0301 
0302     for (KDateNavigator *n : std::as_const(mExtraViews)) {
0303         if (n) {
0304             n->setHighlightMode(highlightEvents, highlightTodos, highlightJournals);
0305         }
0306     }
0307 }
0308 
0309 void DateNavigatorContainer::goNextMonth()
0310 {
0311     const QPair<QDate, QDate> p = dateLimits(1);
0312 
0313     Q_EMIT nextMonthClicked(mNavigatorView->month(), p.first, p.second);
0314 }
0315 
0316 void DateNavigatorContainer::goPrevMonth()
0317 {
0318     const QPair<QDate, QDate> p = dateLimits(-1);
0319 
0320     Q_EMIT prevMonthClicked(mNavigatorView->month(), p.first, p.second);
0321 }
0322 
0323 QPair<QDate, QDate> DateNavigatorContainer::dateLimits(int offset) const
0324 {
0325     QDate firstMonth;
0326     QDate lastMonth;
0327     if (mExtraViews.isEmpty()) {
0328         lastMonth = mNavigatorView->month();
0329     } else {
0330         lastMonth = mExtraViews.last()->month();
0331     }
0332 
0333     firstMonth = mNavigatorView->month().addMonths(offset);
0334     lastMonth = lastMonth.addMonths(offset);
0335 
0336     QPair<QDate, QDate> firstMonthBoundary = KODayMatrix::matrixLimits(firstMonth);
0337     QPair<QDate, QDate> lastMonthBoundary = KODayMatrix::matrixLimits(lastMonth);
0338 
0339     return qMakePair(firstMonthBoundary.first, lastMonthBoundary.second);
0340 }
0341 
0342 QDate DateNavigatorContainer::monthOfNavigator(int navigatorIndex) const
0343 {
0344     if (navigatorIndex == 0) {
0345         return mNavigatorView->month();
0346     }
0347 
0348     if (navigatorIndex <= mExtraViews.count() && navigatorIndex >= 0) {
0349         return mExtraViews[navigatorIndex - 1]->month();
0350     } else {
0351         return {};
0352     }
0353 }
0354 
0355 void DateNavigatorContainer::handleDatesSelectedSignal(const KCalendarCore::DateList &dateList)
0356 {
0357     Q_ASSERT(sender());
0358     // When we have more than one KDateNavigator, both can have the
0359     // same selection ( because they can share weeks )
0360     // The month that we send in the datesSelected() signal should be
0361     // the one belonging to the KDatenavigator with the earliest month
0362     const QDate firstDate = dateList.first();
0363     KDateNavigator *navigator = firstNavigatorForDate(firstDate);
0364     navigator = navigator ? navigator : qobject_cast<KDateNavigator *>(sender());
0365 
0366     Q_EMIT datesSelected(dateList, navigator->month());
0367 }
0368 
0369 void DateNavigatorContainer::handleWeekClickedSignal(const QDate &week, const QDate &)
0370 {
0371     Q_ASSERT(sender());
0372     KDateNavigator *navigator = firstNavigatorForDate(week);
0373     navigator = navigator ? navigator : qobject_cast<KDateNavigator *>(sender());
0374 
0375     Q_EMIT weekClicked(week, navigator->month());
0376 }
0377 
0378 KDateNavigator *DateNavigatorContainer::firstNavigatorForDate(const QDate &date) const
0379 {
0380     KDateNavigator *navigator = nullptr;
0381     if (date.isValid()) {
0382         QPair<QDate, QDate> limits = KODayMatrix::matrixLimits(mNavigatorView->month());
0383 
0384         if (date >= limits.first && date <= limits.second) {
0385             // The date is in the first navigator
0386             navigator = mNavigatorView;
0387         } else {
0388             for (KDateNavigator *nav : std::as_const(mExtraViews)) {
0389                 if (nav) {
0390                     limits = KODayMatrix::matrixLimits(nav->month());
0391                     if (date >= limits.first && date <= limits.second) {
0392                         navigator = nav;
0393                         break;
0394                     }
0395                 }
0396             }
0397         }
0398     }
0399 
0400     return navigator;
0401 }
0402 
0403 #include "moc_datenavigatorcontainer.cpp"