1/****************************************************************************
2**
3** Copyright (C) 2016 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#ifndef QT_BOOTSTRAPPED
61# include "QtCore/qvariant.h"
62#endif
63#include "QtCore/qvector.h"
64#include "QtCore/qcoreapplication.h"
65
66QT_REQUIRE_CONFIG(datetimeparser);
67
68#define QDATETIMEEDIT_TIME_MIN QTime(0, 0) // Prefer QDate::startOfDay()
69#define QDATETIMEEDIT_TIME_MAX QTime(23, 59, 59, 999) // Prefer QDate::endOfDay()
70#define QDATETIMEEDIT_DATE_MIN QDate(100, 1, 1)
71#define QDATETIMEEDIT_COMPAT_DATE_MIN QDate(1752, 9, 14)
72#define QDATETIMEEDIT_DATE_MAX QDate(9999, 12, 31)
73#define QDATETIMEEDIT_DATE_INITIAL QDate(2000, 1, 1)
74
75QT_BEGIN_NAMESPACE
76
77class Q_CORE_EXPORT QDateTimeParser
78{
79 Q_DECLARE_TR_FUNCTIONS(QDateTimeParser)
80public:
81 enum Context {
82 FromString,
83 DateTimeEdit
84 };
85 QDateTimeParser(QVariant::Type t, Context ctx)
86 : currentSectionIndex(-1), display(nullptr), cachedDay(-1), parserType(t),
87 fixday(false), spec(Qt::LocalTime), context(ctx)
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 CalendarPopupSection = 0x80000 | Internal,
133
134 NoSectionIndex = -1,
135 FirstSectionIndex = -2,
136 LastSectionIndex = -3,
137 CalendarPopupIndex = -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 QString input;
164 QDateTime value;
165 State state;
166 int padded;
167 bool conflicts;
168 };
169
170 enum AmPm {
171 AmText,
172 PmText
173 };
174
175 enum Case {
176 UpperCase,
177 LowerCase
178 };
179
180#if QT_CONFIG(datestring)
181 StateNode parse(QString input, int position, const QDateTime &defaultValue, bool fixup) const;
182 bool fromString(const QString &text, QDate *date, QTime *time) const;
183#endif
184 bool parseFormat(const QString &format);
185
186 enum FieldInfoFlag {
187 Numeric = 0x01,
188 FixedWidth = 0x02,
189 AllowPartial = 0x04,
190 Fraction = 0x08
191 };
192 Q_DECLARE_FLAGS(FieldInfo, FieldInfoFlag)
193
194 FieldInfo fieldInfo(int index) const;
195
196 void setDefaultLocale(const QLocale &loc) { defaultLocale = loc; }
197 virtual QString displayText() const { return text; }
198
199private:
200 int sectionMaxSize(Section s, int count) const;
201 QString sectionText(const QString &text, int sectionIndex, int index) const;
202#if QT_CONFIG(datestring)
203 StateNode scanString(const QDateTime &defaultValue,
204 bool fixup, QString *input) const;
205 struct ParsedSection {
206 int value;
207 int used;
208 int zeroes;
209 State state;
210 Q_DECL_CONSTEXPR ParsedSection(State ok = Invalid,
211 int val = 0, int read = 0, int zs = 0)
212 : value(ok == Invalid ? -1 : val), used(read), zeroes(zs), state(ok)
213 {}
214 };
215 ParsedSection parseSection(const QDateTime &currentValue, int sectionIndex,
216 int offset, QString *text) const;
217 int findMonth(const QString &str1, int monthstart, int sectionIndex,
218 QString *monthName = nullptr, int *used = nullptr) const;
219 int findDay(const QString &str1, int intDaystart, int sectionIndex,
220 QString *dayName = nullptr, int *used = nullptr) const;
221 ParsedSection findTimeZone(QStringRef str, const QDateTime &when,
222 int maxVal, int minVal) const;
223#if QT_CONFIG(timezone)
224 // Implemented in qdatetime.cpp:
225 static int startsWithLocalTimeZone(const QStringRef name);
226#endif
227
228 enum AmPmFinder {
229 Neither = -1,
230 AM = 0,
231 PM = 1,
232 PossibleAM = 2,
233 PossiblePM = 3,
234 PossibleBoth = 4
235 };
236 AmPmFinder findAmPm(QString &str, int index, int *used = nullptr) const;
237#endif // datestring
238
239 bool potentialValue(const QStringRef &str, int min, int max, int index,
240 const QDateTime &currentValue, int insert) const;
241 bool potentialValue(const QString &str, int min, int max, int index,
242 const QDateTime &currentValue, int insert) const
243 {
244 return potentialValue(QStringRef(&str), min, max, index, currentValue, insert);
245 }
246
247protected: // for the benefit of QDateTimeEditPrivate
248 int sectionSize(int index) const;
249 int sectionMaxSize(int index) const;
250 int sectionPos(int index) const;
251 int sectionPos(const SectionNode &sn) const;
252
253 const SectionNode &sectionNode(int index) const;
254 Section sectionType(int index) const;
255 QString sectionText(int sectionIndex) const;
256 int getDigit(const QDateTime &dt, int index) const;
257 bool setDigit(QDateTime &t, int index, int newval) const;
258
259 int absoluteMax(int index, const QDateTime &value = QDateTime()) const;
260 int absoluteMin(int index) const;
261
262 bool skipToNextSection(int section, const QDateTime &current, const QStringRef &sectionText) const;
263 bool skipToNextSection(int section, const QDateTime &current, const QString &sectionText) const
264 {
265 return skipToNextSection(section, current, QStringRef(&sectionText));
266 }
267 QString stateName(State s) const;
268 virtual QDateTime getMinimum() const;
269 virtual QDateTime getMaximum() const;
270 virtual int cursorPosition() const { return -1; }
271 virtual QString getAmPmText(AmPm ap, Case cs) const;
272 virtual QLocale locale() const { return defaultLocale; }
273
274 mutable int currentSectionIndex;
275 Sections display;
276 /*
277 This stores the most recently selected day.
278 It is useful when considering the following scenario:
279
280 1. Date is: 31/01/2000
281 2. User increments month: 29/02/2000
282 3. User increments month: 31/03/2000
283
284 At step 1, cachedDay stores 31. At step 2, the 31 is invalid for February, so the cachedDay is not updated.
285 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.
286 This is good for when users have selected their desired day and are scrolling up or down in the month or year section
287 and do not want smaller months (or non-leap years) to alter the day that they chose.
288 */
289 mutable int cachedDay;
290 mutable QString text;
291 QVector<SectionNode> sectionNodes;
292 SectionNode first, last, none, popup;
293 QStringList separators;
294 QString displayFormat;
295 QLocale defaultLocale;
296 QVariant::Type parserType;
297 bool fixday;
298 Qt::TimeSpec spec; // spec if used by QDateTimeEdit
299 Context context;
300};
301Q_DECLARE_TYPEINFO(QDateTimeParser::SectionNode, Q_PRIMITIVE_TYPE);
302
303Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2);
304
305Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections)
306Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo)
307
308QT_END_NAMESPACE
309
310#endif // QDATETIME_P_H
311