00001 #include "dataloader.h"
00002
00003 #include <controllerfactory.h>
00004
00005 #include <domain/taskmanagerdata.h>
00006 #include <domain/resource.h>
00007 #include <domain/duration.h>
00008 #include <domain/task.h>
00009 #include <domain/taskstates.h>
00010 #include <domain/resourcetype.h>
00011 #include <domain/tasktype.h>
00012 #include <domain/usertype.h>
00013 #include <domain/clock.h>
00014 #include <domain/project.h>
00015 #include <domain/user.h>
00016
00017 #include <tools/stringexception.h>
00018
00019 #include <QDomDocument>
00020 #include <QFile>
00021 #include <QDateTime>
00022
00023 using namespace control;
00024
00025 QString DataLoader::description() const
00026 {
00027 return "Load data";
00028 }
00029
00030 QString DataLoader::name() const
00031 {
00032 return "DataLoader";
00033 }
00034
00035 ControllerInterface::DataType DataLoader::dataType() const
00036 {
00037 return FileData;
00038 }
00039
00040 ControllerInterface::ActionType DataLoader::actionType() const
00041 {
00042 return LoadDataAction;
00043 }
00044
00045 void DataLoader::init(domain::TaskManagerData* data, ui::UiInterface* ui,
00046 ControllerFactory* factory)
00047 {
00048 control::ControllerInterface::init(data, ui, factory);
00049
00050 themeLoader = factory->controllerByType(FileData, LoadThemeAction);
00051
00052 if (themeLoader == 0)
00053 throw tools::StringException("No controller to load a theme");
00054 }
00055
00056 bool DataLoader::userIsValid() const
00057 {
00058 return true;
00059 }
00060
00061 void DataLoader::execute()
00062 {
00063 if (!data->hasTheme())
00064 {
00065 ui->showMessage("You have to load a theme first");
00066 themeLoader->run();
00067
00068 if (!data->hasTheme())
00069 return;
00070 }
00071
00072 QString fileName = ui->getOpenFileName("", "XML files(*.xml)");
00073 if (fileName.isEmpty())
00074 return;
00075
00076 data->clear();
00077 resourceRefs.clear();
00078 projectRefs.clear();
00079 taskRefs.clear();
00080 userRefs.clear();
00081 taskInvitees.clear();
00082 userInvitees.clear();
00083
00084 QDomDocument doc;
00085 QFile file(fileName);
00086
00087 if(!file.open(QIODevice::ReadOnly))
00088 {
00089 ui->showError("Could not open the specified file.");
00090 return;
00091 }
00092
00093 QString errorString;
00094 int errorLine, errorColumn;
00095
00096 if (!doc.setContent(&file, &errorString, &errorLine, &errorColumn))
00097 {
00098 file.close();
00099 QString error("The file could not be loaded\nLine %1, Column %2: %3");
00100 ui->showError(error.arg(errorLine).arg(errorColumn).arg(errorString));
00101 return;
00102 }
00103
00104 file.close();
00105
00106 QDomElement root = doc.documentElement();
00107 if (root.tagName() != "mop:taskplanner")
00108 {
00109 ui->showError("This is not a correct XML file.");
00110 return;
00111 }
00112
00113 bool succes = false;
00114
00115 try
00116 {
00117 succes = load(root);
00118 }
00119 catch (tools::StringException e)
00120 {
00121 ui->showError(e.message());
00122 data->clear();
00123 return;
00124 }
00125
00126 if (succes)
00127 ui->showMessage("The file was loaded succesfully.");
00128 else
00129 {
00130 ui->showError("The file has incorrect contents");
00131 data->clear();
00132 }
00133 }
00134
00135 #define FOREACH_ELEMENT(element,node) \
00136 for (QDomElement element = node.firstChildElement(); !element.isNull(); \
00137 element = element.nextSiblingElement())
00138
00139 bool DataLoader::load(const QDomElement& root)
00140 {
00141 projectRefs.clear();
00142 resourceRefs.clear();
00143 taskRefs.clear();
00144
00145
00146 QDomElement systemTime = root.firstChildElement("mop:systemtime");
00147 data->clock()->setTime(QDateTime::fromString(systemTime.text(), Qt::ISODate));
00148
00149 FOREACH_ELEMENT(element,root)
00150 {
00151 if (element.tagName() == "mop:projects")
00152 {
00153 if (!loadProjects(element))
00154 return false;
00155 }
00156 else if (element.tagName() == "mop:resources")
00157 {
00158 if (!loadResources(element))
00159 return false;
00160 }
00161 else if (element.tagName() == "mop:user")
00162 {
00163 if (!loadUser(element))
00164 return false;
00165 }
00166 else if (element.tagName() == "mop:systemtime")
00167 {
00168
00169 }
00170 else
00171 {
00172 throw tools::StringException(QString("illegal tag: %1")
00173 .arg(element.tagName()));
00174 }
00175 }
00176
00177 return loadInvitations() && createTasks();
00178 }
00179
00180 bool DataLoader::loadProjects (const QDomElement& projects)
00181 {
00182 FOREACH_ELEMENT(element, projects)
00183 {
00184 if (element.tagName() == "mop:project")
00185 {
00186 if (!loadProject(element))
00187 return false;
00188 }
00189 else
00190 return false;
00191 }
00192
00193 return true;
00194 }
00195
00196 bool DataLoader::loadProject (const QDomElement& project)
00197 {
00198 QString projectRef = project.attribute("id");
00199 FOREACH_ELEMENT(element, project)
00200 {
00201 if (element.tagName() == "mop:description")
00202 projectRefs.insert(projectRef,data->createProject(element.text()));
00203 else
00204 throw tools::StringException("There is an error in the project tag: " + projectRef);
00205 }
00206
00207 return true;
00208 }
00209
00210 bool DataLoader::loadResources (const QDomElement& resources)
00211 {
00212 FOREACH_ELEMENT(element, resources)
00213 {
00214 if (element.tagName() == "mop:resource")
00215 {
00216 if (!loadResource(element))
00217 return false;
00218 }
00219 else
00220 return false;
00221 }
00222
00223 return true;
00224 }
00225
00226 bool DataLoader::loadResource (const QDomElement& resource)
00227 {
00228 QString description;
00229 domain::ResourceType* resourceType;
00230
00231 QString resourceRef = resource.attribute("id");
00232
00233 FOREACH_ELEMENT(element, resource)
00234 {
00235 if (element.tagName() == "mop:type")
00236 {
00237 domain::Type* type = data->typeById(element.text());
00238
00239 if (type == 0)
00240 {
00241 throw tools::StringException(QString("Type with id %1 does not exist")
00242 .arg(element.text()));
00243 }
00244
00245 resourceType = qobject_cast<domain::ResourceType*>(type);
00246
00247 if (resourceType == 0)
00248 {
00249 throw tools::StringException(QString("Type with id %1 is not a resource type")
00250 .arg(element.text()));
00251 }
00252 }
00253 else if (element.tagName() == "mop:description")
00254 {
00255 description = element.text();
00256 }
00257 else
00258 throw tools::StringException(QString("Unknown tag %1").arg(element.tagName()));
00259 }
00260
00261 resourceRefs.insert(resourceRef,data->createResource(description, resourceType));
00262
00263 return true;
00264 }
00265
00266 bool DataLoader::loadUser (const QDomElement& user)
00267 {
00268 QDomElement name = user.firstChildElement("mop:name");
00269 domain::User* userPointer;
00270
00271 QString typeId = user.firstChildElement("mop:type").text();
00272 domain::Type* type = data->typeById(typeId);
00273
00274 if (type == 0)
00275 throw tools::StringException(QString("No type with id %1").arg(typeId));
00276
00277 domain::UserType* userType = qobject_cast<domain::UserType*>(type);
00278
00279 if (userType == 0)
00280 {
00281 throw tools::StringException(QString("Type with id %1 is not a user type")
00282 .arg(typeId));
00283 }
00284
00285 if (!name.isNull())
00286 userPointer = data->createUser(userType, name.text());
00287 else
00288 throw tools::StringException("The name of a user is empty");
00289
00290 userRefs[user.attribute("id")] = userPointer;
00291
00292 QDomElement tasks = user.firstChildElement("mop:tasks");
00293 if (!loadTasks(tasks, userPointer))
00294 return false;
00295
00296 QDomElement invitations = user.firstChildElement("mop:invitations");
00297 QMap<QString, QString> taskInvitationStateMap;
00298 FOREACH_ELEMENT (invitation, invitations)
00299 {
00300 QString task = invitation.attribute("task");
00301 QString status = invitation.attribute("status");
00302 taskInvitationStateMap[task] = status;
00303 }
00304
00305 userInvitees.insert(userPointer, taskInvitationStateMap);
00306
00307 return true;
00308 }
00309
00310 bool DataLoader::loadReservations(const QDomElement& reservations,
00311 const QString& taskRef)
00312 {
00313 FOREACH_ELEMENT(element, reservations)
00314 {
00315 if (element.tagName() == "mop:reservation")
00316 {
00317 if (!loadReservation(element, taskRef))
00318 return false;
00319 }
00320 else
00321 return false;
00322 }
00323
00324 return true;
00325 }
00326
00327 bool DataLoader::loadReservation(const QDomElement& reservation,
00328 const QString& taskRef)
00329 {
00330 domain::Resource* resource;
00331 domain::Duration duration;
00332 QDateTime startDate;
00333 FOREACH_ELEMENT(element, reservation)
00334 {
00335 if (element.tagName() == "mop:time")
00336 {
00337 startDate = QDateTime::fromString(element.text(), Qt::ISODate);
00338 }
00339 else if (element.tagName() == "mop:duration")
00340 {
00341 duration = domain::Duration(element.text().toInt() * 60);
00342 }
00343 else if (element.tagName() == "mop:refResource")
00344 {
00345 resource = resourceRefs.value(element.text());
00346 }
00347 else
00348 throw tools::StringException(QString("Unknown tag %1")
00349 .arg(element.tagName()));
00350 }
00351
00352 domain::ReservationData reservationData;
00353 reservationData.duration = duration;
00354 reservationData.resource = resource;
00355 reservationData.startDate = startDate;
00356 taskData[taskRef].reservations << reservationData;
00357
00358 return true;
00359 }
00360
00361 bool DataLoader::loadTasks(const QDomElement& tasks, domain::User* userPointer)
00362 {
00363 QList<QDomElement> tasksList;
00364 QDomNodeList nodeList = tasks.elementsByTagName("mop:task");
00365
00366 for (int i = 0; i < nodeList.size(); i++)
00367 tasksList << nodeList.at(i).toElement();
00368
00369 bool createdOne = true;
00370
00371 while (createdOne && !tasksList.isEmpty())
00372 {
00373 createdOne = false;
00374
00375 Q_FOREACH (QDomElement task, tasksList)
00376 {
00377 if (loadTask(task, userPointer))
00378 {
00379 createdOne = true;
00380 tasksList.removeAll(task);
00381 }
00382 }
00383 }
00384
00385 if (!tasksList.isEmpty())
00386 {
00387 ui->showError("Error loading tasks");
00388 return false;
00389 }
00390
00391 return true;
00392 }
00393
00394 bool DataLoader::loadTask(const QDomElement& task, domain::User* userPointer)
00395 {
00396 QString taskRef = task.attribute("id");
00397 QDateTime startDate;
00398 QDateTime dueDate;
00399 QDomElement reservationsElement;
00400 QMap<QString,QVariant> fieldsmap;
00401 QStringList invitees;
00402 domain::Duration duration;
00403 domain::TaskState::SettableState state;
00404 domain::Project* project;
00405 domain::TaskType* type;
00406 QStringList subTasks;
00407
00408 FOREACH_ELEMENT(element, task)
00409 {
00410 if (element.tagName() == "mop:startDate")
00411 {
00412 startDate = QDateTime::fromString(element.text(), Qt::ISODate);
00413 }
00414 else if (element.tagName() == "mop:endDate")
00415 {
00416 dueDate = QDateTime::fromString(element.text(), Qt::ISODate);
00417 }
00418 else if (element.tagName() == "mop:duration")
00419 {
00420 duration = domain::Duration(element.text().toInt() * 60);
00421 }
00422 else if (element.tagName() == "mop:status")
00423 {
00424 if (element.text() == "Successful")
00425 state = domain::TaskState::Successful;
00426 else if (element.text() == "Unfinished")
00427 state = domain::TaskState::Unfinished;
00428 else if (element.text() == "Failed")
00429 state = domain::TaskState::Failed;
00430 else
00431 return false;
00432 }
00433 else if (element.tagName() == "mop:refProject")
00434 {
00435 project = projectRefs.value(element.text());
00436 }
00437 else if (element.tagName() == "mop:dependsOn")
00438 {
00439 FOREACH_ELEMENT (subTask, element)
00440 {
00441 Q_ASSERT(subTask.tagName() == "mop:refTask");
00442
00443 subTasks << subTask.text();
00444 }
00445 }
00446 else if (element.tagName() == "mop:type")
00447 {
00448 domain::Type* typePtr = data->typeById(element.text());
00449 type = qobject_cast<domain::TaskType*>(typePtr);
00450
00451 if (type == 0)
00452 {
00453 throw tools::StringException(QString("Type with id %1 is not a task type")
00454 .arg(typePtr->id()));
00455 }
00456 }
00457 else if (element.tagName() == "mop:fields")
00458 {
00459 FOREACH_ELEMENT(field, element)
00460 {
00461 QString id = field.attribute("id");
00462 QVariant value = field.attribute("value");
00463 fieldsmap[id] = value;
00464 }
00465 }
00466 else if (element.tagName() == "mop:invitees")
00467 {
00468 FOREACH_ELEMENT (refUser, element)
00469 invitees << refUser.text();
00470 }
00471 else if (element.tagName() == "mop:reservations")
00472 {
00473 reservationsElement = element;
00474 }
00475 else
00476 throw tools::StringException(QString("Unknown tag: %1").arg(element.tagName()));
00477 }
00478
00479 TaskData taskData;
00480 taskData.type = type;
00481 taskData.schedule = domain::Schedule(duration, startDate, dueDate);
00482 taskData.user = userPointer;
00483 taskData.state = state;
00484 taskData.subTasks = subTasks;
00485 taskData.project = project;
00486 taskData.fieldsMap = fieldsmap;
00487 this->taskData.insert(taskRef, taskData);
00488
00489 Q_FOREACH (QString invitee, invitees)
00490 taskInvitees.insert(taskRef, invitee);
00491
00492 loadReservations(reservationsElement, taskRef);
00493
00494 return true;
00495 }
00496
00497 bool DataLoader::loadInvitations()
00498 {
00499 QStringList tasksDone;
00500
00501 Q_FOREACH (QString task, taskInvitees.keys())
00502 {
00503 if (tasksDone.contains(task))
00504 continue;
00505
00506 tasksDone << task;
00507
00508 Q_FOREACH (QString userRef, taskInvitees.values(task))
00509 {
00510 domain::User* user = userRefs[userRef];
00511
00512 typedef QMap<QString, QString> TaskInvitationStateMap;
00513 Q_FOREACH (TaskInvitationStateMap taskInvitationStateMap,
00514 userInvitees.values(user))
00515 {
00516 Q_FOREACH (QString taskRef, taskInvitationStateMap.keys())
00517 {
00518 if (taskRef == task)
00519 {
00520 domain::InvitationData invitation;
00521 invitation.user = user;
00522 QString status = taskInvitationStateMap[taskRef];
00523
00524 if (status == "pending")
00525 invitation.state = domain::Invitation::Pending;
00526 else if (status == "accepted")
00527 invitation.state = domain::Invitation::Accepted;
00528 else if (status == "declined")
00529 invitation.state = domain::Invitation::Declined;
00530
00531 taskData[taskRef].invitations << invitation;
00532 }
00533 }
00534 }
00535 }
00536 }
00537
00538 return true;
00539 }
00540
00541 bool DataLoader::createTasks()
00542 {
00543 QStringList doneTasks;
00544 bool createdOne = true;
00545 while (createdOne)
00546 {
00547 createdOne = false;
00548
00549 Q_FOREACH(QString taskRef, taskData.keys())
00550 {
00551 TaskData dataTask = taskData[taskRef];
00552 bool allSubTasksCreated = true;
00553 Q_FOREACH(QString subTaskRef, dataTask.subTasks)
00554 {
00555 if (!taskRefs.contains(subTaskRef))
00556 {
00557 allSubTasksCreated = false;
00558 break;
00559 }
00560 }
00561 if (allSubTasksCreated && !doneTasks.contains(taskRef))
00562 {
00563 QList<domain::Task*> subTasks;
00564 Q_FOREACH(QString subTaskRef, dataTask.subTasks)
00565 {
00566 subTasks << taskRefs[subTaskRef];
00567 }
00568 domain::Task* task = data->createTask(dataTask.type, dataTask.user,
00569 dataTask.schedule,
00570 dataTask.state, subTasks,
00571 dataTask.invitations,
00572 dataTask.reservations);
00573 Q_FOREACH(QString fieldID, dataTask.fieldsMap.keys())
00574 {
00575 task->setField(fieldID, dataTask.fieldsMap[fieldID]);
00576 }
00577
00578 task->setProject(dataTask.project);
00579 createdOne = true;
00580 doneTasks << taskRef;
00581 taskRefs[taskRef] = task;
00582 }
00583 }
00584 }
00585 return taskRefs.size() == taskData.keys().size();
00586 }
00587
00588 Q_EXPORT_PLUGIN2(controller_dataloader, DataLoader)
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614