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 }