File indexing completed on 2024-11-17 04:49:18

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-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0008 */
0009 
0010 #include "kdatenavigator.h"
0011 #include "kodaymatrix.h"
0012 #include "koglobals.h"
0013 #include "widgets/navigatorbar.h"
0014 
0015 #include <KLocalizedString>
0016 #include <QEvent>
0017 #include <QFontDatabase>
0018 #include <QGridLayout>
0019 #include <QLabel>
0020 #include <QLocale>
0021 #include <QWheelEvent>
0022 
0023 KDateNavigator::KDateNavigator(QWidget *parent)
0024     : QFrame(parent)
0025     , mNavigatorBar(new NavigatorBar(this))
0026     , mBaseDate(1970, 1, 1)
0027 {
0028     auto topLayout = new QGridLayout(this);
0029     topLayout->setContentsMargins({});
0030     topLayout->setSpacing(0);
0031 
0032     topLayout->addWidget(mNavigatorBar, 0, 0, 1, 8);
0033 
0034     connect(mNavigatorBar, &NavigatorBar::prevYearClicked, this, &KDateNavigator::prevYearClicked);
0035     connect(mNavigatorBar, &NavigatorBar::prevMonthClicked, this, &KDateNavigator::prevMonthClicked);
0036     connect(mNavigatorBar, &NavigatorBar::nextMonthClicked, this, &KDateNavigator::nextMonthClicked);
0037     connect(mNavigatorBar, &NavigatorBar::nextYearClicked, this, &KDateNavigator::nextYearClicked);
0038     connect(mNavigatorBar, &NavigatorBar::monthSelected, this, &KDateNavigator::monthSelected);
0039     connect(mNavigatorBar, &NavigatorBar::yearSelected, this, &KDateNavigator::yearSelected);
0040 
0041     QString generalFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont).family();
0042 
0043     // Set up the heading fields.
0044     for (int i = 0; i < 7; ++i) {
0045         mHeadings[i] = new QLabel(this);
0046         mHeadings[i]->setFont(QFont(generalFont, 10, QFont::Bold));
0047         mHeadings[i]->setAlignment(Qt::AlignCenter);
0048 
0049         topLayout->addWidget(mHeadings[i], 1, i + 1);
0050     }
0051 
0052     // Create the weeknumber labels
0053     for (int i = 0; i < 6; ++i) {
0054         mWeeknos[i] = new QLabel(this);
0055         mWeeknos[i]->setAlignment(Qt::AlignCenter);
0056         mWeeknos[i]->setFont(QFont(generalFont, 10));
0057         mWeeknos[i]->installEventFilter(this);
0058 
0059         topLayout->addWidget(mWeeknos[i], i + 2, 0);
0060     }
0061 
0062     mDayMatrix = new KODayMatrix(this);
0063     mDayMatrix->setObjectName(QLatin1StringView("KDateNavigator::dayMatrix"));
0064 
0065     connect(mDayMatrix, &KODayMatrix::selected, this, &KDateNavigator::datesSelected);
0066 
0067     connect(mDayMatrix, &KODayMatrix::incidenceDropped, this, &KDateNavigator::incidenceDropped);
0068     connect(mDayMatrix, &KODayMatrix::incidenceDroppedMove, this, &KDateNavigator::incidenceDroppedMove);
0069 
0070     connect(mDayMatrix, &KODayMatrix::newEventSignal, this, &KDateNavigator::newEventSignal);
0071     connect(mDayMatrix, &KODayMatrix::newTodoSignal, this, &KDateNavigator::newTodoSignal);
0072     connect(mDayMatrix, &KODayMatrix::newJournalSignal, this, &KDateNavigator::newJournalSignal);
0073 
0074     topLayout->addWidget(mDayMatrix, 2, 1, 6, 7);
0075 
0076     // read settings from configuration file.
0077     updateConfig();
0078 }
0079 
0080 KDateNavigator::~KDateNavigator() = default;
0081 
0082 void KDateNavigator::addCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
0083 {
0084     mDayMatrix->addCalendar(calendar);
0085 }
0086 
0087 void KDateNavigator::removeCalendar(const Akonadi::CollectionCalendar::Ptr &calendar)
0088 {
0089     mDayMatrix->removeCalendar(calendar);
0090 }
0091 
0092 void KDateNavigator::setBaseDate(const QDate &date)
0093 {
0094     if (date != mBaseDate) {
0095         mBaseDate = date;
0096 
0097         updateDates();
0098         updateView();
0099 
0100         // Use the base date to show the monthname and year in the header
0101         KCalendarCore::DateList dates;
0102         dates.append(date);
0103         mNavigatorBar->selectDates(dates);
0104 
0105         update();
0106         mDayMatrix->update();
0107     }
0108 }
0109 
0110 QSizePolicy KDateNavigator::sizePolicy() const
0111 {
0112     return {QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding};
0113 }
0114 
0115 void KDateNavigator::updateToday()
0116 {
0117     mDayMatrix->recalculateToday();
0118     mDayMatrix->update();
0119 }
0120 
0121 QDate KDateNavigator::startDate() const
0122 {
0123     // Find the first day of the week of the current month.
0124     QDate dayone(mBaseDate.year(), mBaseDate.month(), mBaseDate.day());
0125     const int d2 = dayone.day();
0126     dayone = dayone.addDays(-d2 + 1);
0127 
0128     const int m_fstDayOfWkCalsys = dayone.dayOfWeek();
0129     const int weekstart = KOGlobals::self()->firstDayOfWeek();
0130 
0131     // If month begins on Monday and Monday is first day of week,
0132     // month should begin on second line. Sunday doesn't have this problem.
0133     const int nextLine = m_fstDayOfWkCalsys <= weekstart ? 7 : 0;
0134 
0135     // update the matrix dates
0136     const int index = weekstart - m_fstDayOfWkCalsys - nextLine;
0137 
0138     dayone = dayone.addDays(index);
0139 
0140     return dayone;
0141 }
0142 
0143 QDate KDateNavigator::endDate() const
0144 {
0145     return startDate().addDays(6 * 7);
0146 }
0147 
0148 void KDateNavigator::setHighlightMode(bool highlightEvents, bool highlightTodos, bool highlightJournals) const
0149 {
0150     mDayMatrix->setHighlightMode(highlightEvents, highlightTodos, highlightJournals);
0151 }
0152 
0153 void KDateNavigator::updateDates()
0154 {
0155     QDate dayone = startDate();
0156 
0157     mDayMatrix->updateView(dayone);
0158 
0159     // set the week numbers.
0160     for (int i = 0; i < 6; ++i) {
0161         // Use QDate's weekNumber method to determine the week number!
0162         QDate dtStart = mDayMatrix->getDate(i * 7);
0163         QDate dtEnd = mDayMatrix->getDate((i + 1) * 7 - 1);
0164         const int weeknumstart = dtStart.weekNumber();
0165         const int weeknumend = dtEnd.weekNumber();
0166         QString weeknum;
0167 
0168         if (weeknumstart != weeknumend) {
0169             weeknum = i18nc("start/end week number of line in date picker", "%1/%2", weeknumstart, weeknumend);
0170         } else {
0171             weeknum.setNum(weeknumstart);
0172         }
0173         mWeeknos[i]->setText(weeknum);
0174         mWeeknos[i]->setToolTip(i18n("Scroll to week number %1", weeknum));
0175         mWeeknos[i]->setWhatsThis(
0176             i18n("Click here to scroll the display to week number %1 "
0177                  "of the currently displayed year.",
0178                  weeknum));
0179     }
0180 
0181     // each updateDates is followed by an updateView -> repaint is issued there !
0182     //  mDayMatrix->repaint();
0183 }
0184 
0185 void KDateNavigator::updateDayMatrix()
0186 {
0187     mDayMatrix->updateView();
0188     mDayMatrix->update();
0189 }
0190 
0191 void KDateNavigator::setUpdateNeeded()
0192 {
0193     mDayMatrix->setUpdateNeeded();
0194 }
0195 
0196 QDate KDateNavigator::month() const
0197 {
0198     QDate firstCell = startDate();
0199 
0200     if (firstCell.day() == 1) {
0201         return firstCell;
0202     } else {
0203         firstCell.setDate(firstCell.year(), firstCell.month(), 1);
0204         return firstCell.addMonths(1);
0205     }
0206 }
0207 
0208 void KDateNavigator::updateView()
0209 {
0210     updateDayMatrix();
0211     update();
0212 }
0213 
0214 void KDateNavigator::updateConfig()
0215 {
0216     int weekstart = KOGlobals::self()->firstDayOfWeek();
0217     for (int i = 0; i < 7; ++i) {
0218         const int day = weekstart + i <= 7 ? weekstart + i : (weekstart + i) % 7;
0219         QString dayName = QLocale().dayName(day, QLocale::ShortFormat);
0220         QString longDayName = QLocale().dayName(day, QLocale::LongFormat);
0221         mHeadings[i]->setText(dayName);
0222         mHeadings[i]->setToolTip(i18n("%1", longDayName));
0223         mHeadings[i]->setWhatsThis(i18n("A column header of the %1 dates in the month.", longDayName));
0224     }
0225     mDayMatrix->setUpdateNeeded();
0226     updateDayMatrix();
0227     update();
0228     // FIXME: Use actual config setting here
0229     //  setShowWeekNums( true );
0230 }
0231 
0232 void KDateNavigator::setShowWeekNums(bool enabled)
0233 {
0234     for (int i = 0; i < 6; ++i) {
0235         if (enabled) {
0236             mWeeknos[i]->show();
0237         } else {
0238             mWeeknos[i]->hide();
0239         }
0240     }
0241 }
0242 
0243 void KDateNavigator::selectMonthHelper(int monthDifference)
0244 {
0245     QDate baseDateNextMonth = mBaseDate.addMonths(monthDifference);
0246 
0247     KCalendarCore::DateList newSelection = mSelectedDates;
0248     for (int i = 0; i < mSelectedDates.count(); ++i) {
0249         newSelection[i] = newSelection[i].addMonths(monthDifference);
0250     }
0251 
0252     setBaseDate(baseDateNextMonth);
0253     mSelectedDates = newSelection;
0254     mDayMatrix->setSelectedDaysFrom(*(newSelection.begin()), *(--newSelection.end()));
0255     updateView();
0256 }
0257 
0258 void KDateNavigator::selectNextMonth()
0259 {
0260     selectMonthHelper(1);
0261 }
0262 
0263 void KDateNavigator::selectPreviousMonth()
0264 {
0265     selectMonthHelper(-1);
0266 }
0267 
0268 void KDateNavigator::selectDates(const KCalendarCore::DateList &dateList)
0269 {
0270     if (!dateList.isEmpty()) {
0271         mSelectedDates = dateList;
0272 
0273         updateDates();
0274 
0275         mDayMatrix->setSelectedDaysFrom(*(dateList.begin()), *(--dateList.end()));
0276 
0277         updateView();
0278     }
0279 }
0280 
0281 void KDateNavigator::wheelEvent(QWheelEvent *e)
0282 {
0283     if (e->angleDelta().y() > 0) {
0284         Q_EMIT goPrevious();
0285     } else {
0286         Q_EMIT goNext();
0287     }
0288     e->accept();
0289 }
0290 
0291 bool KDateNavigator::eventFilter(QObject *o, QEvent *e)
0292 {
0293     if (e->type() == QEvent::MouseButtonPress) {
0294         int i;
0295         for (i = 0; i < 6; ++i) {
0296             if (o == mWeeknos[i]) {
0297                 const QDate weekstart = mDayMatrix->getDate(i * 7);
0298                 Q_EMIT weekClicked(weekstart, month());
0299                 break;
0300             }
0301         }
0302         return true;
0303     } else {
0304         return false;
0305     }
0306 }
0307 
0308 #include "moc_kdatenavigator.cpp"