/colonydatamerger.cpp

https://github.com/samcrow/ColonyDataMerger · C++ · 327 lines · 228 code · 75 blank · 24 comment · 41 complexity · d2d12c554eafdd72dcae6f6667a60560 MD5 · raw file

  1. #include "colonydatamerger.hpp"
  2. #include "ui_colonydatamerger.h"
  3. ColonyDataMerger::ColonyDataMerger(QWidget *parent) :
  4. QMainWindow(parent),
  5. ui(new Ui::ColonyDataMerger)
  6. {
  7. ui->setupUi(this);
  8. qInstallMsgHandler(&handleConsoleMessage);
  9. //Fix warning about handleConsoleMessage defined but not used
  10. handleConsoleMessage(QtDebugMsg, "Starting up");
  11. LIBMTP_Init();
  12. qDebug() << "It works!";
  13. }
  14. void ColonyDataMerger::showConsoleDialog() {
  15. if(!activeDialog) {
  16. activeDialog = new ConsoleDialog(this);
  17. }
  18. activeDialog->show();
  19. activeDialog->raise();
  20. activeDialog->activateWindow();
  21. }
  22. QList<Colony *> *ColonyDataMerger::mergeColonyLists(QList<Colony *> *list1, QList<Colony *> *list2) {
  23. //TODO sometime: Find a better algorithm. This one is not very scalable (probably O(n^2))
  24. QList<Colony *> *finalList = new QList<Colony *>();
  25. //Add every colony from both lists to the final list
  26. for(int i = 0, max = list1->length(); i < max; i++) {
  27. finalList->append(list1->at(i));
  28. }
  29. for(int i = 0, max = list2->length(); i < max; i++) {
  30. finalList->append(list2->at(i));
  31. }
  32. //Go through the list and remove duplicates
  33. for(int i = 0, max = finalList->length(); i < max; i++) {
  34. Colony *flColony = finalList->at(i);
  35. int flId = flColony->getID();
  36. //Try to find other colonies in the list with this ID
  37. for(int j = 0, jmax = finalList->length(); j < jmax; j++) {
  38. Colony *innerFlColony = finalList->at(i);
  39. //If another colony was found with the same ID
  40. // (that is not the same colony object as this one
  41. if(innerFlColony->getID() == flId && innerFlColony != flColony) {
  42. //We have two colony pointers, same ID, one of them is better
  43. Colony *chosenColony = chooseColony(flColony, innerFlColony);
  44. //chosenColony is either flColony or innerFlColony
  45. //Remove from the final list the one that was not chosen
  46. if(chosenColony == flColony) {
  47. finalList->removeOne(innerFlColony);
  48. }
  49. else {
  50. //chosenColony == innerFlColony
  51. finalList->removeOne(flColony);
  52. }
  53. }
  54. }
  55. }
  56. return finalList;
  57. }
  58. Colony *ColonyDataMerger::chooseColony(Colony *colony1, Colony *colony2) {
  59. QDateTime date1 = colony1->getModifiedDate();
  60. QDateTime date2 = colony2->getModifiedDate();
  61. //Case 0: both are valid
  62. if(date1.isValid() && date2.isValid()) {
  63. //Colony 1 updated after colony 2
  64. if(date1 > date2) {
  65. return colony1;
  66. }
  67. //Colony 1 updated before colony 2
  68. else if(date1 < date2) {
  69. return colony2;
  70. }
  71. //Same date/time, arbitrarily return colony 1
  72. else {
  73. return colony1;
  74. }
  75. }
  76. //Case 1: One date is valid; return the colony with the valid date
  77. else if(date1.isValid() && !date2.isValid()) {
  78. return colony1;
  79. }
  80. else if(date2.isValid() && !date1.isValid()) {
  81. return colony2;
  82. }
  83. //Case 2: neither is valid
  84. return colony1;
  85. }
  86. ColonyDataMerger::~ColonyDataMerger()
  87. {
  88. delete ui;
  89. }
  90. void ColonyDataMerger::on_uploadButton_clicked()
  91. {
  92. showConsoleDialog();
  93. //Disable the upload button so it can't be clicked again this time the application is run
  94. ui->uploadButton->setEnabled(false);
  95. //Upload the file
  96. QList<MobileDevice *> *devices = MobileDevice::getDevices();
  97. if(!devices) {
  98. qWarning() << "NULL mobile device set! Exiting.";
  99. return;
  100. }
  101. qDebug() << "Connected to" << devices->count() << "device(s).";
  102. QString fileName = QFileDialog::getOpenFileName(activeDialog, "Choose a CSV file to upload", QDir::homePath(), "CSV files (*.csv)");
  103. qDebug() << "CSV file:" << fileName;
  104. if(fileName.isEmpty()) {
  105. qWarning() << "No CSV file selected. Exiting.";
  106. return;
  107. }
  108. foreach(MobileDevice *device, *devices) {
  109. QFile csv(fileName);
  110. csv.open(QIODevice::ReadOnly | QIODevice::Text);
  111. if(!csv.isOpen()) {
  112. qWarning() << "Could not open CSV file. Exiting.";
  113. return;
  114. }
  115. qDebug() << "Uploading to a device...";
  116. device->uploadCSV(&csv);
  117. if(csv.isOpen()) {
  118. csv.close();
  119. }
  120. }
  121. //Clean up
  122. foreach(MobileDevice *device, *devices) {
  123. delete device;
  124. }
  125. delete devices;
  126. qDebug() << "Operation successfully completed.";
  127. }
  128. void ColonyDataMerger::on_downloadButton_clicked()
  129. {
  130. showConsoleDialog();
  131. ui->downloadButton->setEnabled(false);
  132. QList<MobileDevice *> *devices = MobileDevice::getDevices();
  133. if(!devices) {
  134. qWarning() << "NULL mobile device set! Exiting.";
  135. return;
  136. }
  137. qDebug() << "Connected to" << devices->count() << "device(s).";
  138. foreach(MobileDevice *device, *devices) {
  139. QString jsonText = device->getJsonText();
  140. QString fileName = QFileDialog::getSaveFileName(this, "Choose where to save this JSON file", QDir::homePath(), "JSON files (*.json)");
  141. if(fileName.isEmpty()) {
  142. qDebug() << "Emtpy file name. Exiting.";
  143. return;
  144. }
  145. QFile file(fileName);
  146. file.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text);
  147. if(!file.isOpen()) {
  148. qDebug() << "File opening failed. Exiting.";
  149. return;
  150. }
  151. if(!file.isWritable()) {
  152. qDebug() << "File is not writable. Exiting.";
  153. }
  154. file.write(jsonText.toUtf8());
  155. file.close();
  156. qDebug() << "Done writing file" << file.fileName();
  157. }
  158. //Clean up
  159. foreach(MobileDevice *device, *devices) {
  160. delete device;
  161. }
  162. delete devices;
  163. qDebug() << "Operation successfully completed.";
  164. }
  165. void ColonyDataMerger::on_mergeButton_clicked()
  166. {
  167. showConsoleDialog();
  168. QStringList fileNames = QFileDialog::getOpenFileNames(this, "Choose JSON files to merge & export", QDir::homePath(), "JSON files (*.json)");
  169. QList<QList<Colony *> *> colonyLists;
  170. foreach(QString fileName, fileNames) {
  171. qDebug() << "Opening" << fileName;
  172. QFile file(fileName);
  173. file.open(QIODevice::ReadOnly | QIODevice::Text);
  174. if(!file.isOpen()) {
  175. qDebug() << "File opening failed. Exiting.";
  176. return;
  177. }
  178. QList<Colony *> *thisFileList = jsonToColonyList(parseJson(QString(file.readAll())));
  179. colonyLists.append(thisFileList);
  180. }
  181. QList<Colony *> *workingList = new QList<Colony *>();
  182. qDebug() << "Merging colony lists...";
  183. for(int i = 0, max = colonyLists.length(); i < max; i++ ) {
  184. QList<Colony *> *list = colonyLists[i];
  185. workingList = mergeColonyLists(list, workingList);
  186. }
  187. qDebug() << "Merging done.";
  188. //Convert it to CSV
  189. QString csvText = toCSV(workingList);
  190. QString csvPath = QFileDialog::getSaveFileName(this, "Choose where to export the CSV file", QDir::homePath(), "CSV files (*.csv)");
  191. if(!csvPath.isEmpty()) {
  192. QFile csv(csvPath);
  193. csv.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text);
  194. csv.write(csvText.toUtf8());
  195. csv.close();
  196. qDebug() << "Done writing CSV file.";
  197. }
  198. //Clean up
  199. delete workingList;
  200. QListIterator<QList<Colony *> *> listsIterator(colonyLists);
  201. while(listsIterator.hasNext()) {
  202. QList<Colony *> *list = listsIterator.next();
  203. QListIterator<Colony *> colonyIterator(*list);
  204. while(colonyIterator.hasNext()) {
  205. delete colonyIterator.next();
  206. }
  207. delete list;
  208. }
  209. qDebug() << "Operation successfully completed.";
  210. }
  211. QList<Colony *> *ColonyDataMerger::jsonToColonyList(QVariantMap json) {
  212. QVariantList jsonColonies = json.value("colonies").toList();
  213. QList<Colony *> *colonies = new QList<Colony *>();
  214. for(int i = 0, max = jsonColonies.length(); i < max; i++) {
  215. QVariant jsonColony = jsonColonies.at(i);
  216. QVariantMap colonyMap = jsonColony.toMap();
  217. Colony *colony = new Colony();
  218. colony->fromVariant(colonyMap);
  219. //Ensure that the colony's marked as visited if it is active
  220. if(colony->isActive()) {
  221. colony->setVisited(true);
  222. }
  223. colonies->append(colony);
  224. }
  225. qDebug() << "Got" << colonies->length() << "colonies.";
  226. return colonies;
  227. }
  228. QVariantMap ColonyDataMerger::parseJson(QString jsonText) {
  229. QJson::Parser parser;
  230. QVariant variant = parser.parse(jsonText.toUtf8());
  231. return variant.toMap();
  232. }
  233. QString ColonyDataMerger::toCSV(QList<Colony *> *list) {
  234. QString csv;
  235. csv += "col,E,N,active,visted,\n";
  236. for(int i = 0, max = list->size(); i < max; i++) {
  237. Colony *colony = list->at(i);
  238. if(colony->isVisited()) {
  239. csv += QString::number(colony->getID());
  240. csv += ",";
  241. csv += QString::number(colony->getX());
  242. csv += ",";
  243. csv += QString::number(colony->getY());
  244. csv += ",";
  245. csv += colony->isActive() ? "A" : "NA";
  246. csv += ",";
  247. csv += colony->isVisited() ? "true" : "false";
  248. csv += ",\n";
  249. }
  250. }
  251. return csv;
  252. }