File indexing completed on 2024-06-23 04:42:35

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