From 4b1798f0cdf87361869e7cf2b341acacd056c410 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 5 Apr 2017 15:04:00 +0200 Subject: Moved cpp code into src directory --- framework/src/actions/action.cpp | 127 ++++++++++++++++++++++++ framework/src/actions/action.h | 71 ++++++++++++++ framework/src/actions/actionbroker.cpp | 101 +++++++++++++++++++ framework/src/actions/actionbroker.h | 49 ++++++++++ framework/src/actions/actionhandler.cpp | 151 +++++++++++++++++++++++++++++ framework/src/actions/actionhandler.h | 112 +++++++++++++++++++++ framework/src/actions/actionresult.cpp | 20 ++++ framework/src/actions/actionresult.h | 80 +++++++++++++++ framework/src/actions/context.cpp | 91 +++++++++++++++++ framework/src/actions/context.h | 67 +++++++++++++ framework/src/actions/tests/CMakeLists.txt | 6 ++ framework/src/actions/tests/actiontest.cpp | 102 +++++++++++++++++++ 12 files changed, 977 insertions(+) create mode 100644 framework/src/actions/action.cpp create mode 100644 framework/src/actions/action.h create mode 100644 framework/src/actions/actionbroker.cpp create mode 100644 framework/src/actions/actionbroker.h create mode 100644 framework/src/actions/actionhandler.cpp create mode 100644 framework/src/actions/actionhandler.h create mode 100644 framework/src/actions/actionresult.cpp create mode 100644 framework/src/actions/actionresult.h create mode 100644 framework/src/actions/context.cpp create mode 100644 framework/src/actions/context.h create mode 100644 framework/src/actions/tests/CMakeLists.txt create mode 100644 framework/src/actions/tests/actiontest.cpp (limited to 'framework/src/actions') diff --git a/framework/src/actions/action.cpp b/framework/src/actions/action.cpp new file mode 100644 index 00000000..1344d112 --- /dev/null +++ b/framework/src/actions/action.cpp @@ -0,0 +1,127 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#include "action.h" + +#include +#include +#include +#include +#include +#include + +#include "actionbroker.h" +#include "actionhandler.h" +#include "context.h" + +using namespace Kube; + +Action::Action(QObject *parent) + : QObject(parent), + mContext(nullptr) +{ +} + +Action::Action(const QByteArray &actionId, Context &context, QObject *parent) + : QObject(parent), + mContext(&context), + mActionId(actionId) +{ + setContext(&context); +} + +Action::~Action() +{ +} + +void Action::setContext(Context *context) +{ + //Get notified when any property changes + for (int i = context->metaObject()->propertyOffset(); i < context->metaObject()->propertyCount(); i++) { + auto property = context->metaObject()->property(i) ; + // qWarning() << "Property " << property.name() << property.hasNotifySignal() << property.notifySignal().name(); + if (QString(property.name()) != "objectName") { + //We do what SIGNAL does to connect to the changed signal automatically + QObject::connect(context, "2"+property.notifySignal().name()+"()", this, SLOT(contextChanged())); + } + } + mContext = context; + mContext->installEventFilter(this); + emit readyChanged(); +} + +bool Action::eventFilter(QObject *obj, QEvent *e) +{ + if (obj == mContext) { + if (e->type() == QEvent::DynamicPropertyChange) { + contextChanged(); + } + } + return QObject::eventFilter(obj, e); +} + +void Action::contextChanged() +{ + emit readyChanged(); +} + +Context *Action::context() const +{ + return mContext; +} + +void Action::setActionId(const QByteArray &actionId) +{ + mActionId = actionId; + emit readyChanged(); +} + +QByteArray Action::actionId() const +{ + return mActionId; +} + +bool Action::ready() const +{ + return ActionBroker::instance().isActionReady(mActionId, mContext, mPreHandler); +} + +void Action::execute() +{ + ActionBroker::instance().executeAction(mActionId, mContext, mPreHandler, mPostHandler); +} + +ActionResult Action::executeWithResult() +{ + return ActionBroker::instance().executeAction(mActionId, mContext, mPreHandler, mPostHandler); +} + +void Action::addPreHandler(ActionHandler *handler) +{ + //For cleanup + handler->setParent(this); + mPreHandler << handler; +} + +void Action::addPostHandler(ActionHandler *handler) +{ + //For cleanup + handler->setParent(this); + mPostHandler << handler; +} + diff --git a/framework/src/actions/action.h b/framework/src/actions/action.h new file mode 100644 index 00000000..dda8c987 --- /dev/null +++ b/framework/src/actions/action.h @@ -0,0 +1,71 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#pragma once + +#include +#include "context.h" +#include "actionresult.h" + +namespace Kube { + +class ActionHandler; + +class Action : public QObject +{ + Q_OBJECT + Q_PROPERTY(QByteArray actionId READ actionId WRITE setActionId) + //FIXME if I set the property to Context* qml fails to assign the registered type which is calle Kube::Context_QML_90 in QML... + Q_PROPERTY(Context* context READ context WRITE setContext) + Q_PROPERTY(bool ready READ ready NOTIFY readyChanged) + +public: + Action(QObject *parent = 0); + Action(const QByteArray &actionId, Context &context, QObject *parent = 0); + ~Action(); + + void setContext(Context *); + Context *context() const; + + void setActionId(const QByteArray &); + QByteArray actionId() const; + + bool ready() const; + + Q_INVOKABLE void execute(); + ActionResult executeWithResult(); + + void addPreHandler(ActionHandler *handler); + void addPostHandler(ActionHandler *handler); + + bool eventFilter(QObject *obj, QEvent *e) Q_DECL_OVERRIDE; + +Q_SIGNALS: + void readyChanged(); + +private Q_SLOTS: + void contextChanged(); + +private: + Context *mContext; + QByteArray mActionId; + QList> mPreHandler; + QList> mPostHandler; +}; + +} diff --git a/framework/src/actions/actionbroker.cpp b/framework/src/actions/actionbroker.cpp new file mode 100644 index 00000000..f6bfdd8e --- /dev/null +++ b/framework/src/actions/actionbroker.cpp @@ -0,0 +1,101 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "actionbroker.h" + +#include "context.h" +#include "actionhandler.h" +#include + +#include + +using namespace Kube; + +SINK_DEBUG_AREA("actionbroker") + +ActionBroker::ActionBroker(QObject *parent) + : QObject(parent) +{ + +} + +ActionBroker &ActionBroker::instance() +{ + static ActionBroker instance; + return instance; +} + +bool ActionBroker::isActionReady(const QByteArray &actionId, Context *context, const QList> &preHandler) +{ + if (!context) { + return false; + } + for (const auto handler : preHandler) { + if (!handler->isActionReady(context)) { + return false; + } + } + + for (const auto handler : mHandler.values(actionId)) { + if (handler) { + if (handler->isActionReady(context)) { + return true; + } + } + } + + return false; +} + +ActionResult ActionBroker::executeAction(const QByteArray &actionId, Context *context, const QList> &preHandler, const QList> &postHandler) +{ + ActionResult result; + if (context) { + SinkLog() << "Executing action " << actionId; + SinkLog() << *context; + for (const auto handler : preHandler) { + handler->execute(context); + } + //TODO the main handler should only execute once the pre handler is done + for (const auto handler : mHandler.values(actionId)) { + if (handler) { + result += handler->execute(context); + } + } + //TODO the post handler should only execute once the main handler is done + for (const auto handler : postHandler) { + handler->execute(context); + } + } else { + SinkWarning() << "Can't execute without context"; + result.setDone(); + result.setError(1); + } + return result; +} + +void ActionBroker::registerHandler(const QByteArray &actionId, ActionHandler *handler) +{ + mHandler.insert(actionId, handler); +} + +void ActionBroker::unregisterHandler(const QByteArray &actionId, ActionHandler *handler) +{ + mHandler.remove(actionId, handler); +} diff --git a/framework/src/actions/actionbroker.h b/framework/src/actions/actionbroker.h new file mode 100644 index 00000000..d893a3e7 --- /dev/null +++ b/framework/src/actions/actionbroker.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#pragma once + +#include +#include + +namespace Kube { +class Context; +class ActionHandler; +class ActionResult; + +class ActionBroker : public QObject +{ + Q_OBJECT +public: + static ActionBroker &instance(); + + bool isActionReady(const QByteArray &actionId, Context *context, const QList> &preHandler); + ActionResult executeAction(const QByteArray &actionId, Context *context, const QList> &preHandler, const QList> &postHandler); + + void registerHandler(const QByteArray &actionId, ActionHandler *handler); + void unregisterHandler(const QByteArray &actionId, ActionHandler *handler); + +Q_SIGNALS: + void readyChanged(); + +private: + ActionBroker(QObject *parent = 0); + QMultiMap> mHandler; +}; + +} diff --git a/framework/src/actions/actionhandler.cpp b/framework/src/actions/actionhandler.cpp new file mode 100644 index 00000000..99fdf66a --- /dev/null +++ b/framework/src/actions/actionhandler.cpp @@ -0,0 +1,151 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "actionhandler.h" + +#include "context.h" +#include "actionbroker.h" +#include + +using namespace Kube; + +ActionHandler::ActionHandler(QObject *parent) + : QObject(parent) +{ + +} + +ActionHandler::~ActionHandler() +{ + ActionBroker::instance().unregisterHandler(mActionId, this); +} + +bool ActionHandler::isActionReady(Context *context) +{ + if (context) { + QVariant returnedValue; + QMetaObject::invokeMethod(this, "isReady", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, QVariant::fromValue(context))); + return returnedValue.toBool(); + } else { + qWarning() << "The handler didn't get a context"; + } + return false; +} + +ActionResult ActionHandler::execute(Context *context) +{ + ActionResult result; + QVariant returnedValue; + qWarning() << "Executing the handler"; + if (context) { + //The base implementation to call the handler in QML + QMetaObject::invokeMethod(this, "handler", + Q_RETURN_ARG(QVariant, returnedValue), + Q_ARG(QVariant, QVariant::fromValue(context))); + //TODO: support async handlers in QML + result.setDone(); + } else { + qWarning() << "The handler didn't get a context"; + result.setDone(); + result.setError(1); + } + return result; +} + +void ActionHandler::setActionId(const QByteArray &actionId) +{ + //Reassigning the id is not supported + Q_ASSERT(mActionId.isEmpty()); + mActionId = actionId; + ActionBroker::instance().registerHandler(actionId, this); +} + +QByteArray ActionHandler::actionId() const +{ + return mActionId; +} + +void ActionHandler::setRequiredProperties(const QSet &requiredProperties) +{ + mRequiredProperties = requiredProperties; +} + +QSet ActionHandler::requiredProperties() const +{ + return mRequiredProperties; +} + + +ActionHandlerHelper::ActionHandlerHelper(const Handler &handler) + : ActionHandler(nullptr), + handlerFunction(handler) +{ +} + +ActionHandlerHelper::ActionHandlerHelper(const IsReadyFunction &isReady, const Handler &handler) + : ActionHandler(nullptr), + isReadyFunction(isReady), + handlerFunction(handler) +{ +} + +ActionHandlerHelper::ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &isReady, const Handler &handler) + : ActionHandler(nullptr), + isReadyFunction(isReady), + handlerFunction(handler) +{ + setActionId(actionId); +} + +ActionHandlerHelper::ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &isReady, const JobHandler &handler) + : ActionHandler(nullptr), + isReadyFunction(isReady), + jobHandlerFunction(handler) +{ + setActionId(actionId); +} + +bool ActionHandlerHelper::isActionReady(Context *context) +{ + if (isReadyFunction) { + return isReadyFunction(context); + } + return true; +} + +ActionResult ActionHandlerHelper::execute(Context *context) +{ + ActionResult result; + if (handlerFunction) { + handlerFunction(context); + result.setDone(); + } else { + jobHandlerFunction(context).then([=](const KAsync::Error &error) { + auto modifyableResult = result; + if (error) { + qWarning() << "Job failed: " << error.errorCode << error.errorMessage; + modifyableResult.setError(1); + } + modifyableResult.setDone(); + }).exec(); + } + return result; +} diff --git a/framework/src/actions/actionhandler.h b/framework/src/actions/actionhandler.h new file mode 100644 index 00000000..fbaedad1 --- /dev/null +++ b/framework/src/actions/actionhandler.h @@ -0,0 +1,112 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#pragma once + +#include +#include +#include +#include + +#include "actionresult.h" +#include "context.h" + +namespace Kube { + +class ActionHandler : public QObject +{ + Q_OBJECT + Q_PROPERTY(QByteArray actionId READ actionId WRITE setActionId) + +public: + ActionHandler(QObject *parent = 0); + virtual ~ActionHandler(); + + virtual bool isActionReady(Context *context); + + virtual ActionResult execute(Context *context); + + void setActionId(const QByteArray &); + QByteArray actionId() const; + + void setRequiredProperties(const QSet &requiredProperties); + QSet requiredProperties() const; + +private: + QByteArray mActionId; + QSet mRequiredProperties; +}; + +template +class ActionHandlerBase : public ActionHandler +{ +public: + ActionHandlerBase(const QByteArray &actionId) + : ActionHandler{} + { + setActionId(actionId); + } + + bool isActionReady(Context *c) Q_DECL_OVERRIDE + { + auto wrapper = ContextType{*c}; + return isActionReady(wrapper); + } + + ActionResult execute(Context *c) Q_DECL_OVERRIDE + { + ActionResult result; + auto wrapper = ContextType{*c}; + execute(wrapper) + .template then([=](const KAsync::Error &error) { + auto modifyableResult = result; + if (error) { + qWarning() << "Job failed: " << error.errorCode << error.errorMessage; + modifyableResult.setError(1); + } + modifyableResult.setDone(); + }).exec(); + return result; + } +protected: + + virtual bool isActionReady(ContextType &) { return true; } + virtual KAsync::Job execute(ContextType &) = 0; +}; + +class ActionHandlerHelper : public ActionHandler +{ +public: + typedef std::function IsReadyFunction; + typedef std::function Handler; + typedef std::function(Context *)> JobHandler; + + ActionHandlerHelper(const Handler &); + ActionHandlerHelper(const IsReadyFunction &, const Handler &); + ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &, const Handler &); + ActionHandlerHelper(const QByteArray &actionId, const IsReadyFunction &, const JobHandler &); + + bool isActionReady(Context *) Q_DECL_OVERRIDE; + ActionResult execute(Context *) Q_DECL_OVERRIDE; +private: + const IsReadyFunction isReadyFunction; + const Handler handlerFunction; + const JobHandler jobHandlerFunction; +}; + +} diff --git a/framework/src/actions/actionresult.cpp b/framework/src/actions/actionresult.cpp new file mode 100644 index 00000000..631c61c4 --- /dev/null +++ b/framework/src/actions/actionresult.cpp @@ -0,0 +1,20 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#include "actionresult.h" + diff --git a/framework/src/actions/actionresult.h b/framework/src/actions/actionresult.h new file mode 100644 index 00000000..dcf1a9ec --- /dev/null +++ b/framework/src/actions/actionresult.h @@ -0,0 +1,80 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#pragma once + +#include +#include + +namespace Kube { + +struct ActionResultData +{ + ActionResultData() : mError(0), mDone(false) {} + int mError; + bool mDone; +}; + +class ActionResult : public QObject +{ + Q_OBJECT +public: + ActionResult() : QObject(), mData(new ActionResultData()) {} + ActionResult(const ActionResult &rhs) : QObject(), mData(rhs.mData) {} + ActionResult &operator=(const ActionResult &rhs) + { + mData = rhs.mData; + return *this; + } + virtual ~ActionResult() {} + + ActionResult &operator+=(const ActionResult &rhs) + { + if (!error() && rhs.error()) { + setError(rhs.error()); + } + if (isDone() && rhs.isDone()) { + mData->mDone = false; + } + mData = rhs.mData; + return *this; + } + + void setDone() { + mData->mDone = true; + } + + bool isDone() const { + return mData->mDone; + } + + void setError(int error) { + mData->mError = error; + } + + int error() const { + return mData->mError; + } + +private: + QSharedPointer mData; +}; + +} + +Q_DECLARE_METATYPE(Kube::ActionResult); diff --git a/framework/src/actions/context.cpp b/framework/src/actions/context.cpp new file mode 100644 index 00000000..45b660a9 --- /dev/null +++ b/framework/src/actions/context.cpp @@ -0,0 +1,91 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#include "context.h" + +#include +#include + +using namespace Kube; + +Context::Context(QObject *parent) + : QObject(parent) +{ + +} + +Context::Context(const Context &other) + : QObject() +{ + *this = other; +} + +Context &Context::operator=(const Context &other) +{ + for (const auto &p : other.availableProperties()) { + setProperty(p, other.property(p)); + } + return *this; +} + +void Context::clear() +{ + auto meta = metaObject(); + for (auto i = meta->propertyOffset(); i < meta->propertyCount(); i++) { + auto property = meta->property(i); + setProperty(property.name(), QVariant()); + } + for (const auto &p : dynamicPropertyNames()) { + setProperty(p, QVariant()); + } +} + +QSet Context::availableProperties() const +{ + QSet names; + auto meta = metaObject(); + for (auto i = meta->propertyOffset(); i < meta->propertyCount(); i++) { + auto property = meta->property(i); + names << property.name(); + } + for (const auto &p : dynamicPropertyNames()) { + names << p; + } + return names; +} + +QDebug operator<<(QDebug dbg, const Kube::Context &context) +{ + dbg << "Kube::Context {\n"; + auto metaObject = context.metaObject(); + for (auto i = metaObject->propertyOffset(); i < metaObject->propertyCount(); i++) { + auto property = metaObject->property(i); + dbg << property.name() << context.property(property.name()) << "\n"; + } + for (const auto &p : context.dynamicPropertyNames()) { + dbg << p << context.property(p) << "\n"; + } + dbg << "\n}"; + return dbg; +} + +QDebug operator<<(QDebug dbg, const Kube::ContextWrapper &context) +{ + dbg << context.context; + return dbg; +} diff --git a/framework/src/actions/context.h b/framework/src/actions/context.h new file mode 100644 index 00000000..52fbdbc1 --- /dev/null +++ b/framework/src/actions/context.h @@ -0,0 +1,67 @@ +/* + Copyright (c) 2016 Christian Mollekopf + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +#pragma once + +#include +#define KUBE_CONTEXT_PROPERTY(TYPE, NAME, LOWERCASENAME) \ + public: Q_PROPERTY(TYPE LOWERCASENAME MEMBER m##NAME NOTIFY LOWERCASENAME##Changed) \ + Q_SIGNALS: void LOWERCASENAME##Changed(); \ + private: TYPE m##NAME; + +#define KUBE_CONTEXTWRAPPER_PROPERTY(TYPE, NAME, LOWERCASENAME) \ + public: \ + struct NAME { \ + static constexpr const char *name = #LOWERCASENAME; \ + typedef TYPE Type; \ + }; \ + void set##NAME(const TYPE &value) { context.setProperty(NAME::name, QVariant::fromValue(value)); } \ + void clear##NAME() { context.setProperty(NAME::name, QVariant{}); } \ + TYPE get##NAME() const { return context.property(NAME::name).value(); } \ + + +namespace Kube { + +class Context : public QObject { + Q_OBJECT +public: + Context(QObject *parent = 0); + Context(const Context &); + + virtual ~Context(){}; + + Context &operator=(const Context &); + + virtual void clear(); + + QSet availableProperties() const; +}; + +class ContextWrapper { +public: + ContextWrapper(Context &c) : context(c) {} + Context &context; +}; + +} + +QDebug operator<<(QDebug dbg, const Kube::Context &); +QDebug operator<<(QDebug dbg, const Kube::ContextWrapper &); + +Q_DECLARE_METATYPE(Kube::Context*); + diff --git a/framework/src/actions/tests/CMakeLists.txt b/framework/src/actions/tests/CMakeLists.txt new file mode 100644 index 00000000..af872a3b --- /dev/null +++ b/framework/src/actions/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +cmake_policy(SET CMP0063 NEW) +add_executable(actiontest actiontest.cpp) +add_test(actiontest sinkactiontest) +qt5_use_modules(actiontest Core Test) +target_link_libraries(actiontest actionplugin) diff --git a/framework/src/actions/tests/actiontest.cpp b/framework/src/actions/tests/actiontest.cpp new file mode 100644 index 00000000..a4ec4432 --- /dev/null +++ b/framework/src/actions/tests/actiontest.cpp @@ -0,0 +1,102 @@ +#include +#include +#include + +#include +#include +#include + +#include + +SINK_DEBUG_AREA("actiontest") + +class HandlerContext : public Kube::Context { + Q_OBJECT + KUBE_CONTEXT_PROPERTY(QString, Property1, property1) + KUBE_CONTEXT_PROPERTY(QString, Property2, property2) +}; + +class HandlerContextWrapper : public Kube::ContextWrapper { + using Kube::ContextWrapper::ContextWrapper; + KUBE_CONTEXTWRAPPER_PROPERTY(QString, Property1, property1) + KUBE_CONTEXTWRAPPER_PROPERTY(QString, Property2, property2) +}; + + + +class Handler : public Kube::ActionHandlerBase +{ +public: + Handler() : Kube::ActionHandlerBase{"org.kde.kube.test.action1"} + {} + + //TODO default implementation checks that all defined properties are available in the context + // bool isReady() override { + // auto accountId = context->property("accountId").value(); + // return !accountId.isEmpty(); + // } + + KAsync::Job execute(HandlerContextWrapper &context) + { + SinkLog() << "Executing action1"; + SinkLog() << context; + executions.append(context.context); + return KAsync::null(); + } + mutable QList executions; +}; + +class Context1 : public Kube::ContextWrapper { + using Kube::ContextWrapper::ContextWrapper; + KUBE_CONTEXTWRAPPER_PROPERTY(QString, Property1, property1) + KUBE_CONTEXTWRAPPER_PROPERTY(QByteArray, Property2, property2) +}; + +class Context2 : public Kube::ContextWrapper { + using Kube::ContextWrapper::ContextWrapper; + KUBE_CONTEXTWRAPPER_PROPERTY(QByteArray, Property2, property2) +}; + + +class ActionTest : public QObject +{ + Q_OBJECT +private slots: + + void initTestCase() + { + } + + void testActionExecution() + { + Handler actionHandler; + + HandlerContext context; + //Kube::Context context; + HandlerContextWrapper{context}.setProperty1(QString("property1")); + context.setProperty("property2", QVariant::fromValue(QString("property2"))); + auto future = Kube::Action("org.kde.kube.test.action1", context).executeWithResult(); + + QTRY_VERIFY(future.isDone()); + QVERIFY(!future.error()); + + QCOMPARE(actionHandler.executions.size(), 1); + QCOMPARE(actionHandler.executions.first().availableProperties().size(), 2); + } + + void testContextCasting() + { + Kube::Context c; + + Context1 context1{c}; + context1.setProperty1("property1"); + context1.setProperty2("property2"); + + auto context2 = Context2{c}; + QCOMPARE(context2.getProperty2(), QByteArray("property2")); + } + +}; + +QTEST_GUILESS_MAIN(ActionTest) +#include "actiontest.moc" -- cgit v1.2.3