Category : Windows 3.X Files
Archive   : PROJ0928.ZIP
Filename : ACTIVITY.CLS

 
Output of file : ACTIVITY.CLS contained in archive : PROJ0928.ZIP
/* Activity is a formal class to group common behavior among
tasks and milestones for projects. Activities know how to
determine if they are on the critical path and keep track
of their earlyStart, lateFinish and slack time.
The user can set an earlyStart or lateFinish to override
what is calculated.

Since Activity descends from Node, it inherits all of the
methods and instance variables from Node, e.g. name, desc,
inputs, outputs, etc.
*/!!

inherit(Node, #Activity, #(earlyStart /* calculated */
lateFinish /* calculated */
userEarlyStart /* user entered */
userLateFinish /* user entered */
slack /* slack time */
critical /* boolean */), 2, nil)!!

now(ActivityClass)!!

now(Activity)!!

/* In general, activities place no limit on the number
of connections. Descendants, such as Task, will
redefine this to place limits. */
Def maxConnectionNames(self, names)
{
^names;
}!!

/* Delete an activity. First check to see if it is
connected to anything and check with the user. */
Def delete(self)
{
if size(inputs) + size(outputs) = 0
cor yesNoBox("Warning", name + " is connected to " +
"other activities!" + CR_LF + "Delete anyways?") == IDYES
do(inputs,
{using(input)
disconnect(input, self);
});
do(outputs,
{using(output)
disconnect(self, output);
});
removeNode(network, self);
remove(network.display, pos(self));
endif;
}!!

/* Parse a string of nodeNames and return a set of
nodes. Checks to see if they exist. */
Def parseNodeNames(self, nodeNames | names, nodes, aNode)
{
names := words(nodeNames);
names := maxConnectionNames(self, names);
nodes := new(OrderedCollection, 5);
do(names,
{using(name)
if aNode := checkNodeExists(network, name)
add(nodes, aNode);
endif;
});
^nodes;
}!!

/* Checks the connections and reconnects if necessary.
If the connections change, we may have to recalc
the entire project. */
Def checkConnection(self, inputsString, outputsString
| newInputs, newOutputs, calcReqd)
{
if inputsString <> getInputNames(self)
newInputs := parseNodeNames(self, inputsString);
do(inputs,
{using(input)
if not(input in newInputs)
disconnect(network, input.name, self.name);
calcReqd := true;
endif;
});
do(newInputs,
{using(input)
if not(input in inputs)
connect(network, input.name, self.name);
calcReqd := true;
endif;
});
endif;

if outputsString <> getOutputNames(self)
newOutputs := parseNodeNames(self, outputsString);
do(outputs,
{using(output)
if not(output in newOutputs)
disconnect(network, self.name, output.name);
calcReqd := true;
endif
});
do(newOutputs,
{using(output)
if not(output in outputs)
connect(network, self.name, output.name);
calcReqd := true;
endif;
});
endif;

if autoCalc(network) cand calcReqd
recalc(network)
endif;
}!!

/* Return a string of output names.
This is useful when editing. */
Def getOutputNames(self | str)
{
str := "";
do(outputs,
{using(output) str := str + getName(output) + " ";
});
^str;
}!!

/* Return a string of input names.
This is useful when editing. */
Def getInputNames(self | str)
{
str := "";
do(inputs,
{using(input) str := str + getName(input) + " ";
});
^str;
}!!

/* Display and edit the settings.
Descendants that use this should have a dialogClass()
method that returns the dialog class to be used. The
dialog class should define methods run() and setEditItem().
*/
Def editInfo(self, aWindow| dlg, retValue)
{
showWaitCurs();
dlg := new(dialogClass(self));
setEditItem(dlg, self);
retValue := run(dlg, aWindow);
if retValue == IDOK
dirty(aWindow); /* make sure parent knows */
endif;
showOldCurs();
^retValue;
}!!

/* In the simplest case an activity is critical if slack = 0.
However, if the user has set the lateFinish, it could
introduce excess slack to the project. Therefore, a node
is critical if its slack is equal to the excess slack. */
Def calcCritical(self)
{
critical := (slack = getSlack(network));
}!!

/* Set the values of an activity.
Values is an array of name, desc,
userEarlyStart, userLateFinish. */
Def setValues(self, values | oldUES, oldULF)
{
oldUES := userEarlyStart;
oldULF := userLateFinish;
name := values[0];
desc := values[1];
userEarlyStart := values[2];
userLateFinish := values[3];
if autoCalc(network) cand
(oldUES <> userEarlyStart cor
oldULF <> userLateFinish)
recalc(self);
endif;
}!!

/* Get the user set earlyStart time. */
Def getUserEarlyStart(self)
{
^userEarlyStart;
}!!

/* Get the user set lateFinish time. */
Def getUserLateFinish(self)
{
^userLateFinish;
}!!

/* Return a string to be used as a caption in a window. */
Def makeCaption(self)
{
^asString(class(self)) + ": "+getName(self)+
if critical(self)
" *CRITICAL*"
else
" (non-critical)"
endif;
}!!

/* Summarize useful information on a single line. */
Def getInfoLine(self | str)
{
if critical(self)
str := "*";
else
str := " ";
endif;
^str + field(name, 8)
+ field(asString(class(self)), 4) + " "
+ field(asString(getCost(self)), 3) + " "
+ field(asString(getTime(self)), 2) + " "
+ field(asString(getSlack(self)), 3) + " "
+ field(asString(getEarlyStart(self)), 8) + " "
+ field(asString(getLateFinish(self)), 8);
}!!

/* Get the lateFinish time. At End, lateFinish = earlyStart,
unless the user set a lateFinish. */
Def getLateFinish(self)
{
if (size(outputs) == 0 and not(userLateFinish))
lateFinish := earlyStart
endif;
^lateFinish;
}!!

/* Calculate slack for an Activity. This is done
on the backward recalc pass when ES, LF are
up to date. Slack is never < 0. */
Def calcSlack(self)
{
^slack := max(0, getLateStart(self) - getEarlyStart(self));
}!!

/* Get the slack value. */
Def getSlack(self)
{
^slack;
}!!

/* Return the status of whether the node is critical or not. */
Def critical(self)
{
^critical;
}!!

/* Invalidate a node and recursively invalidate all
nodes it's connected to. This is used to force
an entire recalc of the network. */
Def invalidate(self, visited)
{
reset(self); /* reset ivars */
do(outputs, /* pass along */
{using(elem)
if not(elem in visited) /* avoid looping */
add(visited, elem);
invalidate(elem, visited); /* recurse */
endif;
});
}!!

/* Recalculate the network from this node onwards.
This requires forcing a forward recalc1 and a
backwards recalc2 from the end of the net. */
Def recalc(self)
{
recalc1(self,true); /* force forward recalc1 */
recalc2(network); /* do backwards recalc2 */
}!!

/* Backward recalc pass: (not optimized)
Recalculate an activity's lateFinish then its slack and
determine if it's critical.
If the user has set a lateFinish, use it instead of
recalculating. Always propogate recalc2 since a
change to the time of a node will not change lateFinish,
but it can change slack and critical, which are only
known on the backwards pass.

formula: LF = min(LF(i) - time(i)) for all outputs i

Note: This could be optimized to only propogate recalc2
as far back as the next Milestone. */
Def recalc2(self)
{
if (userLateFinish)
lateFinish := userLateFinish; /* user override */
else
lateFinish := asLong(date(12,31,1999));
do(outputs,
{using(output)
lateFinish := min(lateFinish,
getLateFinish(output) - getTime(output));
});
lateFinish := asDate(lateFinish);
endif;

calcSlack(self);
calcCritical(self);

/* Continue sending the recalc2 message. */

do(inputs,
{using(input)
recalc2(input);
});
}!!

/* Forward recalc pass: (optimized minimal recalc)
Recalculate an activity's earlyStart. If the user has
set an earlyStart, use it instead of recalculating.
Send a message to the node's outputs to recalculate only
if a forced recalc is required, or if earlyStart changes.

formula: ES = max(ES(i) + time(i)) for all inputs i

arguments:
timeChanged: force a recalc1 if the time has changed
*/
Def recalc1(self, timeChanged | oldEarlyStart)
{
oldEarlyStart := earlyStart;

if (userEarlyStart)
earlyStart := userEarlyStart; /* user override */
else
earlyStart := asLong(new(Date));
do(inputs,
{using(input)
earlyStart := max(earlyStart,
getEarlyStart(input) + getTime(input));
});
earlyStart := asDate(earlyStart);
endif;

/* Recalculate outputs only if earlyStart changed OR if time has
changed. Don't force it to continue beyond the next level. */

if timeChanged cor (earlyStart <> oldEarlyStart)
do(outputs,
{using(output) recalc1(output, nil);
});
endif;
}!!

/* Initialize a new Activity. */
Def init(self)
{ init(self:Node); /* use ancestor init */
reset(self); /* reset ivars */
} !!

/* Reset the instance variables. This is called by
init and when an entire recalc is forced. */
Def reset(self)
{
slack := 0;
lateFinish := earlyStart := new(Date);
critical := nil;
}!!

/* The user can enter a late finish date to be used
instead of the calculated value. */
Def setLateFinish(self, aDate)
{
userLateFinish := aDate;
if autoCalc(network) /* just do backwards calc */
recalc2(network);
endif;
}!!

/* The user can enter an early start date to be used
instead of the calculated value. */
Def setEarlyStart(self, aDate)
{
userEarlyStart := aDate;
if autoCalc(network)
recalc(self);
endif;
} !!

/* Get the earlyStart time. */
Def getEarlyStart(self)
{
^earlyStart;
} !!

/* Calculcate the earlyFinish time. */
Def getEarlyFinish(self)
{
^asDate(getEarlyStart(self) + getTime(self));
}!!

/* Calcualate the lateStart time. */
Def getLateStart(self)
{
^asDate(getLateFinish(self) - getTime(self));
}!!




  3 Responses to “Category : Windows 3.X Files
Archive   : PROJ0928.ZIP
Filename : ACTIVITY.CLS

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/