File indexing completed on 2024-11-10 04:16:02

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef KOPENINGHOURS_OPENINGHOURS_H
0008 #define KOPENINGHOURS_OPENINGHOURS_H
0009 
0010 #include "kopeninghours_export.h"
0011 
0012 #include <QExplicitlySharedDataPointer>
0013 #include <QMetaType>
0014 
0015 class QByteArray;
0016 class QDateTime;
0017 class QJsonObject;
0018 class QString;
0019 class QTimeZone;
0020 
0021 /** OSM opening hours parsing and evaluation. */
0022 namespace KOpeningHours {
0023 
0024 class Interval;
0025 class OpeningHoursPrivate;
0026 
0027 /** An OSM opening hours specification.
0028  *  This is the main entry point into this library, providing both a way to parse opening hours expressions
0029  *  and to evaluate them.
0030  *  @see https://wiki.openstreetmap.org/wiki/Key:opening_hours
0031  */
0032 class KOPENINGHOURS_EXPORT OpeningHours
0033 {
0034     Q_GADGET
0035     Q_PROPERTY(Error error READ error)
0036     Q_PROPERTY(QString normalizedExpression READ normalizedExpressionString)
0037     Q_PROPERTY(float latitude READ latitude WRITE setLatitude)
0038     Q_PROPERTY(float longitude READ longitude WRITE setLongitude)
0039 #ifndef KOPENINGHOURS_VALIDATOR_ONLY
0040     Q_PROPERTY(QString region READ region WRITE setRegion)
0041 #endif
0042     Q_PROPERTY(QString timeZone READ timeZoneId WRITE setTimeZoneId)
0043 public:
0044     /** Evaluation modes for opening hours expressions. */
0045     enum Mode {
0046         IntervalMode = 1, ///< Expressions that describe time ranges
0047         PointInTimeMode = 2, ///< Expressions that describe points in time
0048     };
0049     Q_DECLARE_FLAGS(Modes, Mode)
0050     Q_FLAG(Modes)
0051 
0052     /** Create an empty/invalid instance. */
0053     explicit OpeningHours();
0054 
0055     /** Parse OSM opening hours expression @p openingHours.
0056      *  @param modes Specify whether time interval and/or point in time expressions are expected.
0057      *  If @p openingHours doesn't match @p modes, error() return IncompatibleMode.
0058      */
0059     explicit OpeningHours(const QByteArray &openingHours, Modes modes = IntervalMode);
0060     /** Parse OSM opening hours expression @p openingHours.
0061      *  @param modes Specify whether time interval and/or point in time expressions are expected.
0062      *  If @p openingHours doesn't match @p modes, error() return IncompatibleMode.
0063      */
0064     explicit OpeningHours(const char *openingHours, std::size_t size, Modes modes = IntervalMode);
0065 
0066     OpeningHours(const OpeningHours&);
0067     OpeningHours(OpeningHours&&);
0068     ~OpeningHours();
0069 
0070     OpeningHours& operator=(const OpeningHours&);
0071     OpeningHours& operator=(OpeningHours&&);
0072 
0073     /** Parse OSM opening hours expression @p openingHours.
0074      *  @param modes Specify whether time interval and/or point in time expressions are expected.
0075      *  If @p openingHours doesn't match @p modes, error() return IncompatibleMode.
0076      *  Prefer this over creating new instances if you are processing <b>many</b> expressions
0077      *  at once.
0078      */
0079     void setExpression(const QByteArray &openingHours, Modes modes = IntervalMode);
0080     /** Parse OSM opening hours expression @p openingHours.
0081      *  @param modes Specify whether time interval and/or point in time expressions are expected.
0082      *  If @p openingHours doesn't match @p modes, error() return IncompatibleMode.
0083      *  Prefer this over creating new instances if you are processing <b>many</b> expressions
0084      *  at once.
0085      */
0086     void setExpression(const char *openingHours, std::size_t size, Modes modes = IntervalMode);
0087 
0088     /** Returns the OSM opening hours expression reconstructed from this object.
0089      * In many cases it will be the same as the expression given to the constructor
0090      * or to setExpression, but some normalization can happen as well, especially in
0091      * case of non-conform input.
0092      */
0093     QByteArray normalizedExpression() const;
0094 
0095     /** Returns a simplified OSM opening hours expression reconstructed from this object.
0096      * In many cases it will be the same as normalizedExpression(), but further
0097      * simplifications can happen, to make the expression shorter/simpler.
0098      */
0099     QByteArray simplifiedExpression() const;
0100 
0101     /** Geographic coordinate at which this expression should be evaluated.
0102      *  This is needed for expressions containing location-based variable time references,
0103      *  such as "sunset". If the expression requires a location, error() returns @c MissingLocation
0104      *  if no location has been specified.
0105      */
0106     Q_INVOKABLE void setLocation(float latitude, float longitude);
0107 
0108     float latitude() const;
0109     void setLatitude(float latitude);
0110     float longitude() const;
0111     void setLongitude(float longitude);
0112 
0113 #ifndef KOPENINGHOURS_VALIDATOR_ONLY
0114     /** ISO 3166-2 region or ISO 316-1 country in which this expression should be evaluated.
0115      *  This is needed for expressions containing public holiday references ("PH").
0116      *  If the expression references a public holiday, error() returns @c MissingRegion
0117      *  if no region has been specified, or if no holiday data is available for the specified region.
0118      */
0119     void setRegion(QStringView region);
0120     QString region() const;
0121 #endif
0122 
0123     /** Timezone in which this expression should be evaluated.
0124      *  If not specified, this assumes local time.
0125      */
0126     void setTimeZone(const QTimeZone &tz);
0127     QTimeZone timeZone() const;
0128 
0129     /** Error codes. */
0130     enum Error {
0131         Null, ///< no expression is set
0132         NoError, ///< there is no error, the expression is valid and can be used
0133         SyntaxError, ///< syntax error in the opening hours expression
0134         MissingRegion, ///< expression refers to public or school holidays, but that information is not available
0135         MissingLocation, ///< evaluation requires location information and those aren't set
0136         IncompatibleMode, ///< expression mode doesn't match the expected mode
0137         UnsupportedFeature, ///< expression uses a feature that isn't implemented/supported (yet)
0138         EvaluationError, ///< runtime error during evaluating the expression
0139     };
0140     Q_ENUM(Error)
0141 
0142     /** Error status of this expression. */
0143     Error error() const;
0144 
0145 #ifndef KOPENINGHOURS_VALIDATOR_ONLY
0146     /** Returns the interval containing @p dt. */
0147     Q_INVOKABLE KOpeningHours::Interval interval(const QDateTime &dt) const;
0148     /** Returns the interval immediately following @p interval. */
0149     Q_INVOKABLE KOpeningHours::Interval nextInterval(const KOpeningHours::Interval &interval) const;
0150 #endif
0151 
0152     /** Convert opening hours in schema.org JSON-LD format.
0153      *  This supports the following formats:
0154      *  - https://schema.org/openingHours
0155      *  - https://schema.org/openingHoursSpecification
0156      *  - https://schema.org/specialOpeningHoursSpecification
0157      */
0158     static OpeningHours fromJsonLd(const QJsonObject &obj);
0159 
0160 private:
0161     // for QML bindings
0162     Q_DECL_HIDDEN QString normalizedExpressionString() const;
0163     Q_DECL_HIDDEN QString timeZoneId() const;
0164     Q_DECL_HIDDEN void setTimeZoneId(const QString &tzId);
0165 
0166     QExplicitlySharedDataPointer<OpeningHoursPrivate> d;
0167 };
0168 
0169 }
0170 
0171 Q_DECLARE_METATYPE(KOpeningHours::OpeningHours)
0172 
0173 #endif // KOPENINGHOURS_OPENINGHOURS_H