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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/time/qdatetimeparser_p.h