colors["taskLoadCol"] = QColor("#FD13C6");
colors["otherLoadCol"] = QColor("#FF8D13");
colors["freeLoadCol"] = QColor("#00AC00");
+ colors["overLimitCol"] = QColor("#505050");
colors["loadFrameCol"] = Qt::black;
colors["hightlightCol"] = Qt::white;
colors["errorCol"] = Qt::red;
legendLabels.append(i18n("Completed Task"));
legendLabels.append(i18n("Task Work Load"));
legendLabels.append(i18n("Other Work Load"));
+ legendLabels.append(i18n("Over Resource Usage Limits"));
legendLabels.append(i18n("Free Load"));
maxLegendLabelWidth = 0;
symbolWidth, legendLabelHeight,
"otherLoadCol", Qt::Dense4Pattern, legend);
break;
- case 7: // Free time
+ case 7: // Over limit time
+ drawLoadBar(x + margin,
+ (int) (legendLabelHeight * (1.5 * row + 0.5)),
+ symbolWidth, legendLabelHeight,
+ "overLimitCol", Qt::Dense4Pattern, legend);
+ break;
+ case 8: // Free time
drawLoadBar(x + margin,
(int) (legendLabelHeight * (1.5 * row + 0.5)),
symbolWidth, legendLabelHeight,
// Now we are calculating the load of the resource with respect to this
// task, to all tasks, and we calculate the not yet allocated load.
Interval period(start, end);
- double freeLoad = r->getEffectiveFreeLoad(scenario, period);
+ double freeLoad;
+ double overLoad;
double taskLoad;
double load;
Qt::BrushStyle pattern1 , pattern2, pattern3;
if (r->getEfficiency() > 0.0)
{
- freeLoad = r->getEffectiveFreeLoad(scenario, period);
+ freeLoad = r->getFreeLoad(scenario, period, true);
+ overLoad = r->getOverLimitLoad(scenario, period, true);
taskLoad = r->getEffectiveLoad(scenario, period, AllAccounts, t);
load = r->getEffectiveLoad(scenario, period, AllAccounts);
pattern1 = pattern2 = pattern3 = Qt::Dense4Pattern;
}
else
{
- freeLoad = r->getAvailableTimeLoad(scenario, period);
+ freeLoad = r->getFreeLoad(scenario, period, false);
+ overLoad = r->getOverLimitLoad(scenario, period, false);
taskLoad = r->getAllocatedTimeLoad(scenario, period, AllAccounts, t);
load = r->getAllocatedTimeLoad(scenario, period, AllAccounts);
pattern1 = pattern2 = pattern3 = Qt::Dense5Pattern;
}
double otherLoad = load - taskLoad;
- double maxLoad = load + freeLoad;
+ double maxLoad = load + freeLoad + overLoad;
if (maxLoad <= 0.0)
return;
(taskLoad / maxLoad));
int colOtherLoadTop = colBottom - (int) ((colBottom - colTop) *
(load / maxLoad));
+ int colOverLimitTop = colBottom - (int) ((colBottom - colTop) *
+ ((load + overLoad) / maxLoad));
// Now we draw the columns. But only if the load is larger than 0.
if (taskLoad > 0.0)
"otherLoadCol", pattern2, chart);
}
+ if (overLoad > 0.0)
+ {
+ drawLoadBar(cx, colOverLimitTop, cw, colOtherLoadTop - colOverLimitTop,
+ "overLimitCol", pattern2, chart);
+ }
+
if (freeLoad > 0.0)
{
// Unallocated load.
- drawLoadBar(cx, colTop, cw, colOtherLoadTop - colTop, "freeLoadCol",
+ drawLoadBar(cx, colTop, cw, colOverLimitTop - colTop, "freeLoadCol",
pattern3, chart);
}
}
double load = r->getEffectiveLoad(scenario, iv, AllAccounts);
double allocatedTimeLoad = r->getAllocatedTimeLoad
(scenario, iv, AllAccounts);
- double freeLoad = r->getEffectiveFreeLoad(scenario, iv);
- double freeTimeLoad = r->getAvailableTimeLoad (scenario, iv);
+ double freeLoad = r->getFreeLoad(scenario, iv, true);
+ double freeTimeLoad = r->getFreeLoad (scenario, iv, false);
double totalLoad = load + freeLoad;
double totalTimeLoad = allocatedTimeLoad + freeTimeLoad;
text = i18n("%1(%2) - %3 - Effort: %4 (%5%) "
vacation 2009-1-6 +1d
}
+resource r3 "R3" {
+}
+
+resource equip "equipement" {
+ resource r4 "R4 (efficiency 0)" {
+ efficiency 0.0
+ limits {dailymax 7h}
+ }
+}
+
task t2 "T2" {
allocate r2 { limits { weeklymax 5d } }
+ allocate equip { mandatory limits {dailymax 5h} }
+}
+
+task t3 "T3" {
+ allocate r3 { limits {dailymax 2h} }
+ allocate equip { mandatory limits {dailymax 2h} }
+}
+
+task t4 "T4" {
+ priority 499
+ effort 10d
+ allocate r3
}
taskreport "Gantt" {
columns id,start,end,maxeffort,chart
+ sorttasks tree,sequenceup
}
htmltaskreport "/tmp/tjweekly.html" {
loadunit days
hideresource 0
}
+
+resourcereport "Resource" {
+ columns chart
+}
\ No newline at end of file
specifiedBookings(new SbBooking**[p->getMaxScenarios()]),
scoreboards(new SbBooking**[p->getMaxScenarios()]),
scenarios(new ResourceScenario[p->getMaxScenarios()]),
+ frozenScenarios(new bool[p->getMaxScenarios()]),
allocationProbability(new double[p->getMaxScenarios()])
{
vacations.setAutoDelete(true);
{
scoreboards[sc] = 0;
specifiedBookings[sc] = 0;
+ frozenScenarios[sc] = false;
}
for (int i = 0; i < p->getMaxScenarios(); ++i)
if (!limits)
return BOOKING_FREE;
+ // TODO: stop here if the scenario is frozen (but how should I guess which
+ // is the current scenario?)
+
if ((limits && limits->getDailyMax() > 0))
{
// Now check that the resource is not overloaded on this day.
bool
Resource::bookInterval(Booking* nb, int sc, int sloppy, int overtime)
{
+ assert(frozenScenarios[sc] == false);
+
uint sIdx = sbIndex(nb->getStart());
uint eIdx = sbIndex(nb->getEnd());
bool
Resource::addBooking(int sc, Booking* nb, int sloppy, int overtime)
{
+ assert(frozenScenarios[sc] == false);
+
SbBooking** tmp = scoreboard;
if (scoreboards[sc])
}
double
-Resource::getEffectiveFreeLoad(int sc, const Interval& period)
+Resource::getFreeLoad(int sc, const Interval& period, bool effective)
{
double load = 0.0;
Interval iv(period);
if (hasSubs())
{
for (ResourceListIterator rli(*sub); *rli != 0; ++rli)
- load += (*rli)->getEffectiveFreeLoad(sc, iv);
+ load += (*rli)->getFreeLoad(sc, iv, effective);
}
else
{
uint endIdx = sbIndex(iv.getEnd());
load = project->convertToDailyLoad
(getAvailableSlots(sc, startIdx, endIdx) *
- project->getScheduleGranularity()) * efficiency;
+ project->getScheduleGranularity())
+ * ((!effective || efficiency == 0.0) ? 1.0 : efficiency);
}
return load;
}
double
-Resource::getAvailableTimeLoad(int sc, const Interval& period)
-{
- return project->convertToDailyLoad(getAvailableTime(sc, period));
-}
-
-long
-Resource::getAvailableTime(int sc, const Interval& period)
+Resource::getOverLimitLoad(int sc, const Interval& period, bool effective)
{
+ double load = 0.0;
Interval iv(period);
if (!iv.overlap(Interval(project->getStart(), project->getEnd())))
- return 0;
+ return 0.0;
- return getAvailableSlots(sc, sbIndex(iv.getStart()),
- sbIndex(iv.getEnd())) *
- project->getScheduleGranularity();
+ if (hasSubs())
+ {
+ for (ResourceListIterator rli(*sub); *rli != 0; ++rli)
+ load += (*rli)->getOverLimitLoad(sc, iv, effective);
+ }
+ else
+ {
+ uint startIdx = sbIndex(iv.getStart());
+ uint endIdx = sbIndex(iv.getEnd());
+ load = project->convertToDailyLoad
+ (getOverLimitSlots(sc, startIdx, endIdx) *
+ project->getScheduleGranularity())
+ * ((!effective || efficiency == 0.0) ? 1.0 : efficiency);
+ }
+
+ return load;
+}
+
+void
+Resource::freezeScenario(int sc)
+{
+ if (frozenScenarios[sc])
+ return;
+ // browse all booking slots for a given scenario, to force
+ // evaluation of resource usage limits a last time before using
+ // scoreboard content in getAvailableSlots() et getOverLimitSlots()
+ SbBooking** tmp = scoreboard;
+ scoreboard = scoreboards[sc];
+ if (!scoreboard)
+ {
+ initScoreboard();
+ scoreboards[sc] = scoreboard;
+ }
+ for (time_t d = project->getStart(); d < project->getEnd();
+ d += project->getScheduleGranularity())
+ getBooking(d);
+ scoreboard = tmp;
+ frozenScenarios[sc] = true;
}
long
}
else
{
- if (!scoreboards[sc])
- {
- scoreboard = scoreboards[sc];
- initScoreboard();
- scoreboards[sc] = scoreboard;
- }
-
+ freezeScenario(sc);
for (uint i = startIdx; i <= endIdx; i++)
- if (scoreboards[sc][i] == 0)
+ if (scoreboards[sc][i] == SB_FREE)
availSlots++;
}
return availSlots;
}
+long
+Resource::getOverLimitSlots(int sc, uint startIdx, uint endIdx)
+{
+ long overSlots = 0;
+
+ if (!sub->isEmpty())
+ {
+ for (ResourceListIterator rli(*sub); *rli != 0; ++rli)
+ overSlots += (*rli)->getOverLimitSlots(sc, startIdx, endIdx);
+ }
+ else
+ {
+ freezeScenario(sc);
+ for (uint i = startIdx; i <= endIdx; i++)
+ if (scoreboards[sc][i] == SB_OVERLIMIT)
+ overSlots++;
+ }
+
+ return overSlots;
+}
+
double
Resource::getCredits(int sc, const Interval& period, AccountType acctType,
const Task* task) const
return( elem );
}
-
-
-
bool book(Booking* b);
- bool bookSlot(uint idx, SbBooking* nb, int overtime = 0);
bool bookInterval(Booking* b, int sc, int sloppy = 0, int overtime = 0);
bool addBooking(int sc, Booking* b, int sloppy = 0, int overtime = 0);
/***
* Return the unallocated load of the resource and its children wheighted
- * by their efficiency.
+ * by their efficiency if effective == true and efficiency != 0.0.
*/
- double getEffectiveFreeLoad(int sc, const Interval& period);
- double getAvailableTimeLoad(int sc, const Interval& period);
- long getAvailableTime(int sc, const Interval& period);
+ double getFreeLoad(int sc, const Interval& period, bool effective);
+ inline double getEffectiveFreeLoad(int sc, const Interval& period)
+ {
+ return getFreeLoad(sc, period, true);
+ }
+ double getOverLimitLoad(int sc, const Interval& period, bool effective);
double getCredits(int sc, const Interval& i, AccountType acctType,
const Task* task = 0) const;
void initScoreboard();
+ bool bookSlot(uint idx, SbBooking* nb, int overtime = 0);
+
long getCurrentLoadSub(uint startIdx, uint endIdx, const Task* task) const;
long getAllocatedSlots(int sc, uint startIdx, uint endIdx,
AccountType acctType, const Task* task) const;
long getAvailableSlots(int sc, uint startIdx, uint endIdx);
+ long getOverLimitSlots(int sc, uint startIdx, uint endIdx);
+ void freezeScenario(int sc);
bool isAllocatedSub(int sc, uint startIdx, uint endIdx, const QString&
prjId) const;
ResourceScenario* scenarios;
+ bool* frozenScenarios;
+
/**
* The allocation probability is calculated prior to scheduling a
* scenario. It is the expected average effort the resource has to deliver