18 #include "controller_p.h"
20 #include "application.h"
21 #include "dispatcher.h"
25 #include "context_p.h"
27 #include <QMetaClassInfo>
28 #include <QRegularExpression>
33 , d_ptr(new ControllerPrivate(this))
37 Controller::~Controller()
40 qDeleteAll(d->actionList);
53 Action *ret = d->actions.value(name);
57 return d->dispatcher->getAction(name, d->pathPrefix);
68 return !qstrcmp(
metaObject()->className(), className);
83 ControllerPrivate::ControllerPrivate(
Controller *parent) :
92 dispatcher = _dispatcher;
100 q->setObjectName(className);
102 bool namespaceFound =
false;
107 pathPrefix.remove(0, 1);
109 namespaceFound =
true;
114 if (!namespaceFound) {
116 bool lastWasUpper =
true;
118 for (
int i = 0; i < className.
length(); ++i) {
119 const QChar c = className.
at(i);
122 lastWasUpper =
false;
136 pathPrefix = controlerNS;
139 registerActionMethods(meta, q, app);
142 void ControllerPrivate::setupFinished()
146 const ActionList beginList = dispatcher->getActions(QStringLiteral(
"Begin"), pathPrefix);
151 beginAutoList.append(dispatcher->getActions(QStringLiteral(
"Auto"), pathPrefix));
153 const ActionList endList = dispatcher->getActions(QStringLiteral(
"End"), pathPrefix);
155 end = endList.
last();
158 const auto actions = actionList;
159 for (
Action *action : actions) {
160 action->dispatcherReady(dispatcher, q);
163 q->preFork(qobject_cast<Application *>(q->parent()));
172 int &asyncDetached = c->d_ptr->asyncDetached;
175 const auto beginAutoList = d->beginAutoList;
176 for (
Action *action : beginAutoList) {
178 c->d_ptr->pendingAsync.append(action);
179 }
else if (!action->dispatch(c)) {
188 c->d_ptr->pendingAsync.append(c->action());
189 }
else if (!c->action()->
dispatch(c)) {
197 c->d_ptr->pendingAsync.append(d->end);
198 }
else if (!d->end->dispatch(c)) {
204 c->d_ptr->engineRequest->status |= EngineRequest::Async;
210 Action *ControllerPrivate::actionClass(
const QVariantHash &args)
212 const auto attributes = args.value(QStringLiteral(
"attributes")).value<
ParamsMultiMap>();
213 const QString actionClass = attributes.value(QStringLiteral(
"ActionClass"));
215 QObject *
object = instantiateClass(actionClass,
"Cutelyst::Action");
217 Action *action = qobject_cast<Action*>(
object);
221 qCWarning(CUTELYST_CONTROLLER) <<
"ActionClass"
223 <<
"is not an ActionClass";
232 Action *action = actionClass(args);
238 for (
int i = 0; i < roles.
size(); ++i) {
240 code->
init(app, args);
246 action->
setName(args.value(QStringLiteral(
"name")).toString());
247 action->
setReverse(args.value(QStringLiteral(
"reverse")).toString());
271 if (name == classInfo.
name()) {
275 ParamsMultiMap attrs = parseAttributes(method, attributeArray, name);
284 Action *action = createAction({
294 actions.replace(action->
reverse(), action);
295 actionList.append(action);
303 std::vector<std::pair<QString, QString> > attributes;
310 int size = str.
size();
317 if (str.
at(pos) ==
':') {
318 int keyStart = ++pos;
321 if (str.
at(pos) ==
'(') {
323 int valueStart = ++pos;
325 if (str.
at(pos) ==
')') {
328 if (++pos < size && str.
at(pos) ==
':') {
333 }
else if (pos >= size) {
346 }
else if (str.
at(pos) ==
':') {
358 if (!value.isEmpty()) {
362 value.remove(value.size() - 1, 1);
367 attributes.push_back({ key, value });
375 auto i = attributes.crbegin();
376 const auto end = attributes.crend();
381 key = QStringLiteral(
"Path");
384 key = QStringLiteral(
"Path");
387 value = parsePathAttr(value);
397 value = parseChainedAttr(value);
405 if (!ret.
contains(QStringLiteral(
"Args")) && !ret.
contains(QStringLiteral(
"CaptureArgs")) &&
406 (ret.
contains(QStringLiteral(
"AutoArgs")) || ret.
contains(QStringLiteral(
"AutoCaptureArgs")))) {
407 if (ret.
contains(QStringLiteral(
"AutoArgs")) && ret.
contains(QStringLiteral(
"AutoCaptureArgs"))) {
408 qFatal(
"Action '%s' has both AutoArgs and AutoCaptureArgs, which is not allowed", name.
constData());
411 if (ret.
contains(QStringLiteral(
"AutoArgs"))) {
412 ret.
remove(QStringLiteral(
"AutoArgs"));
413 parameterName = QStringLiteral(
"Args");
415 ret.
remove(QStringLiteral(
"AutoCaptureArgs"));
416 parameterName = QStringLiteral(
"CaptureArgs");
421 int parameterCount = 0;
446 auto doesIt = attributes.
constFind(QStringLiteral(
"Does"));
447 while (doesIt != attributes.constEnd() && doesIt.
key() ==
QLatin1String(
"Does")) {
448 QObject *
object = instantiateClass(doesIt.
value(), QByteArrayLiteral(
"Cutelyst::Component"));
450 roles.
push(qobject_cast<Component *>(
object));
462 }
else if (!value.isEmpty()) {
470 QString ret = QStringLiteral(
"/");
475 if (attr == QStringLiteral(
".")) {
478 if (!pathPrefix.isEmpty()) {
497 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
504 id = QMetaType::fromName(instanceName.
toLatin1().
data());
505 if (!
id.isValid() && !instanceName.
startsWith(QStringLiteral(
"Cutelyst::"))) {
507 id = QMetaType::fromName(instanceName.
toLatin1().
data());
514 if (!superIsClassName(metaObj->
superClass(), super)) {
515 qCWarning(CUTELYST_CONTROLLER)
518 <<
"is not a derived class of"
524 qCWarning(CUTELYST_CONTROLLER)
525 <<
"Could create a new instance of"
527 <<
"make sure it's default constructor is "
528 "marked with the Q_INVOKABLE macro";
534 Component *component = application->createComponentPlugin(name);
539 component = application->createComponentPlugin(instanceName);
546 qFatal(
"Could not create component '%s', you can register it with qRegisterMetaType<%s>(); or set a proper CUTELYST_PLUGINS_DIR",
547 qPrintable(instanceName), qPrintable(instanceName));
558 if (!
id && !instanceName.
startsWith(QStringLiteral(
"Cutelyst::"))) {
567 if (!superIsClassName(metaObj->
superClass(), super)) {
568 qCWarning(CUTELYST_CONTROLLER)
571 <<
"is not a derived class of"
577 qCWarning(CUTELYST_CONTROLLER)
578 <<
"Could create a new instance of"
580 <<
"make sure it's default constructor is "
581 "marked with the Q_INVOKABLE macro";
587 Component *component = application->createComponentPlugin(name);
592 component = application->createComponentPlugin(instanceName);
599 qFatal(
"Could not create component '%s', you can register it with qRegisterMetaType<%s>(); or set a proper CUTELYST_PLUGINS_DIR",
600 qPrintable(instanceName), qPrintable(instanceName));
613 return superIsClassName(super->
superClass(), className);
618 #include "moc_controller.cpp"
This class represents a Cutelyst Action.
void setupAction(const QVariantHash &args, Application *app)
bool dispatch(Context *c)
void setMethod(const QMetaMethod &method)
void setController(Controller *controller)
The Cutelyst Application.
The Cutelyst Component base class.
void setReverse(const QString &reverse)
virtual bool init(Application *application, const QVariantHash &args)
void applyRoles(const QStack< Component * > &roles)
void setName(const QString &name)
Cutelyst Controller base class
virtual bool preFork(Application *app)
Action * actionFor(const QString &name) const
ActionList actions() const
virtual bool postFork(Application *app)
bool operator==(const char *className)
bool _DISPATCH(Context *c)
Controller(QObject *parent=nullptr)
The Cutelyst namespace holds all public Cutelyst API.
QByteArray & append(char ch)
char at(int i) const const
const char * constData() const const
QByteArray mid(int pos, int len) const const
bool isDigit() const const
bool isLower() const const
QChar toLower() const const
const Key key(const T &value, const Key &defaultKey) const const
const T value(const Key &key, const T &defaultValue) const const
typename QMap< Key, T >::const_iterator constFind(const Key &key, const T &value) const const
bool contains(const Key &key, const T &value) const const
typename QMap< Key, T >::iterator insert(const Key &key, const T &value)
int remove(const Key &key, const T &value)
typename QMap< Key, T >::iterator replace(const Key &key, const T &value)
void setParent(QObject *parent)
QString & append(QChar ch)
const QChar at(int position) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString fromLatin1(const char *str, int size)
bool isEmpty() const const
QString number(int n, int base)
QString & remove(int position, int n)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
QVariant fromValue(const T &value)
void append(const T &value)
const T & at(int i) const const
bool isEmpty() const const
T value(int i) const const