File indexing completed on 2025-01-05 03:51:06

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 1997-04-21
0007  * Description : A date selection widget.
0008  *
0009  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 1997      by Tim D. Gilman <tdgilman at best dot org>
0011  * SPDX-FileCopyrightText: 1998-2001 by Mirko Boehm <mirko at kde dot org>
0012  * SPDX-FileCopyrightText: 2007      by John Layt <john at layt dot net>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "ddatepicker_p.h"
0019 
0020 // Qt includes
0021 
0022 #include <QFontDatabase>
0023 
0024 // KDE includes
0025 
0026 #include <klocalizedstring.h>
0027 
0028 namespace Digikam
0029 {
0030 
0031 DatePickerValidator::DatePickerValidator(DDatePicker* const parent)
0032     : QValidator(parent),
0033       m_picker  (parent)
0034 {
0035 }
0036 
0037 QValidator::State DatePickerValidator::validate(QString& text, int&) const
0038 {
0039     QLocale::FormatType formats[] =
0040     {
0041         QLocale::LongFormat,
0042         QLocale::ShortFormat,
0043         QLocale::NarrowFormat
0044     };
0045 
0046     QLocale locale = m_picker->locale();
0047 
0048     for (int i = 0 ; i < 3 ; ++i)
0049     {
0050         QDate tmp = locale.toDate(text, formats[i]);
0051 
0052         if (tmp.isValid())
0053         {
0054             return Acceptable;
0055         }
0056     }
0057 
0058     return QValidator::Intermediate;
0059 }
0060 
0061 // ------------------------------------------------------------------------------
0062 
0063 /**
0064  * NOTE: Week numbers are defined by ISO 8601
0065  * See https://en.wikipedia.org/wiki/Week#Week_numbering for details
0066  */
0067 DatePickerYearSelector::DatePickerYearSelector(const QDate& currentDate, QWidget* const parent)
0068     : QLineEdit(parent),
0069       val      (new QIntValidator(this)),
0070       result   (0),
0071       oldDate  (currentDate)
0072 {
0073     setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0074 
0075     setFrame(false);
0076 
0077 /*
0078     TODO: Find a way to get that from QLocale
0079     val->setRange(calendar->year(calendar->earliestValidDate()),
0080                   calendar->year(calendar->latestValidDate()));
0081 */
0082     setValidator(val);
0083 
0084     connect(this, &QLineEdit::returnPressed,
0085             this, &DatePickerYearSelector::yearEnteredSlot);
0086 }
0087 
0088 void DatePickerYearSelector::yearEnteredSlot()
0089 {
0090     bool ok;
0091     int newYear;
0092 
0093     // check if entered value is a number
0094 
0095     newYear = text().toInt(&ok);
0096 
0097     if (!ok)
0098     {
0099         QApplication::beep();
0100         return;
0101     }
0102 
0103     // check if new year will lead to a valid date
0104 
0105     if (QDate(newYear, oldDate.month(), oldDate.day()).isValid())
0106     {
0107         result = newYear;
0108         Q_EMIT closeMe(1);
0109     }
0110     else
0111     {
0112         QApplication::beep();
0113     }
0114 }
0115 
0116 int DatePickerYearSelector::year() const
0117 {
0118     return result;
0119 }
0120 
0121 void DatePickerYearSelector::setYear(int year)
0122 {
0123     setText(QString::number(year));
0124 }
0125 
0126 // ------------------------------------------------------------------------------
0127 
0128 DDatePicker::Private::Private(DDatePicker* const qq)
0129     : q                 (qq),
0130       closeButton       (nullptr),
0131       selectWeek        (nullptr),
0132       todayButton       (nullptr),
0133       navigationLayout  (nullptr),
0134       yearForward       (nullptr),
0135       yearBackward      (nullptr),
0136       monthForward      (nullptr),
0137       monthBackward     (nullptr),
0138       selectMonth       (nullptr),
0139       selectYear        (nullptr),
0140       line              (nullptr),
0141       val               (nullptr),
0142       table             (nullptr),
0143       fontsize          (0)
0144 {
0145 }
0146 
0147 void DDatePicker::Private::fillWeeksCombo()
0148 {
0149     /**
0150      * NOTE: every year can have a different number of weeks
0151      * it could be that we had 53,1..52 and now 1..53 which is the same number but different
0152      * so always fill with new values
0153      * We show all week numbers for all weeks between first day of year to last day of year
0154      * This of course can be a list like 53,1,2..52
0155      */
0156     const QDate thisDate      = q->date();
0157     const int thisYear        = thisDate.year();
0158     QDate day(thisDate.year(), 1, 1);
0159     const QDate lastDayOfYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1);
0160 
0161     selectWeek->clear();
0162 
0163     // Starting from the first day in the year, loop through the year a week at a time
0164     // adding an entry to the week combo for each week in the year
0165 
0166     for ( ; day.isValid() && (day <= lastDayOfYear) ; (day = day.addDays(7)))
0167     {
0168         // Get the ISO week number for the current day and what year that week is in
0169         // e.g. 1st day of this year may fall in week 53 of previous year
0170 
0171         int weekYear       = thisYear;
0172         const int week     = day.weekNumber(&weekYear);
0173         QString weekString = i18n("Week %1", week);
0174 
0175         // show that this is a week from a different year
0176 
0177         if (weekYear != thisYear)
0178         {
0179             weekString += QLatin1Char('*');
0180         }
0181 
0182         // when the week is selected, go to the same weekday as the one
0183         // that is currently selected in the date table
0184 
0185         QDate targetDate = day.addDays(thisDate.dayOfWeek() - day.dayOfWeek());
0186         selectWeek->addItem(weekString, targetDate);
0187 
0188         // make sure that the week of the lastDayOfYear is always inserted: in Chinese calendar
0189         // system, this is not always the case
0190 
0191         if (
0192             (day < lastDayOfYear)           &&
0193             (day.daysTo(lastDayOfYear) < 7) &&
0194             (lastDayOfYear.weekNumber() != day.weekNumber())
0195            )
0196         {
0197             day = lastDayOfYear.addDays(-7);
0198         }
0199     }
0200 }
0201 
0202 QDate DDatePicker::Private::validDateInYearMonth(int year, int month)
0203 {
0204     QDate newDate;
0205 
0206     // Try to create a valid date in this year and month
0207     // First try the first of the month, then try last of month
0208 
0209     if      (QDate(year, month, 1).isValid())
0210     {
0211         newDate = QDate(year, month, 1);
0212     }
0213     else if (QDate(year, month + 1, 1).isValid())
0214     {
0215         newDate = QDate(year, month + 1, 1).addDays(-1);
0216     }
0217     else
0218     {
0219         newDate = QDate::fromJulianDay(0);
0220     }
0221 
0222     return newDate;
0223 }
0224 
0225 } // namespace Digikam
0226 
0227 #include "moc_ddatepicker_p.cpp"