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