File indexing completed on 2024-05-12 05:37:11
0001 /* 0002 SPDX-FileCopyrightText: 2013 Mark Gaiser <markg85@gmail.com> 0003 SPDX-FileCopyrightText: 2016 Martin Klapetek <mklapetek@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <QDebug> 0009 0010 #include "calendar.h" 0011 0012 class CalendarPrivate 0013 { 0014 public: 0015 explicit CalendarPrivate(Calendar *q); 0016 0017 QDate displayedDate; 0018 QDate today; 0019 Calendar::Types types; 0020 QList<DayData> dayList; 0021 DaysModel *daysModel; 0022 QJsonArray weekList; 0023 0024 int days = 0; 0025 int weeks = 0; 0026 int firstDayOfWeek; 0027 QString errorMessage; 0028 0029 private: 0030 Q_DISABLE_COPY(CalendarPrivate) 0031 }; 0032 0033 CalendarPrivate::CalendarPrivate(Calendar *q) 0034 : types(Calendar::Holiday | Calendar::Event | Calendar::Todo | Calendar::Journal) 0035 , daysModel(new DaysModel(q)) 0036 , firstDayOfWeek(QLocale::system().firstDayOfWeek()) 0037 { 0038 daysModel->setSourceData(&dayList); 0039 } 0040 0041 Calendar::Calendar(QObject *parent) 0042 : QObject(parent) 0043 , d(new CalendarPrivate(this)) 0044 { 0045 // m_dayHelper = new CalendarDayHelper(this); 0046 // connect(m_dayHelper, SIGNAL(calendarChanged()), this, SLOT(updateData())); 0047 connect(this, &Calendar::monthNameChanged, this, &Calendar::monthChanged); 0048 } 0049 0050 Calendar::~Calendar() 0051 { 0052 delete d; 0053 } 0054 0055 QDateTime Calendar::displayedDate() const 0056 { 0057 return d->displayedDate.startOfDay(); 0058 } 0059 0060 void Calendar::setDisplayedDate(const QDate &dateTime) 0061 { 0062 if (d->displayedDate == dateTime) { 0063 return; 0064 } 0065 0066 const int oldMonth = d->displayedDate.month(); 0067 const int oldYear = d->displayedDate.year(); 0068 0069 d->displayedDate = dateTime; 0070 0071 // m_dayHelper->setDate(m_displayedDate.year(), m_displayedDate.month()); 0072 0073 updateData(); 0074 Q_EMIT displayedDateChanged(); 0075 if (oldMonth != d->displayedDate.month()) { 0076 Q_EMIT monthNameChanged(); 0077 } 0078 if (oldYear != d->displayedDate.year()) { 0079 Q_EMIT yearChanged(); 0080 } 0081 } 0082 0083 void Calendar::setDisplayedDate(const QDateTime &dateTime) 0084 { 0085 setDisplayedDate(dateTime.date()); 0086 } 0087 0088 QDateTime Calendar::today() const 0089 { 0090 return d->today.startOfDay(); 0091 } 0092 0093 void Calendar::setToday(const QDateTime &dateTime) 0094 { 0095 QDate date = dateTime.date(); 0096 if (date == d->today) { 0097 return; 0098 } 0099 0100 d->today = date; 0101 if (d->displayedDate.isNull()) { 0102 resetToToday(); 0103 } else { 0104 // the else is to prevent calling updateData() twice 0105 // if the resetToToday() was called 0106 updateData(); 0107 } 0108 Q_EMIT todayChanged(); 0109 } 0110 0111 void Calendar::resetToToday() 0112 { 0113 setDisplayedDate(d->today); 0114 updateData(); 0115 } 0116 0117 int Calendar::types() const 0118 { 0119 return d->types; 0120 } 0121 0122 void Calendar::setTypes(int types) 0123 { 0124 if (d->types == static_cast<Types>(types)) { 0125 return; 0126 } 0127 0128 // d->m_types = static_cast<Types>(types); 0129 // updateTypes(); 0130 0131 Q_EMIT typesChanged(); 0132 } 0133 0134 int Calendar::days() 0135 { 0136 return d->days; 0137 } 0138 0139 void Calendar::setDays(int days) 0140 { 0141 if (d->days != days) { 0142 d->days = days; 0143 updateData(); 0144 Q_EMIT daysChanged(); 0145 } 0146 } 0147 0148 int Calendar::weeks() const 0149 { 0150 return d->weeks; 0151 } 0152 0153 void Calendar::setWeeks(int weeks) 0154 { 0155 if (d->weeks != weeks) { 0156 d->weeks = weeks; 0157 updateData(); 0158 Q_EMIT weeksChanged(); 0159 } 0160 } 0161 0162 int Calendar::firstDayOfWeek() const 0163 { 0164 // QML has Sunday as 0, so we need to accommodate here 0165 return d->firstDayOfWeek == 7 ? 0 : d->firstDayOfWeek; 0166 } 0167 0168 void Calendar::setFirstDayOfWeek(int day) 0169 { 0170 if (day > 7) { 0171 return; 0172 } 0173 0174 if (d->firstDayOfWeek != day) { 0175 // QML has Sunday as 0, so we need to accommodate here 0176 // for QDate functions which have Sunday as 7 0177 if (day == 0) { 0178 d->firstDayOfWeek = 7; 0179 } else { 0180 d->firstDayOfWeek = day; 0181 } 0182 0183 updateData(); 0184 Q_EMIT firstDayOfWeekChanged(); 0185 } 0186 } 0187 0188 QString Calendar::errorMessage() const 0189 { 0190 return d->errorMessage; 0191 } 0192 0193 int Calendar::currentWeek() const 0194 { 0195 QDate date(QDate::currentDate()); 0196 return date.weekNumber(); 0197 } 0198 0199 QString Calendar::dayName(int weekday) const 0200 { 0201 return QLocale::system().dayName(weekday, QLocale::ShortFormat); 0202 } 0203 0204 QString Calendar::monthName() const 0205 { 0206 // Simple QDate::longMonthName won't do the job as it 0207 // will return the month name using LC_DATE locale which is used 0208 // for date formatting etc. So for example, in en_US locale 0209 // and cs_CZ LC_DATE, it would return Czech month names while 0210 // it should return English ones. So here we force the LANG 0211 // locale and take the month name from that. 0212 // 0213 // See https://bugs.kde.org/show_bug.cgi?id=353715 0214 0215 QLocale langLocale; 0216 0217 if (QLocale().uiLanguages().length() > 0) { 0218 langLocale = QLocale(QLocale().uiLanguages().at(0)); 0219 } 0220 return langLocale.standaloneMonthName(d->displayedDate.month()); 0221 } 0222 0223 int Calendar::year() const 0224 { 0225 return d->displayedDate.year(); 0226 } 0227 0228 int Calendar::month() const 0229 { 0230 return d->displayedDate.month(); 0231 } 0232 0233 QAbstractItemModel *Calendar::daysModel() const 0234 { 0235 return d->daysModel; 0236 } 0237 QJsonArray Calendar::weeksModel() const 0238 { 0239 return d->weekList; 0240 } 0241 0242 void Calendar::updateData() 0243 { 0244 if (d->days == 0 || d->weeks == 0) { 0245 return; 0246 } 0247 0248 d->dayList.clear(); 0249 d->weekList = QJsonArray(); 0250 0251 int totalDays = d->days * d->weeks; 0252 0253 int daysBeforeCurrentMonth = 0; 0254 int daysAfterCurrentMonth = 0; 0255 0256 QDate firstDay(d->displayedDate.year(), d->displayedDate.month(), 1); 0257 0258 // If the first day is the same as the starting day then we add a complete row before it. 0259 if (d->firstDayOfWeek < firstDay.dayOfWeek()) { 0260 daysBeforeCurrentMonth = firstDay.dayOfWeek() - d->firstDayOfWeek; 0261 } else { 0262 daysBeforeCurrentMonth = days() - (d->firstDayOfWeek - firstDay.dayOfWeek()); 0263 } 0264 0265 int daysThusFar = daysBeforeCurrentMonth + d->displayedDate.daysInMonth(); 0266 if (daysThusFar < totalDays) { 0267 daysAfterCurrentMonth = totalDays - daysThusFar; 0268 } 0269 0270 if (daysBeforeCurrentMonth > 0) { 0271 QDate previousMonth = d->displayedDate.addMonths(-1); 0272 // QDate previousMonth(d->m_displayedDate.year(), d->m_displayedDate.month() - 1, 1); 0273 for (int i = 0; i < daysBeforeCurrentMonth; i++) { 0274 DayData day; 0275 day.isCurrent = false; 0276 day.dayNumber = previousMonth.daysInMonth() - (daysBeforeCurrentMonth - (i + 1)); 0277 day.monthNumber = previousMonth.month(); 0278 day.yearNumber = previousMonth.year(); 0279 // day.containsEventItems = false; 0280 d->dayList << day; 0281 } 0282 } 0283 0284 for (int i = 0; i < d->displayedDate.daysInMonth(); i++) { 0285 DayData day; 0286 day.isCurrent = true; 0287 day.dayNumber = i + 1; // +1 to go form 0 based index to 1 based calendar dates 0288 // day.containsEventItems = m_dayHelper->containsEventItems(i + 1); 0289 day.monthNumber = d->displayedDate.month(); 0290 day.yearNumber = d->displayedDate.year(); 0291 d->dayList << day; 0292 } 0293 0294 if (daysAfterCurrentMonth > 0) { 0295 for (int i = 0; i < daysAfterCurrentMonth; i++) { 0296 DayData day; 0297 day.isCurrent = false; 0298 day.dayNumber = i + 1; // +1 to go form 0 based index to 1 based calendar dates 0299 // day.containsEventItems = false; 0300 day.monthNumber = d->displayedDate.addMonths(1).month(); 0301 day.yearNumber = d->displayedDate.addMonths(1).year(); 0302 d->dayList << day; 0303 } 0304 } 0305 const int numOfDaysInCalendar = d->dayList.count(); 0306 0307 // Week numbers are always counted from Mondays 0308 // so find which index is Monday 0309 int mondayOffset = 0; 0310 if (!d->dayList.isEmpty()) { 0311 const DayData &data = d->dayList.at(0); 0312 QDate firstDay(data.yearNumber, data.monthNumber, data.dayNumber); 0313 // If the first day is not already Monday, get offset for Monday 0314 if (firstDay.dayOfWeek() != 1) { 0315 mondayOffset = 8 - firstDay.dayOfWeek(); 0316 } 0317 } 0318 0319 // Fill weeksModel with the week numbers 0320 for (int i = mondayOffset; i < numOfDaysInCalendar; i += 7) { 0321 const DayData &data = d->dayList.at(i); 0322 d->weekList.append(QDate(data.yearNumber, data.monthNumber, data.dayNumber).weekNumber()); 0323 } 0324 Q_EMIT weeksModelChanged(); 0325 d->daysModel->update(); 0326 0327 // qDebug() << "---------------------------------------------------------------"; 0328 // qDebug() << "Date obj: " << d->m_displayedDate; 0329 // qDebug() << "Month: " << d->m_displayedDate.month(); 0330 // qDebug() << "m_days: " << d->m_days; 0331 // qDebug() << "m_weeks: " << d->m_weeks; 0332 // qDebug() << "Days before this month: " << daysBeforeCurrentMonth; 0333 // qDebug() << "Days after this month: " << daysAfterCurrentMonth; 0334 // qDebug() << "Days in current month: " << d->m_displayedDate.daysInMonth(); 0335 // qDebug() << "d->m_dayList size: " << d->m_dayList.count(); 0336 // qDebug() << "---------------------------------------------------------------"; 0337 } 0338 0339 void Calendar::nextDecade() 0340 { 0341 setDisplayedDate(d->displayedDate.addYears(10)); 0342 } 0343 0344 void Calendar::previousDecade() 0345 { 0346 // Negative years don't make sense 0347 if (d->displayedDate.year() >= 10) { 0348 setDisplayedDate(d->displayedDate.addYears(-10)); 0349 } 0350 } 0351 0352 void Calendar::nextYear() 0353 { 0354 setDisplayedDate(d->displayedDate.addYears(1)); 0355 } 0356 0357 void Calendar::previousYear() 0358 { 0359 // Negative years don't make sense 0360 if (d->displayedDate.year() >= 1) { 0361 setDisplayedDate(d->displayedDate.addYears(-1)); 0362 } 0363 } 0364 0365 void Calendar::nextMonth() 0366 { 0367 setDisplayedDate(d->displayedDate.addMonths(1)); 0368 } 0369 0370 void Calendar::previousMonth() 0371 { 0372 setDisplayedDate(d->displayedDate.addMonths(-1)); 0373 } 0374 0375 void Calendar::goToMonth(int month) 0376 { 0377 setDisplayedDate(QDate(d->displayedDate.year(), month, 1)); 0378 } 0379 0380 void Calendar::goToYear(int year) 0381 { 0382 setDisplayedDate(QDate(year, d->displayedDate.month(), 1)); 0383 }