You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kplato/kptresource.h

580 lines
19 KiB

/* This file is part of the KDE project
Copyright (C) 2001 Thomas Zander zander@kde.org
Copyright (C) 2004, 2005 Dag Andersen <danders@get2net.dk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KPTRESOURCE_H
#define KPTRESOURCE_H
#include "kptduration.h"
#include "kptdatetime.h"
#include <qdom.h>
#include <qintdict.h>
#include <qstring.h>
#include <qptrlist.h>
#include <kdebug.h>
class QTime;
namespace KPlato
{
class Risk;
class Effort;
class Appointment;
class Task;
class Node;
class Project;
class Resource;
class ResourceRequest;
class ResourceGroupRequest;
class Calendar;
class ResourceRequestCollection;
class EffortCostMap;
class Schedule;
class ResourceSchedule;
class Schedule;
/**
* This class represents a group of similar resources to be assigned to a task
* e.g. The list of employees, computer resources, etc
*/
/* IDEA; lets create a resourceGroup that has the intelligence to import PIM schedules
* from the kroupware project and use the schedules to use the factory pattern to build
* Resources (probably a derived class) which returns values on getFirstAvailableTime
* and friends based on the schedules we got from the PIM projects.
* (Thomas Zander mrt-2003 by suggestion of Shaheed)
*/
class ResourceGroup {
public:
ResourceGroup(Project *project);
~ResourceGroup();
enum Type { Type_Work, Type_Material };
QString id() const { return m_id; }
bool setId(QString id);
void generateId();
Project *project() { return m_project; }
void setName(QString n) {m_name=n;}
const QString &name() const {return m_name;}
void setType(Type type) { m_type = type; }
//void setType(const QString &type);
Type type() const { return m_type; }
/** Manage the resources in this list
* <p>At some point we will have to look at not mixing types of resources
* (e.g. you can't add a person to a list of computers
*
* <p>Risks must always be associated with a resource, so there is no option
* to manipulate risks (@ref Risk) seperately
*/
void addResource(Resource*, Risk*);
void insertResource( unsigned int index, Resource *resource );
void removeResource( Resource *resource );
Resource *takeResource( Resource *resource );
void removeResource(int);
Resource* getResource(int);
Risk* getRisk(int);
/** Get the "num" resources which is available in the time frame
* defined by "start" and "duration".
* @param start todo
* @param duration todo
* @param num todo
*/
QPtrList<Resource> availableResources(const DateTime start, const Duration duration, int num);
/** Manage the dependent resources. This is a list of the resource
* groups that must have available resources for this resource to
* perform the work
* <p>see also @ref getRequiredResource, @ref getRequiredResource
*/
void addRequiredResource(ResourceGroup*);
/** Manage the dependent resources. This is a list of the resource
* groups that must have available resources for this resource to
* perform the work
* <p>see also @ref addRequiredResource, @ref getRequiredResource
*/
ResourceGroup* getRequiredResource(int);
/** Manage the dependent resources. This is a list of the resource
* groups that must have available resources for this resource to
* perform the work
* <p>see also @ref getRequiredResource, @ref addRequiredResource
*/
void removeRequiredResource(int);
int numResources() const { return m_resources.count(); }
QPtrList<Resource> &resources() { return m_resources; }
bool load(QDomElement &element);
void save(QDomElement &element) const;
void initiateCalculation(Schedule &sch);
void addNode(const Node *node) { m_nodes.append(node); }
void clearNodes() { m_nodes.clear(); }
Calendar *defaultCalendar() { return m_defaultCalendar; }
int units();
void registerRequest(ResourceGroupRequest *request)
{ m_requests.append(request); }
void unregisterRequest(ResourceGroupRequest *request)
{ m_requests.removeRef(request); }
const QPtrList<ResourceGroupRequest> &requests() const
{ return m_requests; }
ResourceGroup *findId() const { return findId(m_id); }
ResourceGroup *findId(const QString &id) const;
bool removeId() { return removeId(m_id); }
bool removeId(const QString &id);
void insertId(const QString &id);
Appointment appointmentIntervals() const;
#ifndef NDEBUG
void printDebug(QString ident);
#endif
private:
Project *m_project;
QString m_id; // unique id
QString m_name;
QPtrList<Resource> m_resources;
QPtrList<Risk> m_risks;
QPtrList<ResourceGroup> m_requires;
QPtrList<Node> m_nodes; //The nodes that want resources from us
Calendar *m_defaultCalendar;
Type m_type;
QPtrList<ResourceGroupRequest> m_requests;
};
/**
* Any resource that is used by a task. A resource can be a worker, or maybe wood.
* If the resources is a worker or a piece of equiment which can be reused but
* can only be used by one node in time, then we can use the scheduling methods of the
* resource to schedule the resource available time for the project.
* The Idea is that all nodes which need this resource point to it and the scheduling
* code (partly implemented here) schedules the actual usage.
* See also @ref ResourceGroup
*/
class Resource {
public:
Resource(Project *project);
Resource(Resource *resource);
virtual ~Resource();
QString id() const { return m_id; }
bool setId(QString id);
void generateId();
enum Type { Type_Work, Type_Material };
void setType(Type type) { m_type = type; }
void setType(const QString &type);
Type type() const { return m_type; }
QString typeToString() const;
void setName(QString n) {m_name=n;}
const QString &name() const {return m_name;}
void setInitials(QString initials) {m_initials=initials;}
const QString &initials() const {return m_initials;}
void setEmail(QString email) {m_email=email;}
const QString &email() const {return m_email;}
void copy(Resource *resource);
/// Set the time from when the resource is available to this project
void setAvailableFrom(const QDateTime &af) {m_availableFrom=af;}
/// Return the time when the resource is available to this project
const DateTime &availableFrom() const {return m_availableFrom;}
/// Set the time when the resource is no longer available to this project
void setAvailableUntil(const QDateTime au) {m_availableUntil=au;}
/// Return the time when the resource is no longer available to this project.
const DateTime &availableUntil() const {return m_availableUntil;}
void addWorkingHour(QTime from, QTime until);
QPtrList<QTime> workingHours() { return m_workingHours; }
DateTime getFirstAvailableTime(DateTime after = DateTime());
DateTime getBestAvailableTime(Duration duration);
DateTime getBestAvailableTime(const DateTime after, const Duration duration);
bool load(QDomElement &element);
void save(QDomElement &element) const;
///Return the list of appointments for current schedule.
QPtrList<Appointment> appointments();
Appointment *findAppointment(Node *node);
/// Adds appointment to current schedule
virtual bool addAppointment(Appointment *appointment);
/// Adds appointment to schedule sch
virtual bool addAppointment(Appointment *appointment, Schedule &main);
/// Adds appointment to both this resource and node
virtual void addAppointment(Schedule *node, DateTime &start, DateTime &end, double load=100);
void initiateCalculation(Schedule &sch);
bool isAvailable(Task *task);
void makeAppointment(Schedule *schedule);
bool isOverbooked() const;
bool isOverbooked(const QDate &date) const;
bool isOverbooked(const DateTime &start, const DateTime &end) const;
double normalRate() const { return cost.normalRate; }
void setNormalRate(double rate) { cost.normalRate = rate; }
double overtimeRate() const { return cost.overtimeRate; }
void setOvertimeRate(double rate) { cost.overtimeRate = rate; }
double fixedCost() const { return cost.fixed; }
void setFixedCost(double value) { cost.fixed = value; }
/**
* Return available units in percent
*/
int units() const { return m_units; }
/**
* Set available units in percent
*/
void setUnits(int units) { m_units = units; }
Project *project() const { return m_project; }
/**
* Get the calendar for this resource.
* If local=false, check if there is a default calendar.
*/
Calendar *calendar(bool local=false) const;
Calendar *calendar(const QString id) const;
void setCalendar(Calendar *calendar) { m_calendar = calendar; }
/**
* Used to clean up requests when the resource is deleted.
*/
void registerRequest(const ResourceRequest *request)
{ m_requests.append(request); }
void unregisterRequest(const ResourceRequest *request)
{ m_requests.removeRef(request); }
const QPtrList<ResourceRequest> &requests() const
{ return m_requests; }
Duration effort(const DateTime &start, const Duration &duration, bool backward, bool *ok=0) const;
/**
* Find the first available time after time, within limit.
* Returns invalid DateTime if not available.
*/
DateTime availableAfter(const DateTime &time, const DateTime limit=DateTime(), bool checkAppointments=false) const;
/**
* Find the first available time before time, within limit.
* Returns invalid DateTime if not available.
*/
DateTime availableBefore(const DateTime &time, const DateTime limit=DateTime(), bool checkAppointments=false) const;
Resource *findId() const { return findId(m_id); }
Resource *findId(const QString &id) const;
bool removeId() { return removeId(m_id); }
bool removeId(const QString &id);
void insertId(const QString &id);
Calendar *findCalendar(const QString &id) const;
Appointment appointmentIntervals() const;
Duration plannedEffort(const QDate &date) const;
void setCurrentSchedule(Schedule *schedule) { m_currentSchedule = schedule; }
void setCurrentSchedule(long id) { m_currentSchedule = findSchedule(id); }
Schedule *currentSchedule() const { return m_currentSchedule; }
QIntDict<Schedule> &schedules() { return m_schedules; }
Schedule *findSchedule(long id) { return m_schedules[id]; }
/// Take, and delete.
void removeSchedule(Schedule *schedule);
/// Take, don't delete.
void takeSchedule(const Schedule *schedule);
void addSchedule(Schedule *schedule);
ResourceSchedule *createSchedule(QString name, int type, long id);
ResourceSchedule *createSchedule(Schedule *parent);
protected:
void makeAppointment(Schedule *node, const DateTime &from, const DateTime &end);
private:
Project *m_project;
QIntDict<Schedule> m_schedules;
QString m_id; // unique id
QString m_name;
QString m_initials;
QString m_email;
DateTime m_availableFrom;
DateTime m_availableUntil;
QPtrList<QTime> m_workingHours;
int m_units; // avalable units in percent
Type m_type;
struct Cost {
double normalRate;
double overtimeRate;
double fixed;
} cost;
Calendar *m_calendar;
QPtrList<ResourceRequest> m_requests;
Schedule *m_currentSchedule;
public:
#ifndef NDEBUG
void printDebug(QString ident);
#endif
};
/**
* Risk is associated with a resource/task pairing to indicate the planner's confidence in the
* estimated effort. Risk can be one of none, low, or high. Some factors that may be taken into
* account for risk are the experience of the person and the reliability of equipment.
*/
class Risk {
public:
enum RiskType {
NONE=0,
LOW=1,
HIGH=2
};
Risk(Node *n, Resource *r, RiskType rt=NONE);
~Risk();
RiskType riskType() { return m_riskType; }
Node *node() { return m_node; }
Resource *resource() { return m_resource; }
private:
Node *m_node;
Resource *m_resource;
RiskType m_riskType;
};
class ResourceRequest {
public:
ResourceRequest(Resource *resource=0, int units = 1);
~ResourceRequest();
ResourceGroupRequest *parent() const { return m_parent; }
void setParent(ResourceGroupRequest *parent) { m_parent = parent; }
Resource *resource() const { return m_resource; }
void setResource(Resource* resource) { m_resource = resource; }
bool load(QDomElement &element, Project &project);
void save(QDomElement &element) const;
/**
* Get amount of requested resource units in percent
*/
int units() const;
/**
* Get amount of requested work units in percent
*/
int workUnits() const;
void registerRequest() { if (m_resource) m_resource->registerRequest(this); }
void unregisterRequest() { if (m_resource) m_resource->unregisterRequest(this); }
void makeAppointment(Schedule *schedule) {
if (m_resource)
m_resource->makeAppointment(schedule);
}
Task *task() const;
private:
Resource *m_resource;
int m_units;
ResourceGroupRequest *m_parent;
#ifndef NDEBUG
public:
void printDebug(QString ident);
#endif
};
class ResourceGroupRequest {
public:
ResourceGroupRequest(ResourceGroup *group=0, int units=0);
~ResourceGroupRequest();
void setParent(ResourceRequestCollection *parent) { m_parent = parent;}
ResourceRequestCollection *parent() const { return m_parent; }
ResourceGroup *group() const { return m_group; }
QPtrList<ResourceRequest> &resourceRequests() { return m_resourceRequests; }
void addResourceRequest(ResourceRequest *request);
void removeResourceRequest(ResourceRequest *request) { m_resourceRequests.removeRef(request); }
ResourceRequest *takeResourceRequest(ResourceRequest *request);
ResourceRequest *find(Resource *resource) const;
bool load(QDomElement &element, Project &project);
void save(QDomElement &element) const;
/**
* Get total amount of resource units in percent
*/
int units() const;
/**
* Get amount of work units in percent
*/
int workUnits() const;
Duration effort(const DateTime &time, const Duration &duration, bool backward, bool *ok=0) const;
int numDays(const DateTime &time, bool backward) const;
/**
* Returns the duration needed to do the effort effort
* starting at start.
*/
Duration duration(const DateTime &start, const Duration &effort, bool backward=false);
DateTime availableAfter(const DateTime &time);
DateTime availableBefore(const DateTime &time);
/**
* Makes appointments for task @param task to the
* requested resources for the duration found in @ref duration().
*/
void makeAppointments(Schedule *schedule);
/**
* Reserves the requested resources for the specified interval
*/
void reserve(const DateTime &start, const Duration &duration);
bool isEmpty() const;
Task *task() const;
private:
ResourceGroup *m_group;
int m_units;
ResourceRequestCollection *m_parent;
QPtrList<ResourceRequest> m_resourceRequests;
DateTime m_start;
Duration m_duration;
#ifndef NDEBUG
public:
void printDebug(QString ident);
#endif
};
class ResourceRequestCollection {
public:
ResourceRequestCollection(Task &task);
~ResourceRequestCollection();
const QPtrList<ResourceGroupRequest> &requests() const { return m_requests; }
void addRequest(ResourceGroupRequest *request) {
m_requests.append(request);
request->setParent(this);
}
void removeRequest(ResourceGroupRequest *request) { m_requests.removeRef(request); }
void takeRequest(ResourceGroupRequest *request) { m_requests.take(m_requests.findRef(request)); }
ResourceGroupRequest *find(ResourceGroup *resource) const;
ResourceRequest *find(Resource *resource) const;
bool isEmpty() const;
//bool load(QDomElement &element, Project &project);
void save(QDomElement &element) const;
void clear() { m_requests.clear(); }
/**
* Returns the total amount of resource units in percent
*/
int units() const;
/**
* Returns the amount of work units in percent
*/
int workUnits() const;
/**
* Returns the duration needed to do the effort @param effort
* starting at @param time.
*/
Duration duration(const DateTime &time, const Duration &effort, bool backward=false);
DateTime availableAfter(const DateTime &time);
DateTime availableBefore(const DateTime &time);
/**
* Makes appointments for the task @param task to the requested resources.
* Assumes that @ref duration() has been run.
*/
void makeAppointments(Schedule *schedule);
/**
* Reserves the requested resources for the specified interval
*/
void reserve(const DateTime &start, const Duration &duration);
Task &task() const { return m_task; }
protected:
struct Interval {
DateTime start;
DateTime end;
Duration effort;
};
private:
Task &m_task;
QPtrList<ResourceGroupRequest> m_requests;
#ifndef NDEBUG
public:
void printDebug(QString ident);
#endif
};
} //KPlato namespace
#endif