1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3  * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4  * SPDX-License-Identifier: GPL-3.0-or-later
5  ***************************************************************************/
6 /** @file
7 * This akonadi resource.
8 *
9 * @author Stephane MANKOWSKI / Guillaume DE BURE
10  */
11 #include "skroogeakonadiresource.h"
12 
13 #ifdef SKG_DBUS
14 #include <qdbusconnection.h>
15 #endiff
16 
17 #include <kdirwatch.h>
18 #include <klocalizedstring.h>
19 
20 #include <akonadicore/entitydisplayattribute.h>
21 #include <kcalcore/todo.h>
22 #include <kpassworddialog.h>
23 #include <qfiledialog.h>
24 
25 #include "settings.h"
26 #include "settingsadaptor.h"
27 #include "skgcategoryobject.h"
28 #include "skgdocumentbank.h"
29 #include "skgoperationobject.h"
30 #include "skgrecurrentoperationobject.h"
31 
skroogeakonadiResource(const QString & id)32 skroogeakonadiResource::skroogeakonadiResource(const QString& id) : ResourceBase(id)
33 {
34     setObjectName(QStringLiteral("SkroogeResource"));
35     setNeedsNetwork(false);
36 
37     new SettingsAdaptor(Settings::self());
38 #ifdef SKG_DBUS
39     QDBusConnection::sessionBus().registerObject(QStringLiteral("/Settings"),
40             Settings::self(), QDBusConnection::ExportAdaptors);
41 #endif
42 
43     if (!KDirWatch::self()->contains(Settings::self()->path())) {
44         KDirWatch::self()->addFile(Settings::self()->path());
45     }
46     QObject::connect(KDirWatch::self(), &KDirWatch::dirty, this, &skroogeakonadiResource::refresh);
47 
48     synchronize();
49 }
50 
51 skroogeakonadiResource::~skroogeakonadiResource() = default;
52 
retrieveCollections()53 void skroogeakonadiResource::retrieveCollections()
54 {
55     Akonadi::Collection c;
56     c.setRemoteId(Settings::self()->path());
57     c.setName(i18nc("Name of a collection akonadi", "Skrooge scheduled operations"));
58     c.setRights(Akonadi::Collection::ReadOnly);
59     c.setParentCollection(Akonadi::Collection::root());
60     c.setContentMimeTypes(QStringList() <<  QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
61 
62     Akonadi::EntityDisplayAttribute* const attribute = new Akonadi::EntityDisplayAttribute();
63     attribute->setIconName("skrooge");
64     c.addAttribute(attribute);
65 
66     collectionsRetrieved(Akonadi::Collection::List() << c);
67 
68     if (!KDirWatch::self()->contains(Settings::self()->path())) {
69         KDirWatch::self()->addFile(Settings::self()->path());
70     }
71 }
72 
retrieveItems(const Akonadi::Collection & collection)73 void skroogeakonadiResource::retrieveItems(const Akonadi::Collection& collection)
74 {
75     Akonadi::Item::List items;
76 
77     // Open the document
78     SKGDocumentBank doc;
79     SKGError err = doc.load(collection.remoteId(), Settings::self()->password(), false, true);
80     IFOK(err) {
81         SKGObjectBase::SKGListSKGObjectBase objs;
82         err = doc.getObjects(QStringLiteral("v_recurrentoperation_display"), QStringLiteral("i_nb_times!=0 ORDER BY d_date"), objs);
83         IFOK(err) {
84             int nb = objs.count();
85             if (nb) {
86                 for (int i = 0; i < nb; ++i) {
87                     Akonadi::Item item(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
88                     item.setRemoteId(collection.remoteId() % ";" % SKGServices::intToString(objs.at(i).getID()));
89 
90                     items << item;
91                 }
92             }
93         }
94     }
95     doc.close();
96 
97     itemsRetrieved(items);
98 }
99 
retrieveItem(const Akonadi::Item & item,const QSet<QByteArray> & parts)100 bool skroogeakonadiResource::retrieveItem(const Akonadi::Item& item, const QSet<QByteArray>& parts)
101 {
102     Q_UNUSED(parts)
103     QStringList params = SKGServices::splitCSVLine(item.remoteId(), ';');
104 
105     bool output = false;
106     SKGDocumentBank doc;
107     SKGError err = doc.load(params.at(0), Settings::self()->password(), false, true);
108     IFOK(err) {
109         SKGRecurrentOperationObject obj(&doc, SKGServices::stringToInt(params.at(1)));
110         SKGOperationObject op;
111         obj.getParentOperation(op);
112 
113         KCalCore::auto akonadiItem = new KCalCore::Todo();
114         KCalCore::Todo::Ptr akonadiItemPtr(akonadiItem);
115         akonadiItem->setDtDue(KDateTime(obj.getDate()));
116         akonadiItem->setDescription(op.getDisplayName().right(op.getDisplayName().count() - 11));
117         if (!obj.hasTimeLimit() || obj.getTimeLimit() > 1) {
118             akonadiItem->setDtRecurrence(KDateTime(obj.getNextDate()));
119         }
120 
121         SKGOperationObject ope;
122         obj.getParentOperation(ope);
123         akonadiItem->setCategories(QStringList() << ope.getAttribute(QStringLiteral("t_CATEGORY")));
124 
125         Akonadi::Item newItem(item);
126         newItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
127         newItem.setPayload<KCalCore::Incidence::Ptr>(akonadiItemPtr);
128 
129         itemRetrieved(newItem);
130         output = true;
131     }
132     doc.close();
133 
134     return output;
135 }
136 
configure(WId windowId)137 void skroogeakonadiResource::configure(WId windowId)
138 {
139     Q_UNUSED(windowId)
140 
141     // Get the old path
142     const QString oldPath = Settings::self()->path();
143     QUrl url;
144     if (!oldPath.isEmpty()) {
145         url = QUrl::fromLocalFile(oldPath);
146     } else {
147         url = QUrl::fromLocalFile(QDir::homePath());
148     }
149 
150     const QString newPath = QFileDialog::getOpenFileName("Skrooge document", 0, url, "*.skg|" % i18nc("A file format", "Skrooge document"), 0, i18nc("@title:window", "Select Skrooge document"));
151 
152     if (newPath.isEmpty() || oldPath == newPath) {
153         return;
154     }
155 
156     // Password dialog
157     QString password;
158     QPointer<KPasswordDialog> dlg = new KPasswordDialog();
159     dlg->setPrompt(i18nc("Question", "If the file is protected.\nPlease enter the password."));
160     if (dlg->exec() == QDialog::Accepted) {
161         password = dlg->password();
162     }
163     delete dlg;
164 
165     // Save settings
166     Settings::self()->setPath(newPath);
167     Settings::self()->setPassword(password);
168     Settings::self()->save();
169 
170     KDirWatch::self()->removeDir(oldPath);
171     KDirWatch::self()->addFile(newPath);
172 
173     synchronize();
174 }
175 
refresh()176 void skroogeakonadiResource::refresh()
177 {
178     invalidateCache(currentCollection());
179     synchronize();
180 }
181 
182 AKONADI_RESOURCE_MAIN(skroogeakonadiResource)
183 
184 
185