Use of gcsDebug instead of qDebug
[meego-garage:garage-client-services.git] / src / applicationstatusstorage.cpp
1 #include "applicationstatusstorage.h"
2 #include "application.h"
3 #include <QDateTime>
4 #include <QtDebug>
5 #include "utils.h"
6
7 // update every 3 days
8 const int secsToForceUpdate = 60 * 60 * 24 * 3;
9
10 namespace MeeGoGarage {
11
12 ApplicationStatusStorage::ApplicationStatusStorage() :
13     m_domDocument("MeeGoGarage")
14 {
15     QDomElement element = m_domDocument.createElement("MeeGoGarage");
16     m_domDocument.appendChild(element);
17 }
18
19 bool ApplicationStatusStorage::read(QIODevice *device)
20 {
21     gcsDebug();
22
23     if (!device)
24         return false;
25
26     if (device->size() <= 0)
27         return false;
28
29     QString errorStr;
30     int errorLine;
31     int errorColumn;
32
33     if (!m_domDocument.setContent(device, true, &errorStr, &errorLine,
34                                 &errorColumn)) {
35         qWarning() << QString("Parse error at line %1, column %2:\n%3")
36                                  .arg(errorLine)
37                                  .arg(errorColumn)
38                                  .arg(errorStr);
39         return false;
40     }
41
42     QDomElement root = m_domDocument.documentElement();
43     gcsDebug() << "Root has children = " << root.childNodes().count();
44     if (root.tagName() != "MeeGoGarage") {
45         qWarning() << "The file is not an MeeGoGarage file.";
46         return false;
47     } else if (root.hasAttribute("version")
48                && root.attribute("version") != "1.0") {
49         qWarning() << "The file is not an MeeGoGarage version 1.0 file.";
50         return false;
51     }
52
53     //disconnect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
54     //           this, SLOT(updateDomElement(QTreeWidgetItem*,int)));
55
56     QDomElement app = root.firstChildElement("application");
57     while (!app.isNull()) {
58         gcsDebug() << "reading from XML file" << app.attribute("id");
59         // processNode can get modified, better ask sibling before that
60         QDomElement processNode = app;
61         app = app.nextSiblingElement("application");
62         parseDomElement(processNode);
63     }
64
65     //connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
66     //        this, SLOT(updateDomElement(QTreeWidgetItem*,int)));
67
68     return true;
69 }
70
71 bool ApplicationStatusStorage::write(QIODevice *device)
72 {
73     gcsDebug();
74
75     if (!device)
76         return false;
77
78     // make sure all apps registered are persisted
79     ApplicationList apps = m_applicationForUuid.values();
80     QListIterator<Application*> i(apps);
81     while(i.hasNext()) {
82         Application * app = i.next();
83         if (app) {
84             updateDomElement(app);
85         }
86     }
87
88     const int IndentSize = 4;
89
90     QTextStream out(device);
91     m_domDocument.save(out, IndentSize);
92     return true;
93 }
94
95 void ApplicationStatusStorage::registerApplications(ApplicationList appList)
96 {
97     gcsDebug();
98
99     QListIterator<Application*> i(appList);
100     while(i.hasNext()) {
101         Application * app = i.next();
102         if (app) {
103             QString id = app->id();
104             if (!id.isNull() && !id.isEmpty()) {
105                 QHash<QString,Application*>::iterator it = m_applicationForUuid.find(id);
106                 if (it != m_applicationForUuid.end()) {
107                     qWarning() << "Application already registered id=" << id << app->name();
108                 } else {
109                     connect(app, SIGNAL(statusUpdated(Application::Status,bool)),
110                             this, SLOT(onStatusUpdated(Application::Status,bool)));
111                 }
112
113                 gcsDebug() << "Registering app " << app->name() << " uid=" << id;
114
115                 m_applicationForUuid[id] = app;
116             }
117         }
118     }
119 }
120
121 void ApplicationStatusStorage::updateApplications(ApplicationList appList)
122 {
123     QListIterator<Application*> i(appList);
124     while(i.hasNext()) {
125         Application * app = i.next();
126         if (app) {
127             updateDomElement(app);
128         }
129     }
130 }
131
132 void ApplicationStatusStorage::parseDomElement(QDomElement & element)
133 {
134     if (!element.isNull()) {
135         QString id = element.attribute("id");
136         QString statusStr = element.attribute("status");
137         QString lastUpdateStr = element.attribute("lastUpdate");
138
139         gcsDebug() << "Parse DOM element " << id << statusStr << lastUpdateStr;
140
141         if (id.isEmpty() || id.isNull() ||
142             statusStr.isEmpty() || statusStr.isNull() ||
143             lastUpdateStr.isEmpty() || lastUpdateStr.isNull()) {
144             return;
145         }
146
147         // update mapping QUuid -> QDomElement
148         m_domElementForUuid[id] = element;
149
150         // find application by id
151         QHash<QString,Application*>::const_iterator it = m_applicationForUuid.find(id);
152         if (it == m_applicationForUuid.constEnd()) {
153             return;
154         }
155         Application * app = (*it);
156         if (!app) {
157             return;
158         }
159
160         // convert status to proper state
161         Application::Status status;
162         if (statusStr == "Installed") {
163             status = Application::InstalledStatus;
164         } else if (statusStr == "NotInstalled") {
165             status = Application::NotInstalledStatus;
166         } else if (statusStr == "UpdateAvailable") {
167             status = Application::UpdateAvailableStatus;
168         //} else if (statusStr == "ResolveError") {
169         //    status = Application::ResolveErrorStatus;
170         } else {
171             status = Application::UnknownStatus;
172         }
173
174         // convert time
175         QDateTime lastUpdate = QDateTime::fromString(lastUpdateStr, Qt::ISODate);
176
177         // assign to application
178         if (!app->updateStatus(status, lastUpdate)) {
179             updateDomElement(app);
180         }
181     }
182 }
183
184 void ApplicationStatusStorage::updateDomElement(Application *app)
185 {
186     if (!app)
187         return;
188
189     QString id = app->id();
190     if (id.isNull() || id.isEmpty())
191         return;
192
193     gcsDebug() << "Update DOM element " << app->name() << id;
194
195     // update uid -> application
196     m_applicationForUuid[id] = app;
197
198     // translate application status into a string
199     Application::Status status = app->status();
200     QString statusStr;
201     switch(status) {
202     case Application::InstalledStatus:
203     case Application::QueuedRemoveStatus:
204     case Application::RemovingStatus:
205         statusStr = "Installed";
206         break;
207     case Application::NotInstalledStatus:
208     case Application::QueuedInstallStatus:
209     case Application::InstallingStatus:
210         statusStr = "NotInstalled";
211         break;
212     case Application::UpdateAvailableStatus:
213     case Application::QueuedUpdateStatus:
214     case Application::UpdatingStatus:
215         statusStr = "UpdateAvailable";
216         break;
217     case Application::ResolveErrorStatus:
218         // do not save ResolveErrorStatus
219         //statusStr = "ResolveError";
220         //break;
221     case Application::UnknownStatus:
222     case Application::QueuedResolveStatus:
223     case Application::ResolvingStatus:
224     case Application::ErrorStatus:
225         // do not save these states
226         break;
227     }
228
229     // translate date into a string
230     QDateTime lastUpdate = app->getLastUpdateStatusDateTime();
231     QString lastUpdateStr = lastUpdate.toString(Qt::ISODate);
232
233     // if status is empty we should not save it -> remove from tree
234     QHash<QString,QDomElement>::iterator it = m_domElementForUuid.find(id);
235     if (statusStr.isNull() || statusStr.isEmpty()) {
236         if (it != m_domElementForUuid.end()) {
237             QDomElement element = *it;
238             m_domElementForUuid.remove(id);
239             element.parentNode().removeChild(element);
240         }
241     } else {
242         // create a dom element if does not exist
243         if (it == m_domElementForUuid.end()) {
244             QDomElement element = m_domDocument.createElement("application");
245             QDomElement root = m_domDocument.documentElement();
246             root.appendChild(element);
247             m_domElementForUuid[id] = element;
248             element.setAttribute("id", id);
249             element.setAttribute("status", statusStr);
250             element.setAttribute("lastUpdate", lastUpdateStr);
251             element.setAttribute("name", app->name());
252         } else {
253             QDomElement element = *it;
254             element.setAttribute("status", statusStr);
255             element.setAttribute("lastUpdate", lastUpdateStr);
256         }
257     }
258 }
259
260 ApplicationList ApplicationStatusStorage::oldOrUnknownApps()
261 {
262     QDateTime now = QDateTime::currentDateTime().toUTC();
263
264     ApplicationList apps = m_applicationForUuid.values();
265     QMutableListIterator<Application*> i(apps);
266     while(i.hasNext()) {
267         Application * app = i.next();
268         if (app) {
269             if (app->status() == Application::InstalledStatus
270                     || app->status() == Application::UpdateAvailableStatus
271                     || app->status() == Application::NotInstalledStatus) {
272                 if (app->getLastUpdateStatusDateTime().secsTo(now) < secsToForceUpdate) {
273                     i.remove();
274                 }
275             }
276         }
277     }
278
279     return apps;
280 }
281
282 void ApplicationStatusStorage::onStatusUpdated(Application::Status /*status*/, bool fromCache)
283 {
284     // we ignore changes produced by itself
285     if (fromCache)
286         return;
287
288     Application * app= qobject_cast<Application *> (sender());
289     if (app != 0) {
290
291         gcsDebug() << app->name();
292
293         updateDomElement(app);
294     }
295 }
296
297 } // namespace MeeGoGarage
298