xmlreaders.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Copyright 2009 Andrew Stromme <astromme@chatonka.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Library General Public License as
  6. * published by the Free Software Foundation; either version 2, or
  7. * (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 Library General Public
  15. * License along with this program; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. #include "xmlreaders.h"
  20. #include "note.h"
  21. #include "request.h"
  22. #include "session.h"
  23. #include "session_p.h"
  24. #include "task.h"
  25. #include "task_p.h"
  26. #include <QCoreApplication>
  27. #include <KDebug>
  28. #include <QNetworkReply>
  29. struct TempProps {
  30. QString name;
  31. RTM::TaskSeriesId seriesId;
  32. RTM::ListId listId;
  33. QHash<RTM::NoteId, RTM::Note> notes;
  34. QList<RTM::Tag> tags;
  35. };
  36. RTM::TasksReader::TasksReader(RTM::Request* r, RTM::Session* s)
  37. : QXmlStreamReader(r),
  38. session(s),
  39. request(r)
  40. {
  41. Q_ASSERT(r);
  42. Q_ASSERT(s);
  43. request->open(QIODevice::ReadOnly);
  44. request->seek(0);
  45. }
  46. QList< RTM::List* > RTM::TasksReader::readLists() const {
  47. return changedLists;
  48. }
  49. QList< RTM::Task* > RTM::TasksReader::readTasks() const {
  50. return changedTasks;
  51. }
  52. QDateTime RTM::TasksReader::parseDateTime(const QString& datetime)
  53. {
  54. QDateTime offsetTime = QDateTime::fromString(datetime, Qt::ISODate);
  55. return localizedTime(offsetTime);
  56. }
  57. QDateTime RTM::TasksReader::localizedTime(const QDateTime& datetime)
  58. {
  59. QDateTime dt = QDateTime(datetime.date(), datetime.time(), Qt::LocalTime);
  60. KTimeZone utc = KSystemTimeZones::zone("UTC");
  61. KTimeZone rtm = session->d->timezone;
  62. //kDebug() << datetime << dt << utc.convert(rtm, dt);
  63. return utc.convert(rtm, dt);
  64. }
  65. bool RTM::TasksReader::read() {
  66. while (!atEnd()) {
  67. readNext();
  68. // if (isEndElement())
  69. // Do I need to close/save my task?
  70. if (isStartElement()) {
  71. if (name().toString() == "rsp")
  72. readResponse();
  73. else
  74. readUnknownElement();
  75. }
  76. }
  77. foreach(RTM::Task* task, changedTasks)
  78. emit session->taskChanged(task);
  79. foreach(RTM::List* list, changedLists)
  80. emit session->listChanged(list);
  81. if (changedTasks.count() > 0)
  82. emit session->tasksChanged();
  83. if (changedLists.count() > 0)
  84. emit session->listsChanged();
  85. this->device()->close();
  86. return true; // !error();
  87. }
  88. bool RTM::TasksReader::readResponse() {
  89. if (attributes().value("stat") != "ok") {
  90. //TODO: Provide more meaningful error
  91. return false;
  92. }
  93. while (!atEnd()) {
  94. readNext();
  95. if (isEndElement()) {
  96. return true;
  97. }
  98. if (isStartElement()) {
  99. if (name() == "tasks")
  100. readTasksHeader();
  101. else if (name() == "lists")
  102. readListsHeader();
  103. else if (name() == "transaction")
  104. readTransaction();
  105. else
  106. readUnknownElement();
  107. }
  108. }
  109. kDebug() << "Reached the end of readResponse() where we shouldn't have" << name().toString() << text().toString();
  110. kDebug() << "Attributes:";
  111. for(int i=0; i < attributes().count(); i++)
  112. { kDebug() << attributes().at(i).name().toString() << attributes().at(i).value().toString(); }
  113. return false;
  114. }
  115. void RTM::TasksReader::readTransaction() {
  116. // If we're not using a getList method we need to jump to the correct spot
  117. QStringList splitMethod = request->method().split('.');
  118. readNext();
  119. if (splitMethod.at(splitMethod.count() - 2) == "tasks")
  120. readTasksHeader();
  121. else if (splitMethod.at(splitMethod.count() - 2) == "lists")
  122. readListsHeader();
  123. else {
  124. kDebug() << "Unknown Method: " << splitMethod.join(".");
  125. readUnknownElement();
  126. }
  127. }
  128. void RTM::TasksReader::readUnknownElement() {
  129. kDebug() << "Unknown Element: " << tokenString() << name().toString() << text().toString();
  130. kDebug() << "Attributes:";
  131. for(int i=0; i < attributes().count(); i++)
  132. { kDebug() << attributes().at(i).name().toString() << attributes().at(i).value().toString(); }
  133. while(!atEnd()) {
  134. readNext();
  135. if (isEndElement())
  136. break;
  137. if (isStartElement())
  138. readUnknownElement();
  139. }
  140. }
  141. void RTM::TasksReader::readFilter(RTM::List* list) {
  142. list->setFilter(readElementText());
  143. kDebug() << "Filter for list: " << list->name() << " is " << list->filter();
  144. // while (!atEnd()) {
  145. // readNext();
  146. // if (isEndElement())
  147. // return;
  148. // if (isStartElement())
  149. // readUnknownElement();
  150. // }
  151. }
  152. void RTM::TasksReader::readList() {
  153. RTM::List *list = session->listFromId(attributes().value("id").toString().toULong());
  154. if (!list)
  155. list = session->newBlankList(attributes().value("id").toString().toULong());
  156. list->setId(attributes().value("id").toString().toULong());
  157. list->setName(attributes().value("name").toString());
  158. list->setSmart(attributes().value("smart").toString() == "1" ? true : false);
  159. changedLists.append(list);
  160. while (!atEnd()) {
  161. readNext();
  162. if (isEndElement()) {
  163. session->d->lists.insert(list->id(), list);
  164. if (list->isSmart())
  165. session->d->populateSmartList(list);
  166. return;
  167. }
  168. if (isStartElement()) {
  169. if (name() == "filter")
  170. readFilter(list);
  171. else
  172. readUnknownElement();
  173. }
  174. }
  175. }
  176. void RTM::TasksReader::readListsHeader() {
  177. while (!atEnd()) {
  178. readNext();
  179. if (isEndElement()) {
  180. return;
  181. }
  182. if (isStartElement()) {
  183. if (name() == "list")
  184. readList();
  185. else
  186. readUnknownElement();
  187. }
  188. }
  189. }
  190. void RTM::TasksReader::readNotes(TempProps* props) {
  191. //kDebug() << "Notes not supported yet";
  192. if (isEndElement())
  193. return;
  194. while (!atEnd()) {
  195. readNext();
  196. if ((isEndElement()) && (name().toString() == "notes"))
  197. break;
  198. if (isEndElement())
  199. continue; // end of a note
  200. if ((isStartElement()) && (name().toString() == "note")) {
  201. RTM::Note note(attributes().value("id").toString().toULong(), attributes().value("title").toString(), readElementText());
  202. props->notes.insert(note.id(), note);
  203. }
  204. else
  205. readUnknownElement();
  206. }
  207. }
  208. void RTM::TasksReader::readParticipants(TempProps* props) {
  209. Q_UNUSED(props);
  210. //kDebug() << "Participants not supported yet";
  211. if (isEndElement())
  212. return;
  213. while (!atEnd()) {
  214. readNext();
  215. if ((isEndElement()) && (name().toString() == "participants"))
  216. break;
  217. }
  218. }
  219. void RTM::TasksReader::readTags(TempProps* props) {
  220. if (isEndElement())
  221. return;
  222. while (!atEnd()) {
  223. readNext();
  224. if ((isEndElement()) && (name().toString() == "tags"))
  225. break;
  226. if (isEndElement())
  227. continue;
  228. if ((isStartElement()) && (name().toString() == "tag"))
  229. props->tags.append(readElementText());
  230. else
  231. readUnknownElement();
  232. }
  233. }
  234. void RTM::TasksReader::readTask(TempProps *props) {
  235. RTM::Task *task = session->taskFromId(attributes().value("id").toString().toLongLong());
  236. if (!task)
  237. task = session->newBlankTask(attributes().value("id").toString().toLongLong());
  238. task->d->name = props->name;
  239. task->d->seriesId = props->seriesId;
  240. task->d->listId = props->listId;
  241. task->d->notes = props->notes;
  242. task->d->tags = props->tags;
  243. RTM::List *list = session->listFromId(props->listId);
  244. if (!list)
  245. list = session->newBlankList(props->listId);
  246. changedTasks.append(task);
  247. changedLists.append(list);
  248. // Grab ID
  249. task->d->taskId = attributes().value("id").toString().toULong();
  250. // Grab Priority
  251. if (attributes().value("priority") == "N")
  252. task->d->priority = 4;
  253. else
  254. task->d->priority = attributes().value("priority").toString().toInt();
  255. // Grab Due Date/Time
  256. task->d->due = parseDateTime(attributes().value("due").toString());
  257. // if (attributes().value("has_due_time") == "0") BUG: FIXME: Re-Implement time support
  258. // Grab Estimate
  259. task->d->estimate = attributes().value("estimate").toString();
  260. // Grab Completed/Deleted
  261. task->d->completed = parseDateTime(attributes().value("completed").toString());
  262. task->d->deleted = parseDateTime(attributes().value("deleted").toString());
  263. // TODO:: Grab Postponed
  264. // TODO: Parse rest of fields
  265. //kDebug() << "Adding Task: " << task->id() << " to list " << list->id() << "(" << list << ")";
  266. list->tasks.insert(task->id(), task);
  267. session->d->tasks.insert(task->id(), task);
  268. while (!atEnd()) {
  269. readNext();
  270. if (isEndElement())
  271. break;
  272. if (isStartElement())
  273. { kDebug() << "readTask().readNext(): " << name().toString(); }
  274. }
  275. }
  276. void RTM::TasksReader::readTaskSeries(RTM::ListId listId) {
  277. TempProps props;
  278. props.name = attributes().value("name").toString();
  279. props.seriesId = attributes().value("id").toString().toULong();
  280. props.listId = listId;
  281. while(!atEnd()) {
  282. readNext();
  283. if ((isEndElement()) && (name().toString() == "taskseries")) {
  284. break;
  285. }
  286. if (isEndElement()) {
  287. kDebug() << "Error in readTaskSeries() with end element: " << name().toString();
  288. break;
  289. }
  290. if (isStartElement()) {
  291. if (name().toString() == "tags")
  292. readTags(&props);
  293. else if (name().toString() == "participants")
  294. readParticipants(&props);
  295. else if (name().toString() == "notes")
  296. readNotes(&props);
  297. else if (name().toString() == "task")
  298. readTask(&props);
  299. else
  300. readUnknownElement();
  301. }
  302. }
  303. }
  304. void RTM::TasksReader::readTasksHeader() {
  305. while (!atEnd()) {
  306. readNext();
  307. if (isEndElement()) {
  308. return;
  309. }
  310. if (isStartElement()) {
  311. if (name() == "list")
  312. readTasksList();
  313. else
  314. readUnknownElement();
  315. }
  316. }
  317. }
  318. void RTM::TasksReader::readTasksList() {
  319. RTM::ListId currentListId = attributes().value("id").toString().toULong();
  320. while(!atEnd()) {
  321. readNext();
  322. if ((isEndElement()) && (name() == "list")) {
  323. break;
  324. }
  325. if (isEndElement()) {
  326. //Error in readTasksList() with end element: name()
  327. break;
  328. }
  329. if (isStartElement()) {
  330. if (name() == "taskseries")
  331. readTaskSeries(currentListId);
  332. else
  333. readUnknownElement();
  334. }
  335. }
  336. }