File indexing completed on 2024-05-12 16:14:33
0001 // SPDX-FileCopyrightText: 2021 Claudio Cambra <claudio.cambra@gmail.com> 0002 // SPDX-License-Identifier: LGPL-2.1-or-later 0003 0004 #include <QDebug> 0005 #include <QMetaEnum> 0006 #include <cmath> 0007 #include "infinitecalendarviewmodel.h" 0008 0009 InfiniteCalendarViewModel::InfiniteCalendarViewModel(QObject *parent) 0010 : QAbstractListModel(parent) 0011 { 0012 setup(); 0013 } 0014 0015 void InfiniteCalendarViewModel::setup() 0016 { 0017 const QDate today = QDate::currentDate(); 0018 0019 switch (m_scale) { 0020 case WeekScale: { 0021 QDate firstDay = today.addDays(-today.dayOfWeek() + m_locale.firstDayOfWeek()); 0022 // We create dates before and after where our view will start from (which is today) 0023 firstDay = firstDay.addDays((-m_datesToAdd * 7) / 2); 0024 0025 addWeekDates(true, firstDay); 0026 break; 0027 } 0028 case MonthScale: { 0029 QDate firstDay(today.year(), today.month(), 1); 0030 firstDay = firstDay.addMonths(-m_datesToAdd / 2); 0031 0032 addMonthDates(true, firstDay); 0033 break; 0034 } 0035 case YearScale: { 0036 QDate firstDay(today.year(), today.month(), 1); 0037 firstDay = firstDay.addYears(-m_datesToAdd / 2); 0038 0039 addYearDates(true, firstDay); 0040 break; 0041 } 0042 case DecadeScale: { 0043 const int firstYear = ((floor(today.year() / 10)) * 10) - 1; // E.g. For 2020 have view start at 2019... 0044 QDate firstDay(firstYear, today.month(), 1); 0045 firstDay = firstDay.addYears(((-m_datesToAdd * 12) / 2) + 10); // 3 * 4 grid so 12 years, end at 2030, and align for mid index to be current decade 0046 0047 addDecadeDates(true, firstDay); 0048 break; 0049 } 0050 } 0051 } 0052 0053 QVariant InfiniteCalendarViewModel::data(const QModelIndex &idx, int role) const 0054 { 0055 if (!hasIndex(idx.row(), idx.column())) { 0056 return {}; 0057 } 0058 0059 const QDate startDate = m_startDates[idx.row()]; 0060 0061 if (m_scale == MonthScale && role != StartDateRole) { 0062 const QDate firstDay = m_firstDayOfMonthDates[idx.row()]; 0063 0064 switch (role) { 0065 case FirstDayOfMonthRole: 0066 return firstDay.startOfDay(); 0067 case SelectedMonthRole: 0068 return firstDay.month(); 0069 case SelectedYearRole: 0070 return firstDay.year(); 0071 default: 0072 qWarning() << "Unknown role for startdate:" << QMetaEnum::fromType<Roles>().valueToKey(role); 0073 return {}; 0074 } 0075 } 0076 0077 switch (role) { 0078 case StartDateRole: 0079 return startDate.startOfDay(); 0080 case SelectedMonthRole: 0081 return startDate.month(); 0082 case SelectedYearRole: 0083 return startDate.year(); 0084 default: 0085 qWarning() << "Unknown role for startdate:" << QMetaEnum::fromType<Roles>().valueToKey(role); 0086 return {}; 0087 } 0088 } 0089 0090 int InfiniteCalendarViewModel::rowCount(const QModelIndex &parent) const 0091 { 0092 Q_UNUSED(parent) 0093 return m_startDates.length(); 0094 } 0095 0096 QHash<int, QByteArray> InfiniteCalendarViewModel::roleNames() const 0097 { 0098 return { 0099 {StartDateRole, QByteArrayLiteral("startDate")}, 0100 {FirstDayOfMonthRole, QByteArrayLiteral("firstDay")}, 0101 {SelectedMonthRole, QByteArrayLiteral("selectedMonth")}, 0102 {SelectedYearRole, QByteArrayLiteral("selectedYear")}, 0103 }; 0104 } 0105 0106 void InfiniteCalendarViewModel::addDates(bool atEnd, const QDate startFrom) 0107 { 0108 switch (m_scale) { 0109 case WeekScale: 0110 addWeekDates(atEnd, startFrom); 0111 break; 0112 case MonthScale: 0113 addMonthDates(atEnd, startFrom); 0114 break; 0115 case YearScale: 0116 addYearDates(atEnd, startFrom); 0117 break; 0118 case DecadeScale: 0119 addDecadeDates(atEnd, startFrom); 0120 break; 0121 } 0122 } 0123 0124 void InfiniteCalendarViewModel::addWeekDates(bool atEnd, const QDate &startFrom) 0125 { 0126 const int newRow = atEnd ? rowCount() : 0; 0127 0128 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1); 0129 0130 for (int i = 0; i < m_datesToAdd; i++) { 0131 QDate startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addDays(7) : m_startDates[0].addDays(-7); 0132 0133 if (startDate.dayOfWeek() != m_locale.firstDayOfWeek()) { 0134 startDate = startDate.addDays(-startDate.dayOfWeek() + m_locale.firstDayOfWeek()); 0135 } 0136 0137 if (atEnd) { 0138 m_startDates.append(startDate); 0139 } else { 0140 m_startDates.insert(0, startDate); 0141 } 0142 } 0143 0144 endInsertRows(); 0145 } 0146 0147 void InfiniteCalendarViewModel::addMonthDates(bool atEnd, const QDate &startFrom) 0148 { 0149 const int newRow = atEnd ? rowCount() : 0; 0150 0151 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1); 0152 0153 for (int i = 0; i < m_datesToAdd; i++) { 0154 const QDate firstDay = startFrom.isValid() && i == 0 ? startFrom 0155 : atEnd ? m_firstDayOfMonthDates[rowCount() - 1].addMonths(1) 0156 : m_firstDayOfMonthDates[0].addMonths(-1); 0157 QDate startDate = firstDay; 0158 0159 startDate = startDate.addDays(-startDate.dayOfWeek() + m_locale.firstDayOfWeek()); 0160 if (startDate >= firstDay) { 0161 startDate = startDate.addDays(-7); 0162 } 0163 0164 if (atEnd) { 0165 m_firstDayOfMonthDates.append(firstDay); 0166 m_startDates.append(startDate); 0167 } else { 0168 m_firstDayOfMonthDates.insert(0, firstDay); 0169 m_startDates.insert(0, startDate); 0170 } 0171 } 0172 0173 endInsertRows(); 0174 } 0175 0176 void InfiniteCalendarViewModel::addYearDates(bool atEnd, const QDate &startFrom) 0177 { 0178 const int newRow = atEnd ? rowCount() : 0; 0179 0180 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1); 0181 0182 for (int i = 0; i < m_datesToAdd; i++) { 0183 QDate startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addYears(1) : m_startDates[0].addYears(-1); 0184 0185 if (atEnd) { 0186 m_startDates.append(startDate); 0187 } else { 0188 m_startDates.insert(0, startDate); 0189 } 0190 } 0191 0192 endInsertRows(); 0193 } 0194 0195 void InfiniteCalendarViewModel::addDecadeDates(bool atEnd, const QDate &startFrom) 0196 { 0197 const int newRow = atEnd ? rowCount() : 0; 0198 0199 beginInsertRows(QModelIndex(), newRow, newRow + m_datesToAdd - 1); 0200 0201 for (int i = 0; i < m_datesToAdd; i++) { 0202 QDate startDate = startFrom.isValid() && i == 0 ? startFrom : atEnd ? m_startDates[rowCount() - 1].addYears(10) : m_startDates[0].addYears(-10); 0203 0204 if (atEnd) { 0205 m_startDates.append(startDate); 0206 } else { 0207 m_startDates.insert(0, startDate); 0208 } 0209 } 0210 0211 endInsertRows(); 0212 } 0213 0214 int InfiniteCalendarViewModel::datesToAdd() const 0215 { 0216 return m_datesToAdd; 0217 } 0218 0219 void InfiniteCalendarViewModel::setDatesToAdd(int datesToAdd) 0220 { 0221 m_datesToAdd = datesToAdd; 0222 Q_EMIT datesToAddChanged(); 0223 } 0224 0225 int InfiniteCalendarViewModel::scale() 0226 { 0227 return m_scale; 0228 } 0229 0230 void InfiniteCalendarViewModel::setScale(int scale) 0231 { 0232 beginResetModel(); 0233 0234 m_startDates.clear(); 0235 m_firstDayOfMonthDates.clear(); 0236 m_scale = scale; 0237 setup(); 0238 Q_EMIT scaleChanged(); 0239 0240 endResetModel(); 0241 } 0242 0243 #include "moc_infinitecalendarviewmodel.cpp"