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"