// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \example time/calendarbackendplugin
    \title Calendar Backend Plugin Example
    \examplecategory {Data Processing & I/O}
    \ingroup examples-time
    \ingroup corelib_examples
    \brief QCalendar example illustrating user-supplied custom calendars.

    \image calendarwindow_transition.png {Calendar widget showing October
           1582 with the Julian to Gregorian transition gap}

    \section1 Introduction

    There are numerous different calendar systems in use around the globe.
    Qt has built-in support for some of them (see \l{QCalendar::}{System}),
    but can't provide general support due to their high number.
    Additional calendar systems can be provided by implementing a
    custom QCalendarBackend, which is a private API.

    This example demonstrates how to write a custom calendar backend
    and how to use the low-level plugin API to extend an application
    to user-selectable calendars.
    Many countries transitioned from the Julian to the Gregorian calendar
    at some point in their history, and this custom calendar backend will
    implement the respective calendar as an example. The custom backend
    is compiled into a plugin and loaded at runtime by the main application.
    The exact transition date, different for various regions, is provided
    as a string to the plugin and can be determined by the user.

    \section1 Calendar backend

    The calendar backend class must inherit from \c QCalendarBackend and implement its
    pure virtual functions in a \c thread-safe way. It may also override
    some other virtual functions as needed.

    \section2 Example implementation

    This example inherits from the already existing \c QRomanCalendar,
    which in turn inherits from the \c QCalendarBackend and implements some of
    its virtual functions.
    It's constructive to do this because the transition calendar shares,
    with both Julian and Gregorian calendars, parts provided by the Roman calendar.

    Here is the class declaration of \c JulianGregorianCalendar:

    \snippet time/calendarbackendplugin/plugin/calendarbackend.h 0

    The \c QDate passed to the constructor - \a endJulian - is the date of the last day
    of the Julian calendar. The calendar will automatically calculate the shift for a given
    year, e.g in 1582, 10 days were omitted, but in 1700, 12 days had to be omitted.
    The calendar backend is registered under \a name and a calendar instance can be
    created using that name. The class only overrides functions where the two calendars
    it combines differ from the Roman base. It has instances of the Julian and Gregorian
    calendars to which these functions can delegate.

    \section2 Julian Day conversions

    \c dateToJulianDay(int year, int month, int day, qint64 *jd) computes the Julian
    day number corresponding to the specified \a year, \a month and \a day.
    Returns \c true and sets \a jd if there is such a date in this calendar; otherwise,
    returns \c false.

    \snippet time/calendarbackendplugin/plugin/calendarbackend.cpp 0

    \c julianDayToDate(qint64 jd) computes year, month and day in this calendar for the given
    Julian day number, \a jd. If the given day falls outside this calendar's scope,
    the return value for \c isValid() is \c false. In this example, if the given date
    falls in the gap jumped over by the transition from Julian to Gregorian calendar,
    it is out of scope.

    \snippet time/calendarbackendplugin/plugin/calendarbackend.cpp 1

    \section2 Locale support

    A calendar may, in general, have its own naming of months of the year
    and days of the week. These must be suitably localized to be intelligible
    to all users. By default the backend baseclass takes care of week day
    names for us, which is entirely sufficient for these Julian/Gregorian
    transition calendars.

    Although a backend can directly override the month naming methods, the
    baseclass version of these can be customized by implementing
    \c localeMonthData() and \c localeMonthIndexData() to provide tables
    of localized month names. Since the Julian and Gregorian
    calendars use the same month naming, they inherit that customization
    from a common base, \c QRomanCalendar. This also means the custom
    calendar can use the same names, again by inheriting from that base.
    This takes care of localization.

    \sa QCalendarWidget, QCalendar, QDate, QLocale

    \section1 Plugin

    Qt applications can be extended through plugins. This requires the application to
    detect and load plugins using \l{QPluginLoader}.

    \section2 Writing a plugin

    To write a plugin, the first thing that has to be done is to
    create a pure virtual class that defines the interface between
    plugin and application.

    In this example the following interface was used:

    \snippet time/calendarbackendplugin/common/calendarBackendInterface.h 0

    and register it in the Qt meta-object system:

    \snippet time/calendarbackendplugin/common/calendarBackendInterface.h 1

    \l{<QtPlugin>::}{Q_DECLARE_INTERFACE()} macro is used to associate the
    \c ClassName (here: \c RequestedCalendarInterface) with the defined
    \c Identifier (here: \c RequestedCalendarInterface_iid). The \c Identifier
    must be unique. This interface can be implemented by plugins that load
    other calendars, interpreting \c loadCalendar()'s string parameter in
    various ways. It isn't limited to this particular plugin that will be implemented
    using it, so it has a generic name, not one specific to this particular backend.

    Then a plugin class that inherits from \l{QObject} and from the interface is created.

    \snippet time/calendarbackendplugin/plugin/calendarplugin.h 0

    \l{<QtPlugin>::}{Q_PLUGIN_METADATA()} and \l{QObject::}{Q_INTERFACES()}
    are being used to declare meta data that was also declared
    in the interface class and to tell Qt which interface the class implements.

    \sa QtPlugin

    This plugin instantiates and registers a custom calendar backend which
    can in turn be used to instantiate \l{QCalendar} by the application at
    any point.

    Qt Plugins are stored in a single shared library (a DLL) and \l{QPluginLoader}
    is used for detecting and dynamically loading the plugin file (for more
    see \l{How to Create Qt Plugins}).

    \section2 Loading the plugin

    \l{QPluginLoader} checks if the plugin's version of Qt
    is the same as that of the application and
    provides direct access to a Qt plugin.

    Here is the use of \l QPluginLoader in the example:

    \snippet time/calendarbackendplugin/application/main.cpp 0

    First, an instance of a QPluginLoader object needs to be initialized. Next,
    it has to be specified which plugin to load by passing a DLL file name to
    \l{QPluginLoader::}{setFileName()}. Then, by using \l{QPluginLoader::}{load()},
    the plugin file is dynamically loaded. At the end, a call to \l{QObject::}{qobject_cast()}
    tests whether a plugin implements a given interface. \l{QObject::}{qobject_cast()}
    uses \l{QPluginLoader::}{instance()} to access the root component in the plugin.
    If the plugin has been loaded correctly, its functions should be available.

    \sa QPluginLoader

    \section2 Instantiating the backend

    In this example there is only one function in the plugin. \c loadCalendar()
    is responsible for registering the custom calendar backend in
    \c QCalendarRegistry with given date of the transition and names.

    \snippet time/calendarbackendplugin/plugin/calendarplugin.cpp 0

    String argument for \c loadCalendar() is supplied by the user via command
    line arguments. Then, the date of transition from the Julian calendar to
    the Gregorian is extracted by splitting the given string.
    After validation, a custom backend object is created.
    The backend must be registered before it can be used in \l{QCalendar},
    using the \c registerCustomBackend() method.
    Once a backend is registered, a QCalendar can be instantiated with
    the respective \l{QCalendar::}{SystemId} or \c name.

    Here is the use of \c loadCalendar in the \c main:

    \snippet time/calendarbackendplugin/application/main.cpp 1

    \section2 Extending QCalendarWidget

    By creating a \l{QCalendar} instance with a specific calendar as a backend,
    it is possible to provide \l{QCalendarWidget} with that backend and
    visualize it.

    \snippet time/calendarbackendplugin/application/main.cpp 2
*/
