00001 #include "taskmanagerdata.h"
00002
00003 #include "dependentdataexception.h"
00004 #include "reservation.h"
00005 #include "user.h"
00006 #include "resource.h"
00007 #include "project.h"
00008 #include "tasktype.h"
00009 #include "usertype.h"
00010 #include "resourcetype.h"
00011 #include "invitation.h"
00012 #include "clock.h"
00013
00014 #include <QList>
00015 #include <QDebug>
00016 #include <tools/invaliddataexception.h>
00017
00018 #include <typeinfo>
00019
00020 namespace domain
00021 {
00022
00023 struct TaskManagerDataPrivate
00024 {
00025 Clock systemClock;
00026 QList<StorableData*> data;
00027 QMap<QString, Type*> types;
00028 AdminUser* admin;
00029
00030 template<typename T>
00031 T* nonConstPointer(const T* pointer)
00032 {
00033 if (pointer == (const T*)admin)
00034 return (T*)admin;
00035
00036 T* ret = const_cast<T*>(pointer);
00037
00038 if (ret == 0 || !data.contains(ret))
00039 return 0;
00040
00041 return ret;
00042 }
00043
00044 template<typename T>
00045 QList<T> dataByType()
00046 {
00047 QList<T> ret;
00048 Q_FOREACH(StorableData* item, data)
00049 {
00050 T casted = qobject_cast<T>(item);
00051 if (casted != 0)
00052 ret << casted;
00053 }
00054
00055 return ret;
00056 }
00057
00058 template<typename T>
00059 QList<T> typeByType()
00060 {
00061 QList<T> ret;
00062 Q_FOREACH(Type* item, types)
00063 {
00064 T casted = qobject_cast<T>(item);
00065 if (casted != 0)
00066 ret << casted;
00067 }
00068
00069 return ret;
00070 }
00071 };
00072
00073 TaskManagerData::TaskManagerData() : d(new TaskManagerDataPrivate())
00074 {
00075 d->admin = new AdminUser();
00076
00077 connect(&d->systemClock, SIGNAL(timeChanged(QDateTime)),
00078 this, SIGNAL(timeChanged(QDateTime)));
00079
00080 connect(this, SIGNAL(tasksChanged()), this, SIGNAL(dataChanged()));
00081 connect(this, SIGNAL(usersChanged()), this, SIGNAL(dataChanged()));
00082 connect(this, SIGNAL(reservationsChanged()), this, SIGNAL(dataChanged()));
00083 connect(this, SIGNAL(resourcesChanged()), this, SIGNAL(dataChanged()));
00084 connect(this, SIGNAL(projectsChanged()), this, SIGNAL(dataChanged()));
00085 connect(this, SIGNAL(invitationsChanged()), this, SIGNAL(dataChanged()));
00086 }
00087
00088 TaskManagerData::~TaskManagerData()
00089 {
00090 clear();
00091 clearTheme();
00092 delete d->admin;
00093 delete d;
00094 }
00095
00096 TaskManagerData* TaskManagerData::instance()
00097 {
00098 static TaskManagerData ret;
00099 return &ret;
00100 }
00101
00102 void TaskManagerData::clear()
00103 {
00104 bool deletedSomething = true;
00105
00106 while (!d->data.isEmpty() && deletedSomething)
00107 {
00108 deletedSomething = false;
00109
00110 Q_FOREACH (StorableData* data, d->data)
00111 {
00112 try
00113 {
00114 removeData(data);
00115 deletedSomething = true;
00116 break;
00117 }
00118 catch (DependentDataException&)
00119 {
00120 continue;
00121 }
00122 catch (tools::StringException& e)
00123 {
00124 qFatal("Caught exception: %s", qPrintable(e.message()));
00125 }
00126 }
00127 }
00128
00129 if (!d->data.isEmpty())
00130 {
00131 qDebug() << "Unable to remove" << d->data;
00132 qFatal("Dependency loop detected.");
00133 }
00134 }
00135
00136 void TaskManagerData::clearTheme()
00137 {
00138 clear();
00139
00140 Q_FOREACH(Type* type, d->types)
00141 {
00142 delete type;
00143 }
00144
00145 d->types.clear();
00146 }
00147
00148 void TaskManagerData::addType(Type* type)
00149 {
00150 QString id = type->id();
00151
00152 if (d->types.contains(id))
00153 {
00154 delete type;
00155 throw tools::InvalidDataException(QString("Multiple types with id %1").arg(id));
00156 }
00157
00158 d->types[id] = type;
00159 }
00160
00161 TaskType* TaskManagerData::createTaskType(QString id, QString name)
00162 {
00163 TaskType* ret = new TaskType(id, name);
00164 addType(ret);
00165 return ret;
00166 }
00167
00168 UserType* TaskManagerData::createUserType(QString id, QString name)
00169 {
00170 UserType* ret = new UserType(id, name);
00171 addType(ret);
00172 return ret;
00173 }
00174
00175 ResourceType* TaskManagerData::createResourceType(QString id, QString name)
00176 {
00177 ResourceType* ret = new ResourceType(id, name);
00178 addType(ret);
00179 return ret;
00180 }
00181
00182 Clock* TaskManagerData::clock() const
00183 {
00184 return &d->systemClock;
00185 }
00186
00187 QList<Task*> TaskManagerData::tasks() const
00188 {
00189 return d->dataByType<Task*>();
00190 }
00191
00192 QList<Task*> TaskManagerData::tasksForUser(const User* user) const
00193 {
00194 QList<Task*> ret;
00195
00196 Q_FOREACH(Task* task, tasks())
00197 {
00198 if (user == task->user())
00199 ret << task;
00200 }
00201
00202 return ret;
00203 }
00204
00205 QList<Reservation*> TaskManagerData::reservations() const
00206 {
00207 return d->dataByType<Reservation*>();
00208 }
00209
00210 QList<User*> TaskManagerData::users() const
00211 {
00212 return d->dataByType<User*>();
00213 }
00214
00215 QList<User*> TaskManagerData::allUsers() const
00216 {
00217 return users() << adminUser();
00218 }
00219
00220 User* TaskManagerData::adminUser() const
00221 {
00222 return d->admin;
00223 }
00224
00225 QList<Invitation*> TaskManagerData::invitations() const
00226 {
00227 return d->dataByType<Invitation*>();
00228 }
00229
00230 QList<Resource*> TaskManagerData::resources() const
00231 {
00232 return d->dataByType<Resource*>();
00233 }
00234
00235 QList<Project*> TaskManagerData::projects() const
00236 {
00237 return d->dataByType<Project*>();
00238 }
00239
00240 Task* TaskManagerData::task(const Task* task) const
00241 {
00242 return d->nonConstPointer(task);
00243 }
00244
00245 Resource* TaskManagerData::resource(const Resource* resource)
00246 {
00247 return d->nonConstPointer(resource);
00248 }
00249
00250 Project* TaskManagerData::project(const Project* project)
00251 {
00252 return d->nonConstPointer(project);
00253 }
00254
00255 User* TaskManagerData::user(const User* user)
00256 {
00257 if (user == d->admin)
00258 return d->admin;
00259
00260 return d->nonConstPointer(user);
00261 }
00262
00263 Invitation* TaskManagerData::invitation(const Invitation* invitation)
00264 {
00265 return d->nonConstPointer(invitation);
00266 }
00267
00268 Task* TaskManagerData::createTask(TaskType* type, const User* user,
00269 const Schedule& schedule,
00270 TaskState::SettableState state,
00271 const QList<Task*>& subTasks,
00272 const QList<InvitationData>& invitations,
00273 const QList<ReservationData>& reservations)
00274 {
00275 if (!d->types.values().contains(type))
00276 throw tools::InvalidDataException("Type not valid");
00277
00278 Task* task = new Task(type, d->nonConstPointer(user), schedule, state,
00279 subTasks, invitations, reservations);
00280 connect(task, SIGNAL(dataChanged()), this, SIGNAL(tasksChanged()));
00281 d->data << task;
00282 emit tasksChanged();
00283 return task;
00284 }
00285
00286 Project* TaskManagerData::createProject(const QString& description)
00287 {
00288 Project* project = new Project(description);
00289 connect(project, SIGNAL(dataChanged()), this, SIGNAL(projectsChanged()));
00290 d->data << project;
00291 emit projectsChanged();
00292 return project;
00293 }
00294
00295 Invitation* TaskManagerData::createInvitation(const domain::Task* task,
00296 const domain::User* user)
00297 {
00298 Invitation* invitation = new Invitation(d->nonConstPointer(task),
00299 d->nonConstPointer(user));
00300 connect(invitation, SIGNAL(dataChanged()), this, SIGNAL(invitationsChanged()));
00301 d->data << invitation;
00302 emit invitationsChanged();
00303 return invitation;
00304 }
00305
00306 Invitation* TaskManagerData::_createInvitation(Task* task, User* user)
00307 {
00308 Invitation* invitation = new Invitation(task, user);
00309 connect(invitation, SIGNAL(dataChanged()), this, SIGNAL(invitationsChanged()));
00310 d->data << invitation;
00311 emit invitationsChanged();
00312 return invitation;
00313 }
00314
00315 Resource* TaskManagerData::createResource(const QString& description,
00316 ResourceType* type)
00317 {
00318 if (!d->types.values().contains(type))
00319 throw tools::InvalidDataException("Type not valid");
00320
00321 Resource* resource = new Resource(type, description);
00322 connect(resource, SIGNAL(dataChanged()), this, SIGNAL(resourcesChanged()));
00323 d->data << resource;
00324 emit resourcesChanged();
00325 return resource;
00326 }
00327
00328 Reservation* TaskManagerData::createReservation(
00329 const Task* task, const Resource* resource,
00330 const QDateTime& time, const Duration& duration)
00331 {
00332 Reservation* reservation = new Reservation(d->nonConstPointer(task),
00333 d->nonConstPointer(resource),
00334 time, duration);
00335
00336 connect(reservation, SIGNAL(dataChanged()),
00337 this, SIGNAL(reservationsChanged()));
00338
00339 d->data << reservation;
00340 emit reservationsChanged();
00341 return reservation;
00342 }
00343
00344 Reservation* TaskManagerData::_createReservation(Task* task, Resource* resource,
00345 const QDateTime& time,
00346 const domain::Duration& duration)
00347 {
00348 Reservation* reservation = new Reservation(task, resource, time, duration);
00349
00350 connect(reservation, SIGNAL(dataChanged()),
00351 this, SIGNAL(reservationsChanged()));
00352
00353 d->data << reservation;
00354 emit reservationsChanged();
00355 return reservation;
00356 }
00357
00358 User* TaskManagerData::createUser(UserType* type, const QString& name)
00359 {
00360 if (!d->types.values().contains(type))
00361 throw tools::InvalidDataException("Type not valid");
00362
00363 Q_FOREACH(User* user, users())
00364 {
00365 if (user->name() == name)
00366 throw tools::InvalidDataException("There already is a user with the given name");
00367 }
00368
00369 User* user = new User(type, name);
00370 connect(user, SIGNAL(dataChanged()), this, SIGNAL(usersChanged()));
00371 d->data << user;
00372 emit usersChanged();
00373 return user;
00374 }
00375
00376 void TaskManagerData::removeData(const domain::StorableData* constData)
00377 {
00378 static QList<const StorableData*> dataToRemove;
00379
00380 domain::StorableData* data = d->nonConstPointer(constData);
00381
00382 if (data == 0)
00383 return;
00384
00385 if (dataToRemove.contains(data))
00386 {
00387 qDebug() << "Unable to remove" << dataToRemove;
00388 qFatal("Dependency loop detected.");
00389 }
00390
00391 dataToRemove << data;
00392
00393 Q_FOREACH (StorableData* data, data->dependentData())
00394 removeData(data);
00395
00396 try
00397 {
00398 delete data;
00399 }
00400 catch (tools::StringException& e)
00401 {
00402 qFatal("Caught exception: %s", qPrintable(e.message()));
00403 }
00404
00405 d->data.removeAll(data);
00406 dataToRemove.removeAll(data);
00407 }
00408
00409 QList<ResourceType*> TaskManagerData::resourceTypes() const
00410 {
00411 return d->typeByType<ResourceType*>();
00412 }
00413
00414 QList<TaskType*> TaskManagerData::taskTypes() const
00415 {
00416 return d->typeByType<TaskType*>();
00417 }
00418
00419 QList<UserType*> TaskManagerData::userTypes() const
00420 {
00421 return d->typeByType<UserType*>();
00422 }
00423
00424 Type* TaskManagerData::typeById(const QString& id) const
00425 {
00426 if (d->types.contains(id))
00427 return d->types[id];
00428
00429 return 0;
00430 }
00431
00432 bool TaskManagerData::hasData() const
00433 {
00434 return !d->data.isEmpty();
00435 }
00436
00437 bool TaskManagerData::hasTheme() const
00438 {
00439 return !d->types.isEmpty();
00440 }
00441
00442 }