| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2020 The Qt Company Ltd. | 
|---|
| 4 | ** Contact: https://www.qt.io/licensing/ | 
|---|
| 5 | ** | 
|---|
| 6 | ** This file is part of the QtCore module of the Qt Toolkit. | 
|---|
| 7 | ** | 
|---|
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
|---|
| 9 | ** Commercial License Usage | 
|---|
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
|---|
| 11 | ** accordance with the commercial license agreement provided with the | 
|---|
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
|---|
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
|---|
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
|---|
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
|---|
| 16 | ** | 
|---|
| 17 | ** GNU Lesser General Public License Usage | 
|---|
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|---|
| 19 | ** General Public License version 3 as published by the Free Software | 
|---|
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
|---|
| 21 | ** packaging of this file. Please review the following information to | 
|---|
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
|---|
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
|---|
| 24 | ** | 
|---|
| 25 | ** GNU General Public License Usage | 
|---|
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
|---|
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
|---|
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
|---|
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
|---|
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
|---|
| 31 | ** included in the packaging of this file. Please review the following | 
|---|
| 32 | ** information to ensure the GNU General Public License requirements will | 
|---|
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
|---|
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
|---|
| 35 | ** | 
|---|
| 36 | ** $QT_END_LICENSE$ | 
|---|
| 37 | ** | 
|---|
| 38 | ****************************************************************************/ | 
|---|
| 39 |  | 
|---|
| 40 | #ifndef QDATETIMEPARSER_P_H | 
|---|
| 41 | #define QDATETIMEPARSER_P_H | 
|---|
| 42 |  | 
|---|
| 43 | // | 
|---|
| 44 | //  W A R N I N G | 
|---|
| 45 | //  ------------- | 
|---|
| 46 | // | 
|---|
| 47 | // This file is not part of the Qt API.  It exists purely as an | 
|---|
| 48 | // implementation detail.  This header file may change from version to | 
|---|
| 49 | // version without notice, or even be removed. | 
|---|
| 50 | // | 
|---|
| 51 | // We mean it. | 
|---|
| 52 | // | 
|---|
| 53 |  | 
|---|
| 54 | #include <QtCore/private/qglobal_p.h> | 
|---|
| 55 | #include "qplatformdefs.h" | 
|---|
| 56 | #include "QtCore/qatomic.h" | 
|---|
| 57 | #include "QtCore/qcalendar.h" | 
|---|
| 58 | #include "QtCore/qcoreapplication.h" | 
|---|
| 59 | #include "QtCore/qdatetime.h" | 
|---|
| 60 | #include "QtCore/qlist.h" | 
|---|
| 61 | #include "QtCore/qlocale.h" | 
|---|
| 62 | #include "QtCore/qstringlist.h" | 
|---|
| 63 | #ifndef QT_BOOTSTRAPPED | 
|---|
| 64 | # include "QtCore/qvariant.h" | 
|---|
| 65 | #endif | 
|---|
| 66 |  | 
|---|
| 67 | QT_REQUIRE_CONFIG(datetimeparser); | 
|---|
| 68 |  | 
|---|
| 69 | #define QDATETIMEEDIT_TIME_MIN QTime(0, 0) // Prefer QDate::startOfDay() | 
|---|
| 70 | #define QDATETIMEEDIT_TIME_MAX QTime(23, 59, 59, 999) // Prefer QDate::endOfDay() | 
|---|
| 71 | #define QDATETIMEEDIT_DATE_MIN QDate(100, 1, 1) | 
|---|
| 72 | #define QDATETIMEEDIT_COMPAT_DATE_MIN QDate(1752, 9, 14) | 
|---|
| 73 | #define QDATETIMEEDIT_DATE_MAX QDate(9999, 12, 31) | 
|---|
| 74 | #define QDATETIMEEDIT_DATE_INITIAL QDate(2000, 1, 1) | 
|---|
| 75 |  | 
|---|
| 76 | QT_BEGIN_NAMESPACE | 
|---|
| 77 |  | 
|---|
| 78 | class Q_CORE_EXPORT QDateTimeParser | 
|---|
| 79 | { | 
|---|
| 80 | public: | 
|---|
| 81 | enum Context { | 
|---|
| 82 | FromString, | 
|---|
| 83 | DateTimeEdit | 
|---|
| 84 | }; | 
|---|
| 85 | QDateTimeParser(QMetaType::Type t, Context ctx, const QCalendar &cal = QCalendar()) | 
|---|
| 86 | : currentSectionIndex(-1), cachedDay(-1), parserType(t), | 
|---|
| 87 | fixday(false), context(ctx), calendar(cal) | 
|---|
| 88 | { | 
|---|
| 89 | defaultLocale = QLocale::system(); | 
|---|
| 90 | first.type = FirstSection; | 
|---|
| 91 | first.pos = -1; | 
|---|
| 92 | first.count = -1; | 
|---|
| 93 | first.zeroesAdded = 0; | 
|---|
| 94 | last.type = LastSection; | 
|---|
| 95 | last.pos = -1; | 
|---|
| 96 | last.count = -1; | 
|---|
| 97 | last.zeroesAdded = 0; | 
|---|
| 98 | none.type = NoSection; | 
|---|
| 99 | none.pos = -1; | 
|---|
| 100 | none.count = -1; | 
|---|
| 101 | none.zeroesAdded = 0; | 
|---|
| 102 | } | 
|---|
| 103 | virtual ~QDateTimeParser(); | 
|---|
| 104 |  | 
|---|
| 105 | enum Section { | 
|---|
| 106 | NoSection     = 0x00000, | 
|---|
| 107 | AmPmSection   = 0x00001, | 
|---|
| 108 | MSecSection   = 0x00002, | 
|---|
| 109 | SecondSection = 0x00004, | 
|---|
| 110 | MinuteSection = 0x00008, | 
|---|
| 111 | Hour12Section   = 0x00010, | 
|---|
| 112 | Hour24Section   = 0x00020, | 
|---|
| 113 | TimeZoneSection = 0x00040, | 
|---|
| 114 | HourSectionMask = (Hour12Section | Hour24Section), | 
|---|
| 115 | TimeSectionMask = (MSecSection | SecondSection | MinuteSection | | 
|---|
| 116 | HourSectionMask | AmPmSection | TimeZoneSection), | 
|---|
| 117 |  | 
|---|
| 118 | DaySection         = 0x00100, | 
|---|
| 119 | MonthSection       = 0x00200, | 
|---|
| 120 | YearSection        = 0x00400, | 
|---|
| 121 | YearSection2Digits = 0x00800, | 
|---|
| 122 | YearSectionMask = YearSection | YearSection2Digits, | 
|---|
| 123 | DayOfWeekSectionShort = 0x01000, | 
|---|
| 124 | DayOfWeekSectionLong  = 0x02000, | 
|---|
| 125 | DayOfWeekSectionMask = DayOfWeekSectionShort | DayOfWeekSectionLong, | 
|---|
| 126 | DaySectionMask = DaySection | DayOfWeekSectionMask, | 
|---|
| 127 | DateSectionMask = DaySectionMask | MonthSection | YearSectionMask, | 
|---|
| 128 |  | 
|---|
| 129 | Internal             = 0x10000, | 
|---|
| 130 | FirstSection         = 0x20000 | Internal, | 
|---|
| 131 | LastSection          = 0x40000 | Internal, | 
|---|
| 132 | = 0x80000 | Internal, | 
|---|
| 133 |  | 
|---|
| 134 | NoSectionIndex = -1, | 
|---|
| 135 | FirstSectionIndex = -2, | 
|---|
| 136 | LastSectionIndex = -3, | 
|---|
| 137 | = -4 | 
|---|
| 138 | }; // extending qdatetimeedit.h's equivalent | 
|---|
| 139 | Q_DECLARE_FLAGS(Sections, Section) | 
|---|
| 140 |  | 
|---|
| 141 | struct Q_CORE_EXPORT SectionNode { | 
|---|
| 142 | Section type; | 
|---|
| 143 | mutable int pos; | 
|---|
| 144 | int count; | 
|---|
| 145 | int zeroesAdded; | 
|---|
| 146 |  | 
|---|
| 147 | static QString name(Section s); | 
|---|
| 148 | QString name() const { return name(type); } | 
|---|
| 149 | QString format() const; | 
|---|
| 150 | int maxChange() const; | 
|---|
| 151 | }; | 
|---|
| 152 |  | 
|---|
| 153 | enum State { // duplicated from QValidator | 
|---|
| 154 | Invalid, | 
|---|
| 155 | Intermediate, | 
|---|
| 156 | Acceptable | 
|---|
| 157 | }; | 
|---|
| 158 |  | 
|---|
| 159 | struct StateNode { | 
|---|
| 160 | StateNode() : state(Invalid), padded(0), conflicts(false) {} | 
|---|
| 161 | StateNode(const QDateTime &val, State ok=Acceptable, int pad=0, bool bad=false) | 
|---|
| 162 | : value(val), state(ok), padded(pad), conflicts(bad) {} | 
|---|
| 163 | QDateTime value; | 
|---|
| 164 | State state; | 
|---|
| 165 | int padded; | 
|---|
| 166 | bool conflicts; | 
|---|
| 167 | }; | 
|---|
| 168 |  | 
|---|
| 169 | enum AmPm { | 
|---|
| 170 | AmText, | 
|---|
| 171 | PmText | 
|---|
| 172 | }; | 
|---|
| 173 |  | 
|---|
| 174 | enum Case { | 
|---|
| 175 | UpperCase, | 
|---|
| 176 | LowerCase | 
|---|
| 177 | }; | 
|---|
| 178 |  | 
|---|
| 179 | StateNode parse(const QString &input, int position, | 
|---|
| 180 | const QDateTime &defaultValue, bool fixup) const; | 
|---|
| 181 | bool fromString(const QString &text, QDate *date, QTime *time) const; | 
|---|
| 182 | bool fromString(const QString &text, QDateTime* datetime) const; | 
|---|
| 183 | bool parseFormat(QStringView format); | 
|---|
| 184 |  | 
|---|
| 185 | enum FieldInfoFlag { | 
|---|
| 186 | Numeric = 0x01, | 
|---|
| 187 | FixedWidth = 0x02, | 
|---|
| 188 | AllowPartial = 0x04, | 
|---|
| 189 | Fraction = 0x08 | 
|---|
| 190 | }; | 
|---|
| 191 | Q_DECLARE_FLAGS(FieldInfo, FieldInfoFlag) | 
|---|
| 192 |  | 
|---|
| 193 | FieldInfo fieldInfo(int index) const; | 
|---|
| 194 |  | 
|---|
| 195 | void setDefaultLocale(const QLocale &loc) { defaultLocale = loc; } | 
|---|
| 196 | virtual QString displayText() const { return m_text; } | 
|---|
| 197 | void setCalendar(const QCalendar &calendar); | 
|---|
| 198 |  | 
|---|
| 199 | private: | 
|---|
| 200 | int sectionMaxSize(Section s, int count) const; | 
|---|
| 201 | QString sectionText(const QString &text, int sectionIndex, int index) const; | 
|---|
| 202 | StateNode scanString(const QDateTime &defaultValue, bool fixup) const; | 
|---|
| 203 | struct ParsedSection { | 
|---|
| 204 | int value; | 
|---|
| 205 | int used; | 
|---|
| 206 | int zeroes; | 
|---|
| 207 | State state; | 
|---|
| 208 | constexpr ParsedSection(State ok = Invalid, | 
|---|
| 209 | int val = 0, int read = 0, int zs = 0) | 
|---|
| 210 | : value(ok == Invalid ? -1 : val), used(read), zeroes(zs), state(ok) | 
|---|
| 211 | {} | 
|---|
| 212 | }; | 
|---|
| 213 | ParsedSection parseSection(const QDateTime ¤tValue, int sectionIndex, int offset) const; | 
|---|
| 214 | int findMonth(const QString &str1, int monthstart, int sectionIndex, | 
|---|
| 215 | int year, QString *monthName = nullptr, int *used = nullptr) const; | 
|---|
| 216 | int findDay(const QString &str1, int intDaystart, int sectionIndex, | 
|---|
| 217 | QString *dayName = nullptr, int *used = nullptr) const; | 
|---|
| 218 | ParsedSection findUtcOffset(QStringView str) const; | 
|---|
| 219 | ParsedSection findTimeZoneName(QStringView str, const QDateTime &when) const; | 
|---|
| 220 | ParsedSection findTimeZone(QStringView str, const QDateTime &when, | 
|---|
| 221 | int maxVal, int minVal) const; | 
|---|
| 222 | // Implemented in qdatetime.cpp: | 
|---|
| 223 | static int startsWithLocalTimeZone(const QStringView name); | 
|---|
| 224 |  | 
|---|
| 225 | enum AmPmFinder { | 
|---|
| 226 | Neither = -1, | 
|---|
| 227 | AM = 0, | 
|---|
| 228 | PM = 1, | 
|---|
| 229 | PossibleAM = 2, | 
|---|
| 230 | PossiblePM = 3, | 
|---|
| 231 | PossibleBoth = 4 | 
|---|
| 232 | }; | 
|---|
| 233 | AmPmFinder findAmPm(QString &str, int index, int *used = nullptr) const; | 
|---|
| 234 |  | 
|---|
| 235 | bool potentialValue(QStringView str, int min, int max, int index, | 
|---|
| 236 | const QDateTime ¤tValue, int insert) const; | 
|---|
| 237 | bool potentialValue(const QString &str, int min, int max, int index, | 
|---|
| 238 | const QDateTime ¤tValue, int insert) const | 
|---|
| 239 | { | 
|---|
| 240 | return potentialValue(QStringView(str), min, max, index, currentValue, insert); | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | protected: // for the benefit of QDateTimeEditPrivate | 
|---|
| 244 | int sectionSize(int index) const; | 
|---|
| 245 | int sectionMaxSize(int index) const; | 
|---|
| 246 | int sectionPos(int index) const; | 
|---|
| 247 | int sectionPos(const SectionNode &sn) const; | 
|---|
| 248 |  | 
|---|
| 249 | const SectionNode §ionNode(int index) const; | 
|---|
| 250 | Section sectionType(int index) const; | 
|---|
| 251 | QString sectionText(int sectionIndex) const; | 
|---|
| 252 | int getDigit(const QDateTime &dt, int index) const; | 
|---|
| 253 | bool setDigit(QDateTime &t, int index, int newval) const; | 
|---|
| 254 |  | 
|---|
| 255 | int absoluteMax(int index, const QDateTime &value = QDateTime()) const; | 
|---|
| 256 | int absoluteMin(int index) const; | 
|---|
| 257 |  | 
|---|
| 258 | bool skipToNextSection(int section, const QDateTime ¤t, QStringView sectionText) const; | 
|---|
| 259 | bool skipToNextSection(int section, const QDateTime ¤t, const QString §ionText) const | 
|---|
| 260 | { | 
|---|
| 261 | return skipToNextSection(section, current, QStringView(sectionText)); | 
|---|
| 262 | } | 
|---|
| 263 | QString stateName(State s) const; | 
|---|
| 264 | QString getAmPmText(AmPm ap, Case cs) const; | 
|---|
| 265 |  | 
|---|
| 266 | virtual QDateTime getMinimum() const; | 
|---|
| 267 | virtual QDateTime getMaximum() const; | 
|---|
| 268 | virtual int cursorPosition() const { return -1; } | 
|---|
| 269 | virtual QLocale locale() const { return defaultLocale; } | 
|---|
| 270 |  | 
|---|
| 271 | mutable int currentSectionIndex; | 
|---|
| 272 | Sections display; | 
|---|
| 273 | /* | 
|---|
| 274 | This stores the most recently selected day. | 
|---|
| 275 | It is useful when considering the following scenario: | 
|---|
| 276 |  | 
|---|
| 277 | 1. Date is: 31/01/2000 | 
|---|
| 278 | 2. User increments month: 29/02/2000 | 
|---|
| 279 | 3. User increments month: 31/03/2000 | 
|---|
| 280 |  | 
|---|
| 281 | At step 1, cachedDay stores 31. At step 2, the 31 is invalid for February, so the cachedDay is not updated. | 
|---|
| 282 | At step 3, the month is changed to March, for which 31 is a valid day. Since 29 < 31, the day is set to cachedDay. | 
|---|
| 283 | This is good for when users have selected their desired day and are scrolling up or down in the month or year section | 
|---|
| 284 | and do not want smaller months (or non-leap years) to alter the day that they chose. | 
|---|
| 285 | */ | 
|---|
| 286 | mutable int cachedDay; | 
|---|
| 287 | mutable QString m_text; | 
|---|
| 288 | QList<SectionNode> sectionNodes; | 
|---|
| 289 | SectionNode first, last, none, ; | 
|---|
| 290 | QStringList separators; | 
|---|
| 291 | QString displayFormat; | 
|---|
| 292 | QLocale defaultLocale; | 
|---|
| 293 | QMetaType::Type parserType; | 
|---|
| 294 | bool fixday; | 
|---|
| 295 | Context context; | 
|---|
| 296 | QCalendar calendar; | 
|---|
| 297 | }; | 
|---|
| 298 | Q_DECLARE_TYPEINFO(QDateTimeParser::SectionNode, Q_PRIMITIVE_TYPE); | 
|---|
| 299 |  | 
|---|
| 300 | Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2); | 
|---|
| 301 |  | 
|---|
| 302 | Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections) | 
|---|
| 303 | Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo) | 
|---|
| 304 |  | 
|---|
| 305 | QT_END_NAMESPACE | 
|---|
| 306 |  | 
|---|
| 307 | #endif // QDATETIME_P_H | 
|---|
| 308 |  | 
|---|