QCalendar example illustrating the user-supplied plugin mechanism
This example demonstrates how to write a calendar backend plugin using a low-level API for extending Qt applications. Fixes: QTBUG-115200 Change-Id: If0b7f2552ba8c2203acdcbff238fb0ffa7cfca55 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
4079ecfb9b
commit
f071d4ee8a
@ -6,6 +6,7 @@ add_subdirectory(mimetypes)
|
||||
add_subdirectory(serialization)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(platform)
|
||||
add_subdirectory(time)
|
||||
if(QT_FEATURE_thread)
|
||||
add_subdirectory(threads)
|
||||
endif()
|
||||
|
@ -6,6 +6,7 @@ SUBDIRS = \
|
||||
mimetypes \
|
||||
serialization \
|
||||
tools \
|
||||
platform
|
||||
platform \
|
||||
time
|
||||
|
||||
qtConfig(thread): SUBDIRS += threads
|
||||
|
4
examples/corelib/time/CMakeLists.txt
Normal file
4
examples/corelib/time/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
add_subdirectory(calendarbackendplugin)
|
32
examples/corelib/time/calendarbackendplugin/CMakeLists.txt
Normal file
32
examples/corelib/time/calendarbackendplugin/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(JulianGregorianCalendar VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
add_subdirectory(plugin)
|
||||
add_subdirectory(application)
|
||||
|
||||
install(TARGETS calendarPlugin JulianGregorianCalendar
|
||||
BUNDLE DESTINATION .
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
qt_generate_deploy_app_script(
|
||||
TARGET calendarPlugin
|
||||
OUTPUT_SCRIPT deploy_script
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
)
|
||||
install(SCRIPT ${deploy_script})
|
||||
|
||||
qt_generate_deploy_app_script(
|
||||
TARGET JulianGregorianCalendar
|
||||
OUTPUT_SCRIPT deploy_script
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
)
|
||||
install(SCRIPT ${deploy_script})
|
@ -0,0 +1,23 @@
|
||||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(JulianGregorianCalendar VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Core)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Core)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
include_directories(../common/)
|
||||
|
||||
qt_add_executable(JulianGregorianCalendar
|
||||
../common/calendarBackendInterface.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(JulianGregorianCalendar
|
||||
PRIVATE
|
||||
Qt::Widgets
|
||||
Qt::Core
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
TEMPLATE = app
|
||||
TARGET = application
|
||||
INCLUDEPATH += . \
|
||||
../common/
|
||||
QT += core core-private widgets
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/datetime/calendarbackendplugin/application
|
||||
INSTALLS += target
|
||||
|
||||
SOURCES += main.cpp
|
||||
HEADERS += ../common/calendarBackendInterface.h
|
@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "calendarBackendInterface.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCalendar>
|
||||
#include <QCalendarWidget>
|
||||
#include <QCommandLineParser>
|
||||
#include <QPluginLoader>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
QCoreApplication::setApplicationName("JulianGregorianCalendar");
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("Calendar Backend Plugin Example");
|
||||
parser.addHelpOption();
|
||||
parser.addPositionalArgument("date; names",
|
||||
"Date of transition between "
|
||||
"Julian and Gregorian calendars "
|
||||
"as string in the format 'yyyy-MM-dd;'. Optionally, user can "
|
||||
"provide names for the calendar separated with ';'");
|
||||
parser.process(a);
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.isEmpty())
|
||||
parser.showHelp(1);
|
||||
if (args.at(0).isEmpty())
|
||||
parser.showHelp(1);
|
||||
//![0]
|
||||
QPluginLoader loader;
|
||||
loader.setFileName("../plugin/calendarPlugin");
|
||||
loader.load();
|
||||
if (!loader.isLoaded())
|
||||
return 1;
|
||||
auto *myplugin = qobject_cast<RequestedCalendarInterface*>(loader.instance());
|
||||
//![0]
|
||||
//![1]
|
||||
const auto cid = myplugin->loadCalendar(args.at(0));
|
||||
if (!cid.isValid()) {
|
||||
qWarning() << "Invalid ID";
|
||||
parser.showHelp(1);
|
||||
}
|
||||
const QCalendar calendar(cid);
|
||||
//![1]
|
||||
//![2]
|
||||
QCalendarWidget widget;
|
||||
widget.setCalendar(calendar);
|
||||
widget.show();
|
||||
QCalendar::YearMonthDay when = { 1582, 10, 4 };
|
||||
QCalendar julian = QCalendar(QCalendar::System::Julian);
|
||||
auto got = QDate::fromString(args.at(0).left(10), u"yyyy-MM-dd", julian);
|
||||
if (got.isValid())
|
||||
when = julian.partsFromDate(got);
|
||||
widget.setCurrentPage(when.year, when.month);
|
||||
//![2]
|
||||
return a.exec();
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += plugin \
|
||||
application
|
@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CALENDARINTERFACE_H
|
||||
#define CALENDARINTERFACE_H
|
||||
|
||||
#include <QCalendar>
|
||||
#include <QObject>
|
||||
|
||||
//![0]
|
||||
class RequestedCalendarInterface
|
||||
{
|
||||
public:
|
||||
RequestedCalendarInterface() = default;
|
||||
virtual QCalendar::SystemId loadCalendar(QAnyStringView requested) = 0;
|
||||
virtual ~RequestedCalendarInterface() = default;
|
||||
};
|
||||
//![0]
|
||||
QT_BEGIN_NAMESPACE
|
||||
//![1]
|
||||
#define RequestedCalendarInterface_iid \
|
||||
"org.qt-project.Qt.Examples.CalendarBackend.RequestedCalendarInterface/1.0"
|
||||
Q_DECLARE_INTERFACE(RequestedCalendarInterface, RequestedCalendarInterface_iid)
|
||||
//![1]
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // CALENDARINTERFACE_H
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@ -0,0 +1,186 @@
|
||||
// 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
|
||||
\brief QCalendar example illustrating user-supplied custom calendars.
|
||||
|
||||
\image calendarwindow_transition.png
|
||||
|
||||
\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
|
||||
*/
|
@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2024 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(calendarPlugin VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Core)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Core)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
include_directories(../common/)
|
||||
|
||||
qt_add_library(calendarPlugin SHARED
|
||||
../common/calendarBackendInterface.h
|
||||
calendarplugin.h
|
||||
calendarplugin.cpp
|
||||
calendarbackend.cpp
|
||||
calendarbackend.h
|
||||
)
|
||||
|
||||
target_link_libraries(calendarPlugin
|
||||
PRIVATE
|
||||
Qt::Widgets
|
||||
Qt::Core
|
||||
Qt::CorePrivate
|
||||
)
|
@ -0,0 +1,103 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "calendarbackend.h"
|
||||
|
||||
#include <QCalendar>
|
||||
|
||||
JulianGregorianCalendar::JulianGregorianCalendar(QDate endJulian, QAnyStringView name = {})
|
||||
: m_julianUntil(julian.partsFromDate(endJulian)),
|
||||
m_gregorianSince(gregorian.partsFromDate(endJulian.addDays(1))),
|
||||
m_name(name.isEmpty()
|
||||
? endJulian.toString(u"Julian until yyyy-MM-dd", julian)
|
||||
: name.toString())
|
||||
{
|
||||
Q_ASSERT_X(m_julianUntil.year < m_gregorianSince.year
|
||||
|| (m_julianUntil.year == m_gregorianSince.year
|
||||
&& (m_julianUntil.month < m_gregorianSince.month
|
||||
|| (m_julianUntil.month == m_gregorianSince.month
|
||||
&& m_julianUntil.day < m_gregorianSince.day))),
|
||||
"JulianGregorianCalendar::JulianGregorianCalendar()",
|
||||
"Perversely early date for Julian-to-Gregorian transition");
|
||||
}
|
||||
|
||||
QString JulianGregorianCalendar::name() const
|
||||
{
|
||||
return QStringLiteral("JulianGregorian");
|
||||
}
|
||||
|
||||
int JulianGregorianCalendar::daysInMonth(int month, int year) const
|
||||
{
|
||||
if (year == QCalendar::Unspecified)
|
||||
return QRomanCalendar::daysInMonth(month, year);
|
||||
if (year < m_julianUntil.year
|
||||
|| (year == m_julianUntil.year && month < m_julianUntil.month)) {
|
||||
return julian.daysInMonth(month, year);
|
||||
}
|
||||
if ((year > m_gregorianSince.year)
|
||||
|| (year == m_gregorianSince.year && month > m_gregorianSince.month)) {
|
||||
return gregorian.daysInMonth(month, year);
|
||||
}
|
||||
if (m_julianUntil.year == m_gregorianSince.year) {
|
||||
Q_ASSERT(year == m_julianUntil.year);
|
||||
if (m_julianUntil.month == m_gregorianSince.month) {
|
||||
Q_ASSERT(month == m_julianUntil.month);
|
||||
return QRomanCalendar::daysInMonth(month, year)
|
||||
+ m_julianUntil.day - m_gregorianSince.day + 1;
|
||||
}
|
||||
}
|
||||
if (year == m_julianUntil.year && month == m_julianUntil.month)
|
||||
return m_julianUntil.day;
|
||||
if (year == m_gregorianSince.year && month == m_gregorianSince.month)
|
||||
return gregorian.daysInMonth(month, year) + 1 - m_gregorianSince.day;
|
||||
Q_ASSERT(year > 3900);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool JulianGregorianCalendar::isLeapYear(int year) const
|
||||
{
|
||||
if (year < m_julianUntil.year
|
||||
|| (year == m_julianUntil.year
|
||||
&& (m_julianUntil.month > 2
|
||||
|| (m_julianUntil.month == 2 && m_julianUntil.day == 29)))) {
|
||||
return julian.isLeapYear(year);
|
||||
}
|
||||
return gregorian.isLeapYear(year);
|
||||
}
|
||||
//![0]
|
||||
bool JulianGregorianCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
|
||||
{
|
||||
if (year == m_julianUntil.year && month == m_julianUntil.month) {
|
||||
if (m_julianUntil.day < day && day < m_gregorianSince.day) {
|
||||
// Requested date is in the gap skipped over by the transition.
|
||||
*jd = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
QDate givenDate = gregorian.dateFromParts(year, month, day);
|
||||
QDate julianUntil = julian.dateFromParts(m_julianUntil);
|
||||
if (givenDate > julianUntil) {
|
||||
*jd = givenDate.toJulianDay();
|
||||
return true;
|
||||
}
|
||||
*jd = julian.dateFromParts(year, month, day).toJulianDay();
|
||||
return true;
|
||||
}
|
||||
//![0]
|
||||
//![1]
|
||||
QCalendar::YearMonthDay JulianGregorianCalendar::julianDayToDate(qint64 jd) const
|
||||
{
|
||||
const qint64 jdForChange = julian.dateFromParts(m_julianUntil).toJulianDay();
|
||||
if (jdForChange < jd) {
|
||||
QCalendar gregorian(QCalendar::System::Gregorian);
|
||||
QDate date = QDate::fromJulianDay(jd);
|
||||
return gregorian.partsFromDate(date);
|
||||
} else if (jd <= jdForChange) {
|
||||
QCalendar julian(QCalendar::System::Julian);
|
||||
QDate date = QDate::fromJulianDay(jd);
|
||||
return julian.partsFromDate(date);
|
||||
}
|
||||
return QCalendar::YearMonthDay(QCalendar::Unspecified, QCalendar::Unspecified,
|
||||
QCalendar::Unspecified);
|
||||
}
|
||||
//![1]
|
@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CALENDARBACKEND_H
|
||||
#define CALENDARBACKEND_H
|
||||
|
||||
#include "private/qromancalendar_p.h"
|
||||
#include "qdatetime.h"
|
||||
|
||||
#include <QtCore/private/qcalendarbackend_p.h>
|
||||
//![0]
|
||||
class JulianGregorianCalendar : public QRomanCalendar
|
||||
{
|
||||
public:
|
||||
JulianGregorianCalendar(QDate endJulian, QAnyStringView name);
|
||||
QString name() const override;
|
||||
int daysInMonth(int month, int year = QCalendar::Unspecified) const override;
|
||||
bool isLeapYear(int year) const override;
|
||||
bool dateToJulianDay(int year, int month, int day, qint64 *jd) const override;
|
||||
QCalendar::YearMonthDay julianDayToDate(qint64 jd) const override;
|
||||
private:
|
||||
static inline const QCalendar julian = QCalendar(QCalendar::System::Julian);
|
||||
static inline const QCalendar gregorian = QCalendar(QCalendar::System::Gregorian);
|
||||
QCalendar::YearMonthDay m_julianUntil;
|
||||
QCalendar::YearMonthDay m_gregorianSince;
|
||||
QString m_name;
|
||||
};
|
||||
//![0]
|
||||
#endif // CALENDARBACKEND_H
|
@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "calendarplugin.h"
|
||||
|
||||
JulianGregorianPlugin::JulianGregorianPlugin()
|
||||
{
|
||||
}
|
||||
//![0]
|
||||
QCalendar::SystemId JulianGregorianPlugin::loadCalendar(QAnyStringView request)
|
||||
{
|
||||
Q_ASSERT(!request.isEmpty());
|
||||
QStringList names = request.toString().split(u';');
|
||||
if (names.size() < 1)
|
||||
return {};
|
||||
QString dateString = names.takeFirst();
|
||||
auto date = QDate::fromString(dateString, u"yyyy-MM-dd",
|
||||
QCalendar(QCalendar::System::Julian));
|
||||
if (!date.isValid())
|
||||
return {};
|
||||
QString primary = names.isEmpty() ?
|
||||
QString::fromStdU16String(u"Julian until ") + dateString : names[0];
|
||||
auto backend = new JulianGregorianCalendar(date, primary);
|
||||
names.emplaceFront(backend->name());
|
||||
auto cid = backend->registerCustomBackend(names);
|
||||
return cid;
|
||||
}
|
||||
|
||||
JulianGregorianPlugin::~JulianGregorianPlugin()
|
||||
{
|
||||
}
|
||||
//![0]
|
@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CALENDARPLUGIN_H
|
||||
#define CALENDARPLUGIN_H
|
||||
|
||||
#include "calendarbackend.h"
|
||||
#include "calendarBackendInterface.h"
|
||||
|
||||
#include <QtPlugin>
|
||||
//![0]
|
||||
class JulianGregorianPlugin : public QObject, public RequestedCalendarInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(RequestedCalendarInterface)
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples."
|
||||
"CalendarBackend."
|
||||
"RequestedCalendarInterface/1.0")
|
||||
public:
|
||||
JulianGregorianPlugin();
|
||||
QCalendar::SystemId loadCalendar(QAnyStringView request) override;
|
||||
~JulianGregorianPlugin();
|
||||
};
|
||||
//![0]
|
||||
#endif // CALENDARPLUGIN_H
|
@ -0,0 +1,11 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = calendarPlugin
|
||||
INCLUDEPATH += . \
|
||||
../common/
|
||||
QT += core core-private widgets
|
||||
|
||||
HEADERS += calendarbackend.h calendarplugin.h
|
||||
SOURCES += calendarbackend.cpp calendarplugin.cpp
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/corelib/datetime/calendarbackendplugin/plugin
|
||||
INSTALLS += target
|
4
examples/corelib/time/time.pro
Normal file
4
examples/corelib/time/time.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TEMPLATE = subdirs
|
||||
CONFIG += no_docs_target
|
||||
|
||||
SUBDIRS = calendarbackendplugin
|
Loading…
x
Reference in New Issue
Block a user