diff --git a/kmymoney/mymoney/onlinejob.cpp b/kmymoney/mymoney/onlinejob.cpp index 768af605a..d6375f719 100644 --- a/kmymoney/mymoney/onlinejob.cpp +++ b/kmymoney/mymoney/onlinejob.cpp @@ -1,322 +1,322 @@ /* * Copyright 2013-2015 Christian Dávid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "onlinejob.h" #include "onlinejob_p.h" #include #include #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "tasks/onlinetask.h" #include "onlinejobadministration.h" #include "mymoneystoragenames.h" using namespace MyMoneyStorageNodes; onlineJob::onlineJob() : MyMoneyObject(*new onlineJobPrivate), m_task(0) { Q_D(onlineJob); d->m_jobSend = QDateTime(); d->m_jobBankAnswerDate = QDateTime(); d->m_jobBankAnswerState = noBankAnswer; d->m_messageList = QList(); d->m_locked = false; } onlineJob::onlineJob(onlineTask* onlinetask, const QString &id) : MyMoneyObject(*new onlineJobPrivate, id), m_task(onlinetask) { Q_D(onlineJob); d->m_jobSend = QDateTime(); d->m_jobBankAnswerDate = QDateTime(); d->m_jobBankAnswerState = noBankAnswer; d->m_messageList = QList(); d->m_locked = false; } onlineJob::onlineJob(onlineTask* onlinetask) : MyMoneyObject(*new onlineJobPrivate, QString()), m_task(onlinetask) { Q_D(onlineJob); d->m_jobSend = QDateTime(); d->m_jobBankAnswerDate = QDateTime(); d->m_jobBankAnswerState = noBankAnswer; d->m_messageList = QList(); d->m_locked = false; } onlineJob::onlineJob(onlineJob const& other) : MyMoneyObject(*new onlineJobPrivate(*other.d_func()), other.id()), m_task(0) { copyPointerFromOtherJob(other); } onlineJob::onlineJob(const QString &id, const onlineJob& other) : MyMoneyObject(*new onlineJobPrivate(*other.d_func()), id), m_task() { Q_D(onlineJob); d->m_jobSend = QDateTime(); d->m_jobBankAnswerDate = QDateTime(); d->m_jobBankAnswerState = noBankAnswer; d->m_messageList = QList(); d->m_locked = false; copyPointerFromOtherJob(other); } onlineJob::onlineJob(const QDomElement& element) : MyMoneyObject(*new onlineJobPrivate, element, true) { Q_D(onlineJob); d->m_messageList = QList(); d->m_locked = false; d->m_jobSend = QDateTime::fromString(element.attribute(d->getAttrName(OnlineJob::Attribute::Send)), Qt::ISODate); d->m_jobBankAnswerDate = QDateTime::fromString(element.attribute(d->getAttrName(OnlineJob::Attribute::BankAnswerDate)), Qt::ISODate); QString state = element.attribute(d->getAttrName(OnlineJob::Attribute::BankAnswerState)); if (state == d->getAttrName(OnlineJob::Attribute::AbortedByUser)) d->m_jobBankAnswerState = abortedByUser; else if (state == d->getAttrName(OnlineJob::Attribute::AcceptedByBank)) d->m_jobBankAnswerState = acceptedByBank; else if (state == d->getAttrName(OnlineJob::Attribute::RejectedByBank)) d->m_jobBankAnswerState = rejectedByBank; else if (state == d->getAttrName(OnlineJob::Attribute::SendingError)) d->m_jobBankAnswerState = sendingError; else d->m_jobBankAnswerState = noBankAnswer; QDomElement taskElem = element.firstChildElement(d->getElName(OnlineJob::Element::OnlineTask)); m_task = onlineJobAdministration::instance()->createOnlineTaskByXml(taskElem.attribute(d->getAttrName(OnlineJob::Attribute::IID)), taskElem); } void onlineJob::copyPointerFromOtherJob(const onlineJob &other) { if (!other.isNull()) m_task = other.constTask()->clone(); } void onlineJob::reset() { Q_D(onlineJob); clearId(); d->m_jobSend = QDateTime(); d->m_jobBankAnswerDate = QDateTime(); d->m_jobBankAnswerState = noBankAnswer; d->m_locked = false; } onlineJob::~onlineJob() { delete m_task; } onlineTask* onlineJob::task() { if (m_task == 0) - throw EMPTYTASKEXCEPTION(); + throw EMPTYTASKEXCEPTION; return m_task; } const onlineTask* onlineJob::task() const { if (m_task == 0) - throw EMPTYTASKEXCEPTION(); + throw EMPTYTASKEXCEPTION; return m_task; } const onlineTask* onlineJob::constTask() const { return task(); } QString onlineJob::taskIid() const { try { return task()->taskName(); } catch (const emptyTask&) { } return QString(); } QString onlineJob::responsibleAccount() const { try { return task()->responsibleAccount(); } catch (const emptyTask&) { } return QString(); } MyMoneyAccount onlineJob::responsibleMyMoneyAccount() const { QString accountId = responsibleAccount(); if (!accountId.isEmpty()) return MyMoneyFile::instance()->account(accountId); return MyMoneyAccount(); } bool onlineJob::setLock(bool enable) { Q_D(onlineJob); d->m_locked = enable; return true; } bool onlineJob::isLocked() const { Q_D(const onlineJob); return d->m_locked; } bool onlineJob::isEditable() const { Q_D(const onlineJob); return (!isLocked() && sendDate().isNull() && (d->m_jobBankAnswerState == noBankAnswer || d->m_jobBankAnswerState == sendingError)); } bool onlineJob::isNull() const { return (m_task == 0); } void onlineJob::setJobSend(const QDateTime &dateTime) { Q_D(onlineJob); d->m_jobSend = dateTime; } void onlineJob::setJobSend() { setJobSend(QDateTime::currentDateTime()); } void onlineJob::setBankAnswer(const onlineJob::sendingState state, const QDateTime &dateTime) { Q_D(onlineJob); d->m_jobBankAnswerState = state; d->m_jobBankAnswerDate = dateTime; } void onlineJob::setBankAnswer(const onlineJob::sendingState state) { setBankAnswer(state, QDateTime::currentDateTime()); } QDateTime onlineJob::bankAnswerDate() const { Q_D(const onlineJob); return d->m_jobBankAnswerDate; } onlineJob::sendingState onlineJob::bankAnswerState() const { Q_D(const onlineJob); return d->m_jobBankAnswerState; } void onlineJob::addJobMessage(const onlineJobMessage& message) { Q_D(onlineJob); d->m_messageList.append(message); } void onlineJob::addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode, const QDateTime& timestamp) { Q_D(onlineJob); onlineJobMessage logMessage(type, sender, message, timestamp); logMessage.setSenderErrorCode(errorCode); d->m_messageList.append(logMessage); } void onlineJob::addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode) { addJobMessage(type, sender, message, errorCode, QDateTime::currentDateTime()); } void onlineJob::addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message) { addJobMessage(type, sender, message, QString(), QDateTime::currentDateTime()); } QList onlineJob::jobMessageList() const { Q_D(const onlineJob); return d->m_messageList; } /** @todo give life */ void onlineJob::writeXML(QDomDocument &document, QDomElement &parent) const { auto el = document.createElement(nodeNames[nnOnlineJob]); Q_D(const onlineJob); d->writeBaseXML(document, el); if (!d->m_jobSend.isNull()) el.setAttribute(d->getAttrName(OnlineJob::Attribute::Send), d->m_jobSend.toString(Qt::ISODate)); if (!d->m_jobBankAnswerDate.isNull()) el.setAttribute(d->getAttrName(OnlineJob::Attribute::BankAnswerDate), d->m_jobBankAnswerDate.toString(Qt::ISODate)); switch (d->m_jobBankAnswerState) { case abortedByUser: el.setAttribute(d->getAttrName(OnlineJob::Attribute::BankAnswerState), d->getAttrName(OnlineJob::Attribute::AbortedByUser)); break; case acceptedByBank: el.setAttribute(d->getAttrName(OnlineJob::Attribute::BankAnswerState), d->getAttrName(OnlineJob::Attribute::AcceptedByBank)); break; case rejectedByBank: el.setAttribute(d->getAttrName(OnlineJob::Attribute::BankAnswerState), d->getAttrName(OnlineJob::Attribute::RejectedByBank)); break; case sendingError: el.setAttribute(d->getAttrName(OnlineJob::Attribute::BankAnswerState), d->getAttrName(OnlineJob::Attribute::SendingError)); break; case noBankAnswer: default: void(); } QDomElement taskEl = document.createElement(d->getElName(OnlineJob::Element::OnlineTask)); taskEl.setAttribute(d->getAttrName(OnlineJob::Attribute::IID), taskIid()); try { task()->writeXML(document, taskEl); // throws execption if there is no task el.appendChild(taskEl); // only append child if there is something to append } catch (const emptyTask&) { } parent.appendChild(el); } bool onlineJob::isValid() const { if (m_task != 0) return m_task->isValid(); return false; } QDateTime onlineJob::sendDate() const { Q_D(const onlineJob); return d->m_jobSend; } bool onlineJob::hasReferenceTo(const QString& id) const { if (m_task != 0) return m_task->hasReferenceTo(id); return false; } diff --git a/kmymoney/mymoney/onlinejob.h b/kmymoney/mymoney/onlinejob.h index 388e78894..bbe811bc4 100644 --- a/kmymoney/mymoney/onlinejob.h +++ b/kmymoney/mymoney/onlinejob.h @@ -1,358 +1,356 @@ /* * Copyright 2013-2015 Christian Dávid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ONLINEJOB_H #define ONLINEJOB_H #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) -#define BADTASKEXCEPTION(what) badTaskCast("Casted onlineTask with wrong type. " __FILE__ ":" TOSTRING(__LINE__)) -#define EMPTYTASKEXCEPTION(what) emptyTask("Requested onlineTask of onlineJob without any task. " __FILE__ ":" TOSTRING(__LINE__)) +#define BADTASKEXCEPTION badTaskCast("Casted onlineTask with wrong type. " __FILE__ ":" TOSTRING(__LINE__)) +#define EMPTYTASKEXCEPTION emptyTask("Requested onlineTask of onlineJob without any task. " __FILE__ ":" TOSTRING(__LINE__)) #include #include #include "mymoneyobject.h" #include "mymoneyexception.h" #include "onlinejobmessage.h" class onlineTask; class MyMoneyAccount; /** * @brief Class to share jobs which can be procceded by an online banking plugin * * This class stores only the status information and a pointer to an @r onlineTask which stores * the real data. So onlineJob is similar to an shared pointer. * * If you know the type of the onlineTask, @r onlineJobTyped is the first choice to use. * * It is save to use because accesses to pointers (e.g. task() ) throw an execption if onlineJob is null. * * Online jobs are usually not created directly but over @r onlineJobAdministration::createOnlineJob. This is * required to allow loading of onlineTasks at runtime and only if needed. * * This class was created to help writing stable and reliable code. Before an unsafe structure (= pointer) * is accessed it is checked. Exceptions are thrown if the content is unsafe. * * @see onlineTask * @see onlineJobTyped * @todo LOW make data implicitly shared */ class onlineJobPrivate; class KMM_MYMONEY_EXPORT onlineJob : public MyMoneyObject { Q_DECLARE_PRIVATE(onlineJob) KMM_MYMONEY_UNIT_TESTABLE public: /** * @brief Contructor for null onlineJobs * * A onlineJob which is null cannot become valid again. * @see isNull() */ onlineJob(); /** * @brief Default construtor * * The onlineJob takes ownership of the task. The task is deleted in the destructor. */ onlineJob(onlineTask* task, const QString& id); // krazy:exclude=explicit onlineJob(onlineTask* task); // krazy:exclude=explicit /** @brief Contruct from xml */ explicit onlineJob(const QDomElement&); /** * @brief Create new onlineJob as copy of other * * This constructor does not copy the status information but the task only. */ onlineJob(const QString &id, const onlineJob& other); onlineJob(const onlineJob & other); onlineJob(onlineJob && other); onlineJob & operator=(onlineJob other); friend void swap(onlineJob& first, onlineJob& second); virtual ~onlineJob(); /** * @brief Returns task attached to this onlineJob * * You should not store this pointer but use onlineJob::task() (or @r onlineJobTyped::task()) * every time you access it. * * @note The return type may change in future (e.g. to an atomic pointer). But you can always expect * the operator @c -> to work like it does for onlineTask*. * * @throws emptyTask if isNull() */ onlineTask* task(); /** @copydoc task(); */ const onlineTask* task() const; /** * @brief Returns task attached to this onlineJob as const * @throws emptyTask if isNull() */ const onlineTask* constTask() const; /** * @brief Returns task of type T attached to this onlineJob * * Internaly a dynamic_cast is done and the result is checked. * * @throws emptyTask if isNull() * @throws badTaskCast if attached task cannot be casted to T */ template T* task(); /** @copydoc task() */ template const T* task() const; template const T* constTask() const { return task(); } template bool canTaskCast() const; QString taskIid() const; /** @todo implement */ bool hasReferenceTo(const QString &id) const override; void writeXML(QDomDocument &document, QDomElement &parent) const override; /** * @brief The state of a job given by the onlinePlugin */ enum sendingState { noBankAnswer, /**< Used during or before sending or if sendDate().isValid() the job was successfully sent */ acceptedByBank, /**< bank definetly confirmed the job */ rejectedByBank, /**< bank definetly rejected this job */ abortedByUser, /**< aborted by user during sending */ sendingError /**< an error occurred, the job is certainly not executed by the bank */ }; /** * @brief Account this job is related to * * Each job must have an account on which the job operates. This is used to determine * the correct onlinePlugin which can execute this job. If the job is related to more * than one account (e.g. a password change) select a random one. * * @return accountId or QString() if none is set or job isNull. */ virtual QString responsibleAccount() const; /** * @brief Returns the MyMoneyAccount this job is related to * @see responsibleAccount() */ MyMoneyAccount responsibleMyMoneyAccount() const; /** * @brief Check if this onlineJob is editable by the user * * A job is no longer editable by the user if it is used for documentary purposes * e.g. the job was sent to the bank. In that case create a new job based on the * old one. * * @todo make it possible to use onlineJobs as templates */ virtual bool isEditable() const; /** * @brief Checks if this onlineJob has an attached task * * @return true if no task is attached to this job */ virtual bool isNull() const; /** * @brief Checks if an valid onlineTask is attached * * @return true if task().isValid(), false if isNull() or !task.isValid() */ virtual bool isValid() const; /** * @brief DateTime the job was sent to the bank * * A valid return does not mean that this job was accepted by the bank. * * @return A valid QDateTime if send to bank, an QDateTime() if not send. */ virtual QDateTime sendDate() const; /** * @brief Mark this job as send * * To be used by online plugin only! * * Set dateTime to QDateTime to mark unsend. */ virtual void setJobSend(const QDateTime &dateTime); virtual void setJobSend(); /** * @brief The bank's answer to this job * * To be used by online plugin only! * * Set dateTime to QDateTime() and bankAnswer to noState to mark unsend. If bankAnswer == noState dateTime.isNull() must be true! */ void setBankAnswer(const sendingState state, const QDateTime &dateTime); void setBankAnswer(const sendingState state); /** * @brief DateTime of the last status update by the bank * */ QDateTime bankAnswerDate() const; /** * @brief Returns last status sand by bank * @return */ sendingState bankAnswerState() const; /** * @brief locks the onlineJob for sending it * * Used when the job is in sending process by the online plugin. * * A locked onlineJob cannot be removed from the storage. * * @note The onlineJob can still be edited and stored. But it should be done by * the one how owns the lock only. * * @todo Enforce the lock somehow? Note: the onlinePlugin must still be able to * write to the job. * * @param enable true locks the job, false unlocks the job */ virtual bool setLock(bool enable = true); /** * @brief Get lock status */ virtual bool isLocked() const; /** * @brief Make this onlineJob a "new" onlineJob * * Removes all status information, log, and the id. Only * the task is keept. */ virtual void reset(); /** * @brief addJobMessage * * To be used by online plugin only. * @param message */ void addJobMessage(const onlineJobMessage &message); /** * @brief Convenient method to set add a log message */ void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode, const QDateTime& timestamp); void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message, const QString& errorCode); void addJobMessage(const eMyMoney::OnlineJob::MessageType& type, const QString& sender, const QString& message); /** * @brief jobMessageList * @return */ virtual QList jobMessageList() const; /** * @brief Thrown if a cast of a task fails * * This is inspired by std::bad_cast */ class badTaskCast : public std::runtime_error { public: explicit badTaskCast(const char *msg) : std::runtime_error(msg) {} }; /** * @brief Thrown if a task of an invalid onlineJob is requested */ class emptyTask : public std::runtime_error { public: explicit emptyTask(const char *msg) : std::runtime_error(msg) {} }; /** @brief onlineTask attatched to this job */ onlineTask* m_task; private: /** @brief Copies stored pointers (used by copy constructors) */ inline void copyPointerFromOtherJob(const onlineJob& other); }; inline void swap(onlineJob& first, onlineJob& second) // krazy:exclude=inline { using std::swap; swap(first.d_ptr, second.d_ptr); swap(first.m_task, second.m_task); } inline onlineJob::onlineJob(onlineJob && other) : onlineJob() // krazy:exclude=inline { swap(*this, other); } inline onlineJob & onlineJob::operator=(onlineJob other) // krazy:exclude=inline { swap(*this, other); return *this; } template T* onlineJob::task() { T* ret = dynamic_cast(m_task); if (ret == 0) - throw EMPTYTASKEXCEPTION(); -// throw badTaskCast(__FILE__, __LINE__); + throw EMPTYTASKEXCEPTION; return ret; } template const T* onlineJob::task() const { const T* ret = dynamic_cast(m_task); if (ret == 0) - throw BADTASKEXCEPTION(); -// throw badTaskCast(__FILE__, __LINE__); + throw BADTASKEXCEPTION; return ret; } Q_DECLARE_METATYPE(onlineJob) #endif // ONLINEJOB_H diff --git a/kmymoney/mymoney/onlinejobtyped.h b/kmymoney/mymoney/onlinejobtyped.h index 62bd0115b..97e13a2f7 100644 --- a/kmymoney/mymoney/onlinejobtyped.h +++ b/kmymoney/mymoney/onlinejobtyped.h @@ -1,147 +1,147 @@ /* * Copyright 2013-2014 Christian Dávid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ONLINEJOBTYPED_H #define ONLINEJOBTYPED_H #include "onlinejob.h" #include "onlinejobadministration.h" /** * @brief Convenient template if you know the task type of an onlineJob * * To prevent using onlineJob.task() repeatingly you can use this class * where task() has a defined return type. * * Any type check is done in the constructors. So an invalid onlineJobTyped * cannot exist. This class is very fast as well because task() does not need * any checks. * * onlineJobTyped::isNull() is always false. All constructors will throw * onlineJobTyped::badCast or onlineJobTyped::emptyTask if they fail. */ template class onlineJobTyped : public onlineJob { KMM_MYMONEY_UNIT_TESTABLE public: /** * @brief create new task * * @throws emptyTask if plugin could not be found/loaded (determined at runtime). */ explicit onlineJobTyped(); /** * @brief Create typed onlineJob * * @throws emptyTask if task == 0 */ explicit onlineJobTyped(T* task, const QString& id = QString()); /** @brief Copy constructor */ onlineJobTyped(onlineJobTyped const& other); /** * @brief Copy from onlineJob * * @throws badTaskCast if task in other does not fit T * @throws emptyTask if other has no task */ explicit onlineJobTyped(const onlineJob &other); /** @brief Copy constructor with new id */ explicit onlineJobTyped(const QString &id, const onlineJobTyped& other); /** Does not throw */ inline T* task(); // krazy:exclude=inline /** Does not throw */ inline const T* task() const; // krazy:exclude=inline /** Does not throw */ inline const T* constTask() const { // krazy:exclude=inline return task(); } /** Does not throw */ onlineJobTyped operator =(onlineJobTyped const& other); private: T* m_taskTyped; }; template onlineJobTyped::onlineJobTyped() : onlineJob(onlineJobAdministration::instance()->createOnlineTask(T::name())) { m_taskTyped = static_cast(onlineJob::task()); // this can throw emptyTask // Just be safe: an onlineTask developer could have done something wrong Q_CHECK_PTR(dynamic_cast(onlineJob::task())); } template onlineJobTyped::onlineJobTyped(T* task, const QString& id) : onlineJob(task, id), m_taskTyped(task) { if (!task) - throw EMPTYTASKEXCEPTION(); + throw EMPTYTASKEXCEPTION; } template onlineJobTyped::onlineJobTyped(onlineJobTyped const& other) : onlineJob(other) { m_taskTyped = dynamic_cast(onlineJob::task()); Q_CHECK_PTR(m_taskTyped); } template onlineJobTyped onlineJobTyped::operator =(onlineJobTyped const & other) { onlineJob::operator =(other); m_taskTyped = dynamic_cast(onlineJob::task()); Q_CHECK_PTR(m_taskTyped); return (*this); } template onlineJobTyped::onlineJobTyped(const onlineJob &other) : onlineJob(other) { m_taskTyped = dynamic_cast(onlineJob::task()); // can throw emptyTask if (!m_taskTyped) - throw BADTASKEXCEPTION(); + throw BADTASKEXCEPTION; } template T* onlineJobTyped::task() { Q_CHECK_PTR(m_taskTyped); return m_taskTyped; } template const T* onlineJobTyped::task() const { Q_CHECK_PTR(m_taskTyped); return m_taskTyped; } #endif // ONLINEJOBTYPED_H