1 /*
2  * Copyright 2013-2018  Christian Dávid <christian-david@web.de>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef ONLINEJOBADMINISTRATION_H
19 #define ONLINEJOBADMINISTRATION_H
20 
21 // ----------------------------------------------------------------------------
22 // QT Includes
23 
24 #include <QMap>
25 
26 // ----------------------------------------------------------------------------
27 // KDE Includes
28 
29 // ----------------------------------------------------------------------------
30 // Project Includes
31 
32 #include "onlinejob.h"
33 #include "onlinetasks/interfaces/tasks/onlinetask.h"
34 #include "onlinetasks/interfaces/tasks/ionlinetasksettings.h"
35 #include "onlinetasks/interfaces/tasks/credittransfer.h"
36 #include "onlinetasks/interfaces/converter/onlinetaskconverter.h"
37 
38 class onlineTask;
39 class IonlineJobEdit;
40 
41 namespace KMyMoneyPlugin
42 {
43 class OnlinePluginExtended;
44 }
45 
46 /**
47  * @brief Connection between KMyMoney and the plugins
48  *
49  * It's main task is the communication with plugins
50  * and caching their information during run-time. During
51  * sending this class selects the correct plugin for each
52  * onlineJob.
53  *
54  * This class keeps an overview which account can handle which job and
55  * offers methods to access these information.
56  *
57  * onlineJobAdministration is created with singleton pattern. Get the
58  * instance with @ref onlineJobAdministration::instance() .
59  */
60 class KMM_MYMONEY_EXPORT onlineJobAdministration : public QObject
61 {
62   Q_OBJECT
63   KMM_MYMONEY_UNIT_TESTABLE
64 
65   Q_PROPERTY(bool canSendAnyTask READ canSendAnyTask NOTIFY canSendAnyTaskChanged STORED false);
66   Q_PROPERTY(bool canSendCreditTransfer READ canSendCreditTransfer NOTIFY canSendCreditTransferChanged STORED false);
67 
68 protected:
69   explicit onlineJobAdministration(QObject *parent = 0);
70 
71 public:
72   ~onlineJobAdministration();
73 
74   struct onlineJobEditOffer {
75     QString fileName;
76     QString pluginKeyword;
77     QString name;
78   };
79   using onlineJobEditOffers = QVector<onlineJobEditOffer>;
80 
81   /**
82    * @brief List all available onlineTasks
83    */
84   QStringList availableOnlineTasks();
85 
86   static onlineJobAdministration* instance();
87 
88   /** @brief clear the internal caches for shutdown */
89   void clearCaches();
90 
91   /** @brief Use onlineTask::name() to create a corresponding onlineJob */
92   onlineJob createOnlineJob(const QString& name, const QString& id = QString()) const;
93 
94   /**
95    * @brief Return list of IonlineJobEdits
96    *
97    * Method is temporary!
98    *
99    * @return I stay owner of all pointers.
100    */
101   onlineJobEditOffers onlineJobEdits();
102   QString onlineJobEditName(onlineJobEditOffer);
103 
104   bool isJobSupported(const QString& accountId, const QString& name) const;
105   bool isJobSupported(const QString& accountId, const QStringList& names) const;
106   bool isAnyJobSupported(const QString& accountId) const;
107 
108   onlineTaskConverter::convertType canConvert(const QString& originalTaskIid, const QString& convertTaskIid) const;
109   onlineTaskConverter::convertType canConvert(const QString& originalTaskIid, const QStringList& convertTaskIids) const;
110 
111 #if 0
112   template<class T>
113   onlineJobTyped<T> convert(const onlineJob& original, const QString& convertTaskIid, onlineTaskConverter::convertType& convertType, QString& userInformation, const QString& onlineJobId) const;
114   template<class T>
115   onlineJobTyped<T> convert(const onlineJob& original, const QString& convertTaskIid, onlineTaskConverter::convertType& convertType, QString& userInformation) const;
116 #endif
117 
118   /**
119    * @brief Convert an onlineTask to another type
120    *
121    * @param original onlineJob to convert
122    * @param convertTaskIid onlineTask iid you want to convert into
123    * @param convertType OUT result of conversion. Note: this depends on original
124    * @param userInformation OUT A translated html-string with information about the changes which were done
125    * @param onlineJobId The id of the new onlineJob, if none is given original.id() is used
126    */
127   onlineJob convert(const onlineJob& original, const QString& convertTaskIid, onlineTaskConverter::convertType& convertType, QString& userInformation, const QString& onlineJobId) const;
128 
129   /**
130    * @copydoc convert()
131    */
132   onlineJob convert(const onlineJob& original, const QString& convertTaskIid, onlineTaskConverter::convertType& convertType, QString& userInformation) const;
133 
134   /**
135    * @brief Converts a onlineTask to best fitting type of a set of onlineTasks
136    *
137    * Will look for best conversion possible from original to any of convertTaskIids.
138    *
139    * @param original onlineJob to convert
140    * @param convertTaskIids onlineTask-iids you want to convert into.
141    * @param convertType OUT result of conversion. Note: this depends on original
142    * @param userInformation OUT A translated html-string with information about the changes which were done
143    * @param onlineJobId The id of the new onlineJob, if none is given original.id() is used
144    */
145   onlineJob convertBest(const onlineJob& original, const QStringList& convertTaskIids, onlineTaskConverter::convertType& convertType, QString& userInformation, const QString& onlineJobId) const;
146 
147   /**
148    * @brief Convenient for convertBest() which crates an onlineJob with the same id as original.
149    */
150   onlineJob convertBest(const onlineJob& original, const QStringList& convertTaskIids, onlineTaskConverter::convertType& convertType, QString& userInformation) const;
151 
152   /**
153    * @brief Request onlineTask::settings from plugin
154    *
155    * @return QSharedPointer to settings from plugin, can be a nullptr
156    */
157   template<class T>
158   QSharedPointer<T> taskSettings(const QString& taskId, const QString& accountId) const;
159 
160   /**
161    * @brief Request onlineTask::settings from plugin
162    *
163    * @see onlineTask::settings
164    *
165    * @param taskId onlineTask::name()
166    * @param accountId MyMoneyAccount.id()
167    * @return QSharedPointer to settings. QSharedPointer::isNull() is true if an error occurs
168    * (e.g. plugin does not support the task).
169    */
170   QSharedPointer<IonlineTaskSettings> taskSettings(const QString& taskId, const QString& accountId) const;
171 
172   /**
173    * @brief Check if the onlineTask system can do anything
174    *
175    * This is true if at least one plugin can process one of the available onlineTasks for at least one available account.
176    */
177   bool canSendAnyTask();
178 
179   /**
180    * @brief Are there plugins and accounts to send a credit transfers?
181    *
182    * Like @r canSendAnyTask() but restricts the onlineTasks to credit transfers. This is useful
183    * to disable the create credit transfer buttons.
184    */
185   bool canSendCreditTransfer();
186 
187   /**
188    * @brief Are all preconditions set to edit the given job?
189    */
190   bool canEditOnlineJob(const onlineJob& job);
191 
192   /**
193    * @brief See if a online task has a specified base
194    *
195    * This is usable if you want to see if e.g. taskIid is
196    * of type creditTransfer
197    */
198   template<class baseTask>
199   bool isInherited(const QString& taskIid) const;
200 
201   /**
202    * @brief makes plugins loaded in KMyMoneyApp available here
203    * @param plugins
204    */
205   void setOnlinePlugins(QMap<QString, KMyMoneyPlugin::OnlinePluginExtended*>& plugins);
206 
207   /**
208    * @brief updates online actions and should be called after plugin enable or disable
209    */
210   void updateActions();
211 
212   /**
213    * @brief Creates an onlineTask by its iid and xml data
214    * @return pointer to task, caller gains ownership. Can be 0.
215    */
216   onlineTask* createOnlineTaskByXml(const QString& iid, const QDomElement& element) const;
217 
218 Q_SIGNALS:
219   /**
220    * @brief Emitted if canSendAnyTask() changed
221    *
222    * At the moment it this signal can be sent even if the status did not change.
223    */
224   void canSendAnyTaskChanged(bool);
225 
226   /**
227    * @brief Emitted if canSendCreditTransfer changed
228    *
229    * At the moment it this signal can be sent even if the status did not change.
230    */
231   void canSendCreditTransferChanged(bool);
232 
233 public Q_SLOTS:
234   /**
235    * @brief Slot for plugins to make an onlineTask available.
236    * @param task the task to register, I take ownership
237    */
238   void registerOnlineTask(onlineTask *const task);
239 
240   /**
241    * @brief Slot for plugins to make an onlineTaskConverter available.
242    * @param converter the converter to register, I take ownership
243    */
244   void registerOnlineTaskConverter(onlineTaskConverter *const converter);
245 
246   /**
247    * @brief Check if the properties about available and sendable online tasks are still valid
248    */
249   void updateOnlineTaskProperties();
250 
251 private:
252   /**
253    * Register all available online tasks
254    */
255   void registerAllOnlineTasks();
256 
257   /**
258    * @brief Find onlinePlugin which is responsible for accountId
259    * @param accountId
260    * @return Pointer to onlinePluginExtended, do not delete.
261    */
262   KMyMoneyPlugin::OnlinePluginExtended* getOnlinePlugin(const QString& accountId) const;
263 
264   /**
265    * @brief Creates an onlineTask by iid
266    * @return pointer to task, caller gains ownership. Can be 0.
267    */
268   onlineTask* createOnlineTask(const QString& iid) const;
269 
270   // Must be able to call createOnlineTaskByXml
271   friend class onlineJob;
272 
273   // Must be able to call createOnlineTask
274   template<class T>
275   friend class onlineJobTyped;
276 
277   /**
278    * @brief Get root instance of an onlineTask
279    *
280    * Returns a pointer from m_onlineTasks or tries to load/create
281    * a approiate root element.
282    *
283    * Only createOnlineTask and createOnlineTaskByXml use it.
284    *
285    * @return A pointer, you do *not* gain ownership! Can be 0 if something went wrong.
286    *
287    * @internal Made to be forward compatible when onlineTask are loaded as plugins.
288    */
289   inline onlineTask* rootOnlineTask(const QString& name) const;
290 
291   /**
292    * The key is the onlinePlugin's name
293    */
294   QMap<QString, KMyMoneyPlugin::OnlinePluginExtended*>* m_onlinePlugins;
295 
296   /**
297    * The key is the name of the task
298    */
299   QMap<QString, onlineTask*> m_onlineTasks;
300 
301   /**
302    * Key is the task the converter converts to
303    */
304   QMultiMap<QString, onlineTaskConverter*> m_onlineTaskConverter;
305 
306   /**
307    * Instances of editors
308    */
309   QList<IonlineJobEdit*> m_onlineTaskEditors;
310 
311   bool m_inRegistration;
312 };
313 
314 template<class T>
taskSettings(const QString & taskName,const QString & accountId)315 QSharedPointer<T> onlineJobAdministration::taskSettings(const QString& taskName, const QString& accountId) const
316 {
317   IonlineTaskSettings::ptr settings = taskSettings(taskName, accountId);
318   if (!settings.isNull()) {
319     QSharedPointer<T> settingsFinal = settings.dynamicCast<T>();
320     if (Q_LIKELY(!settingsFinal.isNull()))     // This can only happen if the onlinePlugin has a bug.
321       return settingsFinal;
322   }
323   return QSharedPointer<T>();
324 }
325 
326 template< class baseTask >
isInherited(const QString & taskIid)327 bool onlineJobAdministration::isInherited(const QString& taskIid) const
328 {
329   return (dynamic_cast<baseTask*>(rootOnlineTask(taskIid)) != 0);
330 }
331 
332 #if 0
333 template<class T>
334 onlineJobTyped<T> onlineJobAdministration::convert(const onlineJob& original, const QString& convertTaskIid, onlineTaskConverter::convertType& convertType, QString& userInformation, const QString& onlineJobId) const
335 {
336   onlineJob job = convert(original, convertTaskIid, convertType, userInformation, onlineJobId);
337   return onlineJobTyped<T>(job);
338 }
339 
340 template<class T>
341 onlineJobTyped< T > onlineJobAdministration::convert(const onlineJob& original, const QString& convertTaskIid, onlineTaskConverter::convertType& convertType, QString& userInformation) const
342 {
343   return convert<T>(original, convertTaskIid, convertType, userInformation, original.id());
344 }
345 #endif
346 
347 #endif // ONLINEJOBADMINISTRATION_H
348