1/****************************************************************************
2**
3** Copyright (C) 2019 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/qdatetime.h"
58#include "QtCore/qstringlist.h"
59#include "QtCore/qlocale.h"
60#include "QtCore/qcalendar.h"
61#ifndef QT_BOOTSTRAPPED
62# include "QtCore/qvariant.h"
63#endif
64#include "QtCore/qvector.h"
65#include "QtCore/qcoreapplication.h"
66
67QT_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
76QT_BEGIN_NAMESPACE
77
78class Q_CORE_EXPORT QDateTimeParser
79{
80 Q_DECLARE_TR_FUNCTIONS(QDateTimeParser)
81public:
82 enum Context {
83 FromString,
84 DateTimeEdit
85 };
86 QDateTimeParser(QMetaType::Type t, Context ctx, const QCalendar &cal = QCalendar())
87 : currentSectionIndex(-1), cachedDay(-1), parserType(t),
88 fixday(false), context(ctx), calendar(cal)
89 {
90 defaultLocale = QLocale::system();
91 first.type = FirstSection;
92 first.pos = -1;
93 first.count = -1;
94 first.zeroesAdded = 0;
95 last.type = LastSection;
96 last.pos = -1;
97 last.count = -1;
98 last.zeroesAdded = 0;
99 none.type = NoSection;
100 none.pos = -1;
101 none.count = -1;
102 none.zeroesAdded = 0;
103 }
104 virtual ~QDateTimeParser();
105
106 enum Section {
107 NoSection = 0x00000,
108 AmPmSection = 0x00001,
109 MSecSection = 0x00002,
110 SecondSection = 0x00004,
111 MinuteSection = 0x00008,
112 Hour12Section = 0x00010,
113 Hour24Section = 0x00020,
114 TimeZoneSection = 0x00040,
115 HourSectionMask = (Hour12Section | Hour24Section),
116 TimeSectionMask = (MSecSection | SecondSection | MinuteSection |
117 HourSectionMask | AmPmSection | TimeZoneSection),
118
119 DaySection = 0x00100,
120 MonthSection = 0x00200,
121 YearSection = 0x00400,
122 YearSection2Digits = 0x00800,
123 YearSectionMask = YearSection | YearSection2Digits,
124 DayOfWeekSectionShort = 0x01000,
125 DayOfWeekSectionLong = 0x02000,
126 DayOfWeekSectionMask = DayOfWeekSectionShort | DayOfWeekSectionLong,
127 DaySectionMask = DaySection | DayOfWeekSectionMask,
128 DateSectionMask = DaySectionMask | MonthSection | YearSectionMask,
129
130 Internal = 0x10000,
131 FirstSection = 0x20000 | Internal,
132 LastSection = 0x40000 | Internal,
133 CalendarPopupSection = 0x80000 | Internal,
134
135 NoSectionIndex = -1,
136 FirstSectionIndex = -2,
137 LastSectionIndex = -3,
138 CalendarPopupIndex = -4
139 }; // extending qdatetimeedit.h's equivalent
140 Q_DECLARE_FLAGS(Sections, Section)
141
142 struct Q_CORE_EXPORT SectionNode {
143 Section type;
144 mutable int pos;
145 int count;
146 int zeroesAdded;
147
148 static QString name(Section s);
149 QString name() const { return name(s: type); }
150 QString format() const;
151 int maxChange() const;
152 };
153
154 enum State { // duplicated from QValidator
155 Invalid,
156 Intermediate,
157 Acceptable
158 };
159
160 struct StateNode {
161 StateNode() : state(Invalid), padded(0), conflicts(false) {}
162 StateNode(const QDateTime &val, State ok=Acceptable, int pad=0, bool bad=false)
163 : value(val), state(ok), padded(pad), conflicts(bad) {}
164 QString input;
165 QDateTime value;
166 State state;
167 int padded;
168 bool conflicts;
169 };
170
171 enum AmPm {
172 AmText,
173 PmText
174 };
175
176 enum Case {
177 UpperCase,
178 LowerCase
179 };
180
181#if QT_CONFIG(datestring)
182 StateNode parse(QString input, int position, const QDateTime &defaultValue, bool fixup) const;
183 bool fromString(const QString &text, QDate *date, QTime *time) const;
184 bool fromString(const QString &text, QDateTime* datetime) const;
185#endif
186 bool parseFormat(const QString &format);
187
188 enum FieldInfoFlag {
189 Numeric = 0x01,
190 FixedWidth = 0x02,
191 AllowPartial = 0x04,
192 Fraction = 0x08
193 };
194 Q_DECLARE_FLAGS(FieldInfo, FieldInfoFlag)
195
196 FieldInfo fieldInfo(int index) const;
197
198 void setDefaultLocale(const QLocale &loc) { defaultLocale = loc; }
199 virtual QString displayText() const { return text; }
200 void setCalendar(const QCalendar &calendar);
201
202private:
203 int sectionMaxSize(Section s, int count) const;
204 QString sectionText(const QString &text, int sectionIndex, int index) const;
205#if QT_CONFIG(datestring)
206 StateNode scanString(const QDateTime &defaultValue,
207 bool fixup, QString *input) const;
208 struct ParsedSection {
209 int value;
210 int used;
211 int zeroes;
212 State state;
213 Q_DECL_CONSTEXPR ParsedSection(State ok = Invalid,
214 int val = 0, int read = 0, int zs = 0)
215 : value(ok == Invalid ? -1 : val), used(read), zeroes(zs), state(ok)
216 {}
217 };
218 ParsedSection parseSection(const QDateTime &currentValue, int sectionIndex,
219 int offset, QString *text) const;
220 int findMonth(const QString &str1, int monthstart, int sectionIndex,
221 int year, QString *monthName = nullptr, int *used = nullptr) const;
222 int findDay(const QString &str1, int intDaystart, int sectionIndex,
223 QString *dayName = nullptr, int *used = nullptr) const;
224 ParsedSection findUtcOffset(QStringRef str) const;
225 ParsedSection findTimeZoneName(QStringRef str, const QDateTime &when) const;
226 ParsedSection findTimeZone(QStringRef str, const QDateTime &when,
227 int maxVal, int minVal) const;
228 // Implemented in qdatetime.cpp:
229 static int startsWithLocalTimeZone(const QStringRef name);
230
231 enum AmPmFinder {
232 Neither = -1,
233 AM = 0,
234 PM = 1,
235 PossibleAM = 2,
236 PossiblePM = 3,
237 PossibleBoth = 4
238 };
239 AmPmFinder findAmPm(QString &str, int index, int *used = nullptr) const;
240#endif // datestring
241
242 bool potentialValue(const QStringRef &str, int min, int max, int index,
243 const QDateTime &currentValue, int insert) const;
244 bool potentialValue(const QString &str, int min, int max, int index,
245 const QDateTime &currentValue, int insert) const
246 {
247 return potentialValue(str: QStringRef(&str), min, max, index, currentValue, insert);
248 }
249
250protected: // for the benefit of QDateTimeEditPrivate
251 int sectionSize(int index) const;
252 int sectionMaxSize(int index) const;
253 int sectionPos(int index) const;
254 int sectionPos(const SectionNode &sn) const;
255
256 const SectionNode &sectionNode(int index) const;
257 Section sectionType(int index) const;
258 QString sectionText(int sectionIndex) const;
259 int getDigit(const QDateTime &dt, int index) const;
260 bool setDigit(QDateTime &t, int index, int newval) const;
261
262 int absoluteMax(int index, const QDateTime &value = QDateTime()) const;
263 int absoluteMin(int index) const;
264
265 bool skipToNextSection(int section, const QDateTime &current, const QStringRef &sectionText) const;
266 bool skipToNextSection(int section, const QDateTime &current, const QString &sectionText) const
267 {
268 return skipToNextSection(section, current, sectionText: QStringRef(&sectionText));
269 }
270 QString stateName(State s) const;
271 virtual QDateTime getMinimum() const;
272 virtual QDateTime getMaximum() const;
273 virtual int cursorPosition() const { return -1; }
274 virtual QString getAmPmText(AmPm ap, Case cs) const;
275 virtual QLocale locale() const { return defaultLocale; }
276
277 mutable int currentSectionIndex;
278 Sections display;
279 /*
280 This stores the most recently selected day.
281 It is useful when considering the following scenario:
282
283 1. Date is: 31/01/2000
284 2. User increments month: 29/02/2000
285 3. User increments month: 31/03/2000
286
287 At step 1, cachedDay stores 31. At step 2, the 31 is invalid for February, so the cachedDay is not updated.
288 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.
289 This is good for when users have selected their desired day and are scrolling up or down in the month or year section
290 and do not want smaller months (or non-leap years) to alter the day that they chose.
291 */
292 mutable int cachedDay;
293 mutable QString text;
294 QVector<SectionNode> sectionNodes;
295 SectionNode first, last, none, popup;
296 QStringList separators;
297 QString displayFormat;
298 QLocale defaultLocale;
299 QMetaType::Type parserType;
300 bool fixday;
301 Context context;
302 QCalendar calendar;
303};
304Q_DECLARE_TYPEINFO(QDateTimeParser::SectionNode, Q_PRIMITIVE_TYPE);
305
306Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2);
307
308Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections)
309Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo)
310
311QT_END_NAMESPACE
312
313#endif // QDATETIME_P_H
314

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