6 #include "application.h" 9 #include "controller_p.h" 10 #include "dispatcher.h" 12 #include <QMetaClassInfo> 13 #include <QRegularExpression> 242 , d_ptr(new ControllerPrivate(this))
246 Controller::~Controller()
249 qDeleteAll(d->actionList);
256 return d->pathPrefix;
262 auto it = d->actions.constFind(name);
263 if (it != d->actions.constEnd()) {
266 return d->dispatcher->getAction(name.
toString(), d->pathPrefix);
272 return d->actionList;
277 return !qstrcmp(
metaObject()->className(), className);
292 ControllerPrivate::ControllerPrivate(
Controller *parent)
303 dispatcher = _dispatcher;
311 q->setObjectName(className);
313 bool namespaceFound =
false;
317 while (pathPrefix.startsWith(u
'/')) {
320 namespaceFound =
true;
325 if (!namespaceFound) {
327 bool lastWasUpper =
true;
329 for (
int i = 0; i < className.
length(); ++i) {
330 const QChar c = className.
at(i);
333 lastWasUpper =
false;
334 }
else if (c == u
'_') {
347 pathPrefix = controlerNS;
350 registerActionMethods(meta, q, app);
353 void ControllerPrivate::setupFinished()
357 const ActionList beginList = dispatcher->getActions(QStringLiteral(
"Begin"), pathPrefix);
362 beginAutoList.append(dispatcher->getActions(QStringLiteral(
"Auto"), pathPrefix));
364 const ActionList endList = dispatcher->getActions(QStringLiteral(
"End"), pathPrefix);
366 end = endList.
last();
369 const auto actions = actionList;
370 for (
Action *action : actions) {
371 action->dispatcherReady(dispatcher, q);
374 q->preFork(qobject_cast<Application *>(q->parent()));
383 int &actionRefCount = c->d_ptr->actionRefCount;
386 const auto beginAutoList = d->beginAutoList;
387 for (
Action *action : beginAutoList) {
388 if (actionRefCount) {
389 c->d_ptr->pendingAsync.enqueue(action);
390 }
else if (!action->dispatch(c)) {
398 if (actionRefCount) {
399 c->d_ptr->pendingAsync.enqueue(c->
action());
407 if (actionRefCount) {
408 c->d_ptr->pendingAsync.enqueue(d->end);
409 }
else if (!d->end->dispatch(c)) {
414 if (actionRefCount) {
415 c->d_ptr->engineRequest->status |= EngineRequest::Async;
421 Action *ControllerPrivate::actionClass(
const QVariantHash &args)
423 const auto attributes = args.value(QStringLiteral(
"attributes")).value<
ParamsMultiMap>();
424 const QString actionClass = attributes.value(QStringLiteral(
"ActionClass"));
426 QObject *
object = instantiateClass(actionClass,
"Cutelyst::Action");
432 qCWarning(CUTELYST_CONTROLLER) <<
"ActionClass" << actionClass <<
"is not an ActionClass";
439 Action *ControllerPrivate::createAction(
const QVariantHash &args,
444 Action *action = actionClass(args);
450 for (
int i = 0; i < roles.
size(); ++i) {
452 code->
init(app, args);
458 action->
setName(args.value(QStringLiteral(
"name")).toString());
459 action->
setReverse(args.value(QStringLiteral(
"reverse")).toString());
465 void ControllerPrivate::registerActionMethods(
const QMetaObject *meta,
481 method.
parameterType(0) == qMetaTypeId<Cutelyst::Context *>())) {
487 if (name == classInfo.
name()) {
491 ParamsMultiMap attrs = parseAttributes(method, attributeArray, name);
510 actionList.append(action);
520 std::vector<std::pair<QString, QString>> attributes;
527 int size = str.
size();
534 if (str.
at(pos) ==
':') {
535 int keyStart = ++pos;
538 if (str.
at(pos) ==
'(') {
540 int valueStart = ++pos;
542 if (str.
at(pos) ==
')') {
545 if (++pos < size && str.
at(pos) ==
':') {
551 }
else if (pos >= size) {
565 }
else if (str.
at(pos) ==
':') {
577 if (!value.isEmpty()) {
578 if ((value.startsWith(u
'\'') && value.endsWith(u
'\'')) ||
579 (value.startsWith(u
'"') && value.endsWith(u
'"'))) {
581 value.remove(value.size() - 1, 1);
586 attributes.emplace_back(std::make_pair(key, value));
596 for (
const auto &pair : attributes) {
599 if (key.
compare(u
"Global") == 0) {
600 key = QStringLiteral(
"Path");
602 }
else if (key.
compare(u
"Local") == 0) {
603 key = QStringLiteral(
"Path");
605 }
else if (key.
compare(u
"Path") == 0) {
606 value = parsePathAttr(value);
607 }
else if (key.
compare(u
"Args") == 0) {
610 value = args.
remove(digitRE);
612 }
else if (key.
compare(u
"CaptureArgs") == 0) {
614 value = captureArgs.
remove(digitRE);
615 }
else if (key.
compare(u
"Chained") == 0) {
616 value = parseChainedAttr(value);
623 if (!ret.
contains(QStringLiteral(
"Args")) && !ret.
contains(QStringLiteral(
"CaptureArgs")) &&
624 (ret.
contains(QStringLiteral(
"AutoArgs")) ||
625 ret.
contains(QStringLiteral(
"AutoCaptureArgs")))) {
626 if (ret.
contains(QStringLiteral(
"AutoArgs")) &&
627 ret.
contains(QStringLiteral(
"AutoCaptureArgs"))) {
628 qFatal(
"Action '%s' has both AutoArgs and AutoCaptureArgs, which is not allowed",
632 if (ret.
contains(QStringLiteral(
"AutoArgs"))) {
633 ret.
remove(QStringLiteral(
"AutoArgs"));
634 parameterName = QStringLiteral(
"Args");
636 ret.
remove(QStringLiteral(
"AutoCaptureArgs"));
637 parameterName = QStringLiteral(
"CaptureArgs");
643 int parameterCount = 0;
667 auto doesIt = attributes.
constFind(QStringLiteral(
"Does"));
668 while (doesIt != attributes.constEnd() && doesIt.
key().compare(u
"Does") == 0) {
670 instantiateClass(doesIt.
value(), QByteArrayLiteral(
"Cutelyst::Component"));
672 roles.
push(qobject_cast<Component *>(
object));
682 if (value.startsWith(u
'/')) {
684 }
else if (!value.isEmpty()) {
685 ret = pathPrefix + u
'/' + value;
692 QString ret = QStringLiteral(
"/");
700 if (!pathPrefix.isEmpty()) {
701 ret.
append(pathPrefix + u
'/' + attr);
726 if (!
id.isValid() && !instanceName.
startsWith(u
"Cutelyst::")) {
735 if (!superIsClassName(metaObj->
superClass(), super)) {
736 qCWarning(CUTELYST_CONTROLLER)
737 <<
"Class name" << instanceName <<
"is not a derived class of" << super;
742 qCWarning(CUTELYST_CONTROLLER)
743 <<
"Could create a new instance of" << instanceName
744 <<
"make sure it's default constructor is " 745 "marked with the Q_INVOKABLE macro";
751 Component *component = application->createComponentPlugin(name);
756 component = application->createComponentPlugin(instanceName);
763 qCCritical(CUTELYST_CONTROLLER,
764 "Could not create component '%s', you can register it with " 765 "qRegisterMetaType<%s>(); or set a proper CUTELYST_PLUGINS_DIR",
766 qPrintable(instanceName),
767 qPrintable(instanceName));
780 return superIsClassName(super->
superClass(), className);
785 #include "moc_controller.cpp" void setName(const QString &name)
QString & append(QChar ch)
bool dispatch(Context *c)
QMultiMap::const_iterator constFind(const Key &key) const const
QMultiMap::iterator replace(const Key &key, const T &value)
char at(qsizetype i) const const
void setReverse(const QString &reverse)
bool isDigit() const const
QList::const_reference at(qsizetype i) const const
virtual bool preFork(Application *app)
QString & remove(qsizetype position, qsizetype n)
QString reverse() const noexcept
The Cutelyst Component base class.
qsizetype size() const const
This class represents a Cutelyst Action.
T value(qsizetype i) const const
QString number(int n, int base)
Cutelyst Controller base class.
void append(QList::parameter_type value)
QMultiMap::size_type remove(const Key &key)
bool isEmpty() const const
bool isEmpty() const const
const char * constData() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
virtual bool init(Application *application, const QVariantHash &args)
QMultiMap::iterator insert(const Key &key, const T &value)
bool _DISPATCH(Context *c)
The Cutelyst namespace holds all public Cutelyst API.
void applyRoles(const QStack< Component *> &roles)
QByteArray mid(qsizetype pos, qsizetype len) const const
QByteArray & append(char ch)
void setParent(QObject *parent)
QVariant fromValue(const T &value)
QChar toLower() const const
void setController(Controller *controller)
virtual bool postFork(Application *app)
bool contains(const Key &key) const const
Key key(const T &value, const Key &defaultKey) const const
QString fromLatin1(QByteArrayView str)
QByteArray toLatin1() const const
QString toString() const const
void setupAction(const QVariantHash &args, Application *app)
const QChar at(qsizetype position) const const
QString ns() const noexcept
qsizetype length() const const
bool operator==(const char *className)
The Cutelyst application.
QString first(qsizetype n) const const
void setMethod(const QMetaMethod &method)
Action * actionFor(QStringView name) const
qsizetype size() const const
int compare(const QString &other, Qt::CaseSensitivity cs) const const
ActionList actions() const noexcept
bool isLower() const const
T value(const Key &key, const T &defaultValue) const const
Controller(QObject *parent=nullptr)