File indexing completed on 2024-04-28 04:40:44

0001 // SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
0002 // SPDX-License-Identifier: LGPL-2.1-or-later
0003 
0004 #include "monthmodel.h"
0005 #include <QRandomGenerator>
0006 
0007 class MonthModel::Private {
0008 public:
0009     int year;
0010     int month;
0011     QCalendar calendar = QCalendar();
0012     QDate selected;
0013 };
0014 
0015 MonthModel::MonthModel(QObject *parent)
0016     : QAbstractListModel(parent)
0017     , d(new MonthModel::Private())
0018 {
0019     goToday();
0020     d->selected = QDate::currentDate();
0021 }
0022 
0023 MonthModel::~MonthModel()
0024 {
0025 }
0026 
0027 int MonthModel::year() const
0028 {
0029     return d->year;
0030 }
0031 
0032 void MonthModel::setYear(int year)
0033 {
0034     if (d->year == year) {
0035         return;
0036     }
0037     d->year = year;
0038     Q_EMIT yearChanged();
0039     Q_EMIT dataChanged(index(0, 0), index(41, 0));
0040     setSelected(QDate(year, d->selected.month(), qMin(d->selected.day(), d->calendar.daysInMonth(d->selected.month(), year))));
0041 }
0042 
0043 int MonthModel::month() const
0044 {
0045     return d->month;
0046 }
0047 
0048 void MonthModel::setMonth(int month)
0049 {
0050     if (d->month == month) {
0051         return;
0052     }
0053     d->month = month;
0054     Q_EMIT monthChanged();
0055     Q_EMIT dataChanged(index(0, 0), index(41, 0));
0056     setSelected(QDate(d->selected.year(), d->month, qMin(d->selected.day(), d->calendar.daysInMonth(d->month, d->selected.year()))));
0057 }
0058 
0059 QDate MonthModel::selected() const
0060 {
0061     return d->selected;
0062 }
0063 
0064 void MonthModel::setSelected(const QDate &selected)
0065 {
0066     if (d->selected == selected) {
0067         return;
0068     }
0069     d->selected = selected;
0070     Q_EMIT selectedChanged();
0071     Q_EMIT dataChanged(index(0, 0), index(41, 0), {Roles::IsSelected});
0072 }
0073 
0074 QStringList MonthModel::weekDays() const
0075 {
0076     QLocale locale;
0077     QStringList daysName;
0078     for (int i = 0; i < 7; i++) {
0079         int day = locale.firstDayOfWeek() + i;
0080         if (day > 7) {
0081             day -= 7;
0082         }
0083         if (day == 7) {
0084             day = 0;
0085         }
0086         daysName.append(locale.standaloneDayName(day == 0 ? Qt::Sunday : day, QLocale::NarrowFormat));
0087     }
0088     return daysName;
0089 }
0090 
0091 void MonthModel::previous()
0092 {
0093     if (d->month == 1) {
0094         setYear(d->year - 1);
0095         setMonth(d->calendar.monthsInYear(d->year) - 1);
0096     } else {
0097         setMonth(d->month - 1);
0098     }
0099 }
0100 
0101 void MonthModel::next()
0102 {
0103     if (d->calendar.monthsInYear(d->year) == d->month) {
0104         setMonth(1);
0105         setYear(d->year + 1);
0106     } else {
0107         setMonth(d->month + 1);
0108     }
0109 }
0110 
0111 void MonthModel::goToday()
0112 {
0113     const auto today = QDate::currentDate();
0114     setMonth(today.month());
0115     setYear(today.year());
0116 }
0117 
0118 QVariant MonthModel::data(const QModelIndex &index, int role) const
0119 {
0120     if (!index.isValid()) {
0121         return {};
0122     }
0123 
0124     const int row = index.row();
0125 
0126     if (!index.parent().isValid()) {
0127         // Fetch days in month
0128         int prefix = d->calendar.dayOfWeek(QDate(d->year, d->month, 1)) - m_locale.firstDayOfWeek();
0129 
0130         if (prefix <= 1) {
0131             prefix += 7;
0132         } else if (prefix > 7) {
0133             prefix -= 7;
0134         }
0135 
0136         switch (role) {
0137         case Qt::DisplayRole:
0138         case DayNumber:
0139         case IsSelected:
0140         case IsToday:
0141         case Date: {
0142             int day = -1;
0143             int month = d->month;
0144             int year = d->year;
0145             const int daysInMonth = d->calendar.daysInMonth(d->month, d->year);
0146             if (row >= prefix && row - prefix < daysInMonth) {
0147                 // This month
0148                 day = row - prefix + 1;
0149             } else if (row - prefix >= daysInMonth) {
0150                 // Next month
0151                 month = d->calendar.monthsInYear(d->year) == d->month ? 1 : d->month + 1;
0152                 year = d->calendar.monthsInYear(d->year) == d->month ? d->year + 1 : d->year;
0153                 day = row - daysInMonth - prefix + 1;
0154             } else {
0155                 // Previous month
0156                 year = d->month > 1 ? d->year : d->year - 1;
0157                 month = d->month > 1 ? d->month - 1 : d->calendar.monthsInYear(year);
0158                 int daysInPreviousMonth = d->calendar.daysInMonth(month, year);
0159                 day = daysInPreviousMonth - prefix + row + 1;
0160             }
0161 
0162             if (role == DayNumber || role == Qt::DisplayRole) {
0163                 return day;
0164             }
0165             const QDate date(year, month, day);
0166             if (role == Date) {
0167                 return date.startOfDay();
0168                 // Ensure the date doesn't get mangled into a different date by QML date conversion
0169             }
0170 
0171             if (role == IsSelected) {
0172                 return d->selected == date;
0173             }
0174             if (role == IsToday) {
0175                 return date == QDate::currentDate();
0176             }
0177             return {};
0178         }
0179         case SameMonth: {
0180             const int daysInMonth = d->calendar.daysInMonth(d->month, d->year);
0181             return row >= prefix && row - prefix < daysInMonth;
0182         }
0183         }
0184     }
0185     return {};
0186 }
0187 
0188 int MonthModel::rowCount(const QModelIndex &parent) const
0189 {
0190     Q_UNUSED(parent);
0191     return 42; // Display 6 weeks with each 7 days
0192 }
0193 
0194 QHash<int, QByteArray> MonthModel::roleNames() const
0195 {
0196     return {
0197         {Qt::DisplayRole, QByteArrayLiteral("display")},
0198         {Roles::DayNumber, QByteArrayLiteral("dayNumber")},
0199         {Roles::SameMonth, QByteArrayLiteral("sameMonth")},
0200         {Roles::Date, QByteArrayLiteral("date")},
0201         {Roles::IsSelected, QByteArrayLiteral("isSelected")},
0202         {Roles::IsToday, QByteArrayLiteral("isToday")},
0203     };
0204 }
0205 
0206 #include "moc_monthmodel.cpp"