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