0001: /*
0002: The contents of this file are subject to the Common Public Attribution License
0003: Version 1.0 (the "License"); you may not use this file except in compliance with
0004: the License. You may obtain a copy of the License at
0005: http://www.projity.com/license . The License is based on the Mozilla Public
0006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
0007: software over a computer network and provide for limited attribution for the
0008: Original Developer. In addition, Exhibit A has been modified to be consistent
0009: with Exhibit B.
0010:
0011: Software distributed under the License is distributed on an "AS IS" basis,
0012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
0013: specific language governing rights and limitations under the License. The
0014: Original Code is OpenProj. The Original Developer is the Initial Developer and
0015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
0016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
0017:
0018: Alternatively, the contents of this file may be used under the terms of the
0019: Projity End-User License Agreeement (the Projity License), in which case the
0020: provisions of the Projity License are applicable instead of those above. If you
0021: wish to allow use of your version of this file only under the terms of the
0022: Projity License and not to allow others to use your version of this file under
0023: the CPAL, indicate your decision by deleting the provisions above and replace
0024: them with the notice and other provisions required by the Projity License. If
0025: you do not delete the provisions above, a recipient may use your version of this
0026: file under either the CPAL or the Projity License.
0027:
0028: [NOTE: The text of this license may differ slightly from the text of the notices
0029: in Exhibits A and B of the license at http://www.projity.com/license. You should
0030: use the latest text at http://www.projity.com/license for your modifications.
0031: You may not remove this license text from the source files.]
0032:
0033: Attribution Information: Attribution Copyright Notice: Copyright � 2006, 2007
0034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
0035: an open source solution from Projity. Attribution URL: http://www.projity.com
0036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
0037: alternatives listed on http://www.projity.com/logo
0038:
0039: Display of Attribution Information is required in Larger Works which are defined
0040: in the CPAL as a work which combines Covered Code or portions thereof with code
0041: not governed by the terms of the CPAL. However, in addition to the other notice
0042: obligations, all copies of the Covered Code in Executable and Source Code form
0043: distributed must, as a form of attribution of the original author, include on
0044: each user interface screen the "OpenProj" logo visible to all users. The
0045: OpenProj logo should be located horizontally aligned with the menu bar and left
0046: justified on the top left of the screen adjacent to the File menu. The logo
0047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
0048: must direct them back to http://www.projity.com.
0049: */
0050: package com.projity.pm.task;
0051:
0052: import java.io.IOException;
0053: import java.io.ObjectInputStream;
0054: import java.io.ObjectOutputStream;
0055: import java.util.Collection;
0056: import java.util.Iterator;
0057: import java.util.LinkedList;
0058:
0059: import org.apache.commons.collections.Closure;
0060:
0061: import com.projity.algorithm.ReverseQuery;
0062: import com.projity.algorithm.TimeIteratorGenerator;
0063: import com.projity.algorithm.buffer.CalculatedValues;
0064: import com.projity.association.AssociationFormatParameters;
0065: import com.projity.association.AssociationList;
0066: import com.projity.association.AssociationListFormat;
0067: import com.projity.configuration.Configuration;
0068: import com.projity.configuration.Settings;
0069: import com.projity.datatype.Duration;
0070: import com.projity.datatype.ImageLink;
0071: import com.projity.datatype.TimeUnit;
0072: import com.projity.document.Document;
0073: import com.projity.field.CustomFieldsImpl;
0074: import com.projity.field.FieldContext;
0075: import com.projity.field.FieldParseException;
0076: import com.projity.functor.IntervalConsumer;
0077: import com.projity.functor.NumberClosure;
0078: import com.projity.functor.ObjectVisitor;
0079: import com.projity.graphic.configuration.HasIndicators;
0080: import com.projity.graphic.configuration.HasTaskIndicators;
0081: import com.projity.grouping.core.Node;
0082: import com.projity.grouping.core.model.NodeModel;
0083: import com.projity.grouping.core.summaries.DeepChildWalker;
0084: import com.projity.options.CalculationOption;
0085: import com.projity.options.CalendarOption;
0086: import com.projity.options.ScheduleOption;
0087: import com.projity.pm.assignment.Allocation;
0088: import com.projity.pm.assignment.Assignment;
0089: import com.projity.pm.assignment.AssignmentFormat;
0090: import com.projity.pm.assignment.AssignmentService;
0091: import com.projity.pm.assignment.HasAssignments;
0092: import com.projity.pm.assignment.TimeDistributedFields;
0093: import com.projity.pm.assignment.timesheet.TimesheetHelper;
0094: import com.projity.pm.calendar.CalendarService;
0095: import com.projity.pm.calendar.WorkCalendar;
0096: import com.projity.pm.costing.Accrual;
0097: import com.projity.pm.costing.EarnedValueCalculator;
0098: import com.projity.pm.costing.EarnedValueFields;
0099: import com.projity.pm.costing.EarnedValueValues;
0100: import com.projity.pm.criticalpath.TaskSchedule;
0101: import com.projity.pm.key.HasKeyImpl;
0102: import com.projity.pm.resource.Resource;
0103: import com.projity.pm.resource.ResourceImpl;
0104: import com.projity.pm.scheduling.BarClosure;
0105: import com.projity.pm.scheduling.ConstraintType;
0106: import com.projity.pm.scheduling.Schedule;
0107: import com.projity.pm.scheduling.ScheduleEvent;
0108: import com.projity.pm.scheduling.ScheduleInterval;
0109: import com.projity.pm.scheduling.ScheduleUtil;
0110: import com.projity.pm.scheduling.SchedulingFields;
0111: import com.projity.pm.scheduling.SchedulingRule;
0112: import com.projity.pm.scheduling.SchedulingType;
0113: import com.projity.pm.snapshot.BaselineScheduleFields;
0114: import com.projity.pm.snapshot.DataSnapshot;
0115: import com.projity.pm.snapshot.SnapshottableImpl;
0116: import com.projity.strings.Messages;
0117: import com.projity.util.DateTime;
0118:
0119: /**
0120: * @stereotype thing
0121: */
0122: public class NormalTask extends Task implements Allocation,
0123: TaskSpecificFields, SchedulingFields, HasAssignments,
0124: EarnedValueValues, EarnedValueFields, TimeDistributedFields,
0125: BaselineScheduleFields, HasTaskIndicators {
0126: static final long serialVersionUID = 273898992929L;
0127:
0128: // Schedule schedule = null;
0129:
0130: boolean estimated = true;
0131: int priority = 500;
0132:
0133: public NormalTask(Project project) {
0134: this (project.isLocal(), project);
0135: }
0136:
0137: public NormalTask(boolean local, Project project) {
0138: super (local);
0139: this .project = project;
0140: initializeDates();
0141: addDefaultAssignment();
0142:
0143: }
0144:
0145: public NormalTask() {
0146: super ();
0147: }
0148:
0149: /**
0150: * Used when creating a task to set initial date and duration conditions
0151: *
0152: */
0153: void initializeDates() {
0154: setRawConstraintType(project == null ? ConstraintType.ASAP
0155: : project.getDefaultConstraintType());
0156: long duration = CalendarOption.getInstance()
0157: .getDefaultDuration(); //MS uses 1 day estimated
0158: setRawDuration(duration);
0159: setWorkCalendar(null);
0160:
0161: // initialize start and end to avoid 0 dates in calculations
0162: long start = project.getStart();
0163: currentSchedule.setStart(start);
0164: currentSchedule.setFinish(start);
0165:
0166: if (ScheduleOption.getInstance().isNewTasksStartToday())
0167: setWindowEarlyStart(CalendarOption.getInstance()
0168: .makeValidStart(DateTime.midnightToday(), true));
0169: }
0170:
0171: /**
0172: * This constructor is used to create dummy tasks, such as the UNASSIGNED
0173: * instance. We do not want to perform standard initialization on it.
0174: *
0175: * @param dummy
0176: */
0177: private NormalTask(boolean dummy) {
0178: super (true);
0179: }
0180:
0181: private static NormalTask UNASSIGNED = null;
0182:
0183: public static NormalTask getUnassignedInstance() {
0184: if (UNASSIGNED == null) {
0185: UNASSIGNED = new NormalTask(true);
0186: UNASSIGNED.setName(Messages.getString("Text.Unassigned"));
0187: }
0188: return UNASSIGNED;
0189: }
0190:
0191: private Assignment newDefaultAssignment() {
0192: return Assignment.getInstance(this , ResourceImpl
0193: .getUnassignedInstance(), 1.0, 0);
0194: }
0195:
0196: public boolean isNormal() {
0197: return !isSummary() && !isMilestone() && !isExternal();
0198: }
0199:
0200: public boolean isCritical() {
0201: if (currentSchedule.isForward())
0202: return getEarlyFinish() >= getLateFinish(); //TODO hook into preference
0203: else
0204: // reverse schedule
0205: return getLateStart() <= getEarlyStart();
0206: }
0207:
0208: public boolean isMilestone() {
0209: // return !hasDuration();
0210: return Duration.millis(getRawDuration()) == 0
0211: || isMarkTaskAsMilestone();
0212: }
0213:
0214: /****************************************************************************************
0215: * Schedule
0216: ****************************************************************************************/
0217: /**
0218: * @return
0219: */
0220: public long getDuration() {
0221: long duration;
0222: if (isWbsParent() || isExternal() || isSubproject()) {
0223: duration = getRawDuration();
0224: } else {
0225: AssociationList assignments = getAssignments();
0226: if (assignments.size() == 1) {
0227: duration = ((Assignment) assignments.getFirst())
0228: .getDurationMillis();
0229: } else {
0230: Iterator i = assignments.iterator();
0231: long end = 0;
0232: // get the latest ending assignment
0233: while (i.hasNext()) {
0234: end = Math.max(end, ((Assignment) i.next())
0235: .getEnd());
0236: }
0237: // duration is calendar time between assignment end and task start
0238: duration = getEffectiveWorkCalendar().compare(end,
0239: getStart(), false);
0240: }
0241: }
0242: duration = Duration.setAsEstimated(duration, estimated);
0243: return duration;
0244:
0245: // return calcActiveAssignmentDuration(getEffectiveWorkCalendar());
0246: }
0247:
0248: /** Quickly check to see if a task has a duration without actually calculating it
0249: *
0250: * @return true if duration > 0
0251: */
0252: public boolean hasDuration() {
0253: if (isWbsParent()) {
0254: return getRawDuration() != 0;
0255: } else {
0256: AssociationList assignments = getAssignments();
0257: if (assignments.size() == 1)
0258: return ((Assignment) assignments.getFirst())
0259: .hasDuration();
0260: Iterator i = assignments.iterator();
0261: while (i.hasNext()) {
0262: if (((Assignment) i.next()).hasDuration())
0263: return true;
0264: }
0265: }
0266: return false;
0267:
0268: }
0269:
0270: /**
0271: * @param duration
0272: */
0273: public void setDuration(long duration) {
0274: setRawDuration(duration); // set the schedule duration, primariy for use when reading a file
0275: estimated = Duration.isEstimated(duration);
0276: duration = Duration.millis(duration);
0277: long actualDurationMillis = Duration
0278: .millis(getActualDuration());
0279: if (duration < actualDurationMillis) // if reducing duration to shorter than the current actual duration
0280: setPercentComplete(1);
0281: if (!isWbsParent()) {
0282: long remainingDuration = duration - actualDurationMillis;
0283: getSchedulingRule().adjustRemainingDuration(this ,
0284: remainingDuration, true);
0285: }
0286: updateCachedDuration();
0287: }
0288:
0289: /********************************************************************************
0290: * Calendars
0291: ***********************************************************************************/
0292:
0293: private WorkCalendar workCalendar = null;
0294:
0295: /**
0296: * @return
0297: */
0298: public WorkCalendar getWorkCalendar() {
0299: return workCalendar;
0300: }
0301:
0302: public WorkCalendar getEffectiveWorkCalendar() {
0303: if (workCalendar == null)
0304: return getProject().getEffectiveWorkCalendar();
0305: return workCalendar;
0306: }
0307:
0308: /**
0309: * @param workCalendar
0310: */
0311: public void setWorkCalendar(WorkCalendar workCalendar) {
0312: this .workCalendar = workCalendar;
0313: }
0314:
0315: /**
0316: * @return
0317: */
0318: public DataSnapshot getCurrentSnapshot() {
0319: return snapshots.getCurrentSnapshot();
0320: }
0321:
0322: /**
0323: * @param i
0324: * @return
0325: */
0326: public DataSnapshot getSnapshot(Object snapshotId) {
0327: return snapshots.getSnapshot(snapshotId);
0328: }
0329:
0330: /**
0331: * @param i
0332: */
0333: public void saveCurrentToSnapshot(Object snapshotId) {
0334: setSnapshot(snapshotId, cloneSnapshot(getSnapshot(CURRENT)));
0335: markTaskAsNeedingRecalculation(); // for redraw purpooses, not for recalc.
0336: setDirty(true);
0337: }
0338:
0339: public void restoreSnapshot(Object snapshotId, Object b) {
0340: TaskBackup backup = (TaskBackup) b;
0341: if (backup.snapshot == null)
0342: return;
0343: TaskSnapshot snapshot = (TaskSnapshot) ((TaskSnapshot) getSnapshot(CURRENT))
0344: .clone();
0345: //snapshot.setCurrentSchedule(getCurrentSchedule());
0346: restoreDetail(this , backup, true, snapshot);
0347: setSnapshot(snapshotId, snapshot);
0348: markTaskAsNeedingRecalculation(); // for redraw purpooses, not for recalc.
0349: setDirty(true);
0350: }
0351:
0352: /**
0353: * @param snapshot
0354: */
0355: public void setCurrentSnapshot(DataSnapshot snapshot) {
0356:
0357: snapshots.setCurrentSnapshot(snapshot);
0358: }
0359:
0360: /**
0361: * @param i
0362: * @param snapshot
0363: */
0364: public void setSnapshot(Object snapshotId, DataSnapshot snapshot) {
0365: snapshots.setSnapshot(snapshotId, snapshot);
0366: }
0367:
0368: /**
0369: * @param i
0370: */
0371: public void clearSnapshot(Object snapshotId) {
0372: snapshots.clearSnapshot(snapshotId);
0373: markTaskAsNeedingRecalculation(); // for redraw purpooses, not for recalc.
0374: setDirty(true);
0375: }
0376:
0377: public boolean hasRealAssignments() {
0378: return (null == findAssignment(ResourceImpl
0379: .getUnassignedInstance()));
0380: }
0381:
0382: /**
0383: * @return
0384: */
0385: public AssociationList getAssignments() {
0386: return ((TaskSnapshot) getCurrentSnapshot()).getAssignments();
0387: }
0388:
0389: public AssociationList getRealAssignments() {
0390: if (hasRealAssignments())
0391: return getAssignments();
0392: else
0393: return new AssociationList(); //empty list
0394: }
0395:
0396: public boolean isAssignedToMe() {
0397: for (Iterator i = getAssignments().iterator(); i.hasNext();) {
0398: Assignment a = (Assignment) i.next();
0399: if (a.isMine())
0400: return true;
0401: }
0402: return false;
0403: }
0404:
0405: /**
0406: * Add an assignment to the task. A task always has at least one assignment, whether or not
0407: * it has any true assignments. This is because a default assignment is always present. This
0408: * greatly facilitates other calculations. This method takes care to either create or delete
0409: * the default assignment.
0410: *
0411: * @param assignment
0412: */
0413: public void addDefaultAssignment() {
0414: addAssignment(newDefaultAssignment());
0415: }
0416:
0417: public void addAssignment(Assignment assignment) {
0418: //project.beginUndoUpdate();
0419: boolean recalculateDuration = !assignment.isDefault()
0420: && assignment.isInitialized() && assignment.isLabor();
0421: Assignment defaultAssignment = findAssignment(ResourceImpl
0422: .getUnassignedInstance());
0423:
0424: if (!assignment.isDefault()) {
0425: // get rid of any default
0426: if (defaultAssignment != null) { //Remove any default assignment
0427: assignment.usePropertiesOf(defaultAssignment); // the new assignment must take on properties of the default assignment
0428: AssignmentService.getInstance().remove(
0429: defaultAssignment, null, true);
0430: } else {
0431: // if the task is started already, then only apply to remaining duration. This means added delay to new assignment
0432: if (getActualStart() != 0L)
0433: assignment.setDelay(Duration
0434: .millis(getActualDuration()));
0435: assignment.adjustRemainingDuration(Duration
0436: .millis(getRemainingDuration()), false);
0437: }
0438: } else {
0439: if (defaultAssignment != null) //Remove any default assignment. This happens importing if the imported task just has no assignments
0440: AssignmentService.getInstance().remove(
0441: defaultAssignment, null, true);
0442:
0443: // use default task duration for the default assignment duraiton
0444: assignment.setDuration(getRawDuration());
0445: }
0446:
0447: // must calculate these two values before adding assignment!
0448: double mostLoadedAssignmentUnits = getMostLoadedAssignmentUnits();
0449: // Get details of current assignments before change
0450: double assignedRate = getRemainingUnits();
0451:
0452: // add assignment
0453: ((TaskSnapshot) getCurrentSnapshot()).addAssignment(assignment);
0454:
0455: if (!assignment.isInitialized()) // if reading in, then don't recalc duration
0456: return;
0457:
0458: // if effort driven then set duration
0459: if (recalculateDuration && isEffortDriven()) {
0460: if (assignedRate != 0) {//
0461: if (getSchedulingType() == SchedulingType.FIXED_DURATION) // fixed duration effort driven has complicated rule - a new assignment is weighted the same as the most loaded assignment, unless that assignment is over 100%
0462: assignment
0463: .adjustRemainingUnits(Math.min(1.0,
0464: mostLoadedAssignmentUnits), 1,
0465: false, false);
0466: double newRemainingUnits = assignedRate
0467: + assignment.getRemainingLaborUnits();
0468:
0469: getSchedulingRule().adjustRemainingUnits(this ,
0470: newRemainingUnits, assignedRate, true, true); // conserve total units
0471: }
0472: }
0473: setDirty(true);
0474: //project.endUndoUpdate();
0475:
0476: }
0477:
0478: /**
0479: * @param assignment
0480: */
0481: public void removeAssignment(Assignment assignment) {
0482: //project.beginUndoUpdate();
0483: boolean recalculateDuration = !assignment.isDefault()
0484: && assignment.isInitialized(); // && assignment.isLabor();
0485: // Get details of current assignments before change
0486:
0487: double assignedRate = getRemainingUnits();
0488: ((TaskSnapshot) getCurrentSnapshot())
0489: .removeAssignment(assignment);
0490:
0491: if (!assignment.isDefault()) {
0492:
0493: if (recalculateDuration && isEffortDriven()) {
0494: double newUnits = assignedRate
0495: - assignment.getLaborUnits();
0496: if (newUnits != 0) {
0497: getSchedulingRule().adjustRemainingUnits(this ,
0498: newUnits, assignedRate, true, true); // conserve total units
0499: }
0500: }
0501: if (getAssignments().isEmpty()) {
0502: Assignment newDefault = newDefaultAssignment();
0503: newDefault.usePropertiesOf(assignment); // the default assignment must take on properties of the removed assignment
0504: AssignmentService.getInstance().connect(newDefault,
0505: null);
0506: }
0507: }
0508: setDirty(true);
0509: //project.endUndoUpdate();
0510:
0511: }
0512:
0513: /*
0514: * (non-Javadoc)
0515: *
0516: * @see com.projity.pm.snapshot.Snapshottable#cloneSnapshot(com.projity.pm.snapshot.DataSnapshot)
0517: */
0518:
0519: public DataSnapshot cloneSnapshot(DataSnapshot snapshot) {
0520: return (DataSnapshot) ((TaskSnapshot) snapshot).clone();
0521: }
0522:
0523: public TaskSnapshot getBaselineSnapshot() {
0524: return (TaskSnapshot) getSnapshot(CalculationOption
0525: .getInstance().getEarnedValueBaselineId());
0526: }
0527:
0528: /*
0529: * (non-Javadoc)
0530: *
0531: * @see com.projity.pm.assignment.HasTimeDistributedData#buildComplexQuery(com.projity.algorithm.ComplexQuery)
0532: */
0533: public void buildReverseQuery(ReverseQuery reverseQuery) {
0534: //Do this ones assignments
0535: ((TaskSnapshot) getCurrentSnapshot())
0536: .buildReverseQuery(reverseQuery);
0537: Collection children = getWbsChildrenNodes();
0538: Object current;
0539: if (children != null) { // do for all children as well
0540: Iterator i = children.iterator();
0541: Task child;
0542: while (i.hasNext()) {
0543: current = ((Node) i.next()).getImpl();
0544: if (!(current instanceof NormalTask))
0545: continue;
0546: child = (Task) current;
0547: child.buildReverseQuery(reverseQuery);
0548: }
0549: }
0550:
0551: }
0552:
0553: public long getBaselineStart() {
0554: TaskSnapshot baseline = getBaselineSnapshot();
0555: if (baseline == null)
0556: return getStart();
0557:
0558: return baseline.getCurrentSchedule().getStart();
0559:
0560: }
0561:
0562: public int getSchedulingType() {
0563: return ((TaskSnapshot) getCurrentSnapshot())
0564: .getSchedulingType();
0565: }
0566:
0567: public void setSchedulingType(int schedulingType) {
0568: ((TaskSnapshot) getCurrentSnapshot())
0569: .setSchedulingType(schedulingType);
0570: }
0571:
0572: public boolean isEffortDriven() {
0573: return ((TaskSnapshot) getCurrentSnapshot()).isEffortDriven();
0574: }
0575:
0576: public void setEffortDriven(boolean effortDriven) {
0577: ((TaskSnapshot) getCurrentSnapshot())
0578: .setEffortDriven(effortDriven);
0579:
0580: }
0581:
0582: public boolean isReadOnlyEffortDriven(FieldContext fieldContext) {
0583: return ((TaskSnapshot) getCurrentSnapshot())
0584: .isReadOnlyEffortDriven(fieldContext);
0585: }
0586:
0587: public static Closure forAllAssignments(Closure visitor) {
0588: return new ObjectVisitor(visitor) {
0589: protected Object getObject(Object arg0) {
0590: return ((TaskSnapshot) ((Task) arg0)
0591: .getCurrentSnapshot()).getHasAssignments();
0592: }
0593: };
0594: }
0595:
0596: public double getFixedCost() {
0597: return ((TaskSnapshot) getCurrentSnapshot()).getFixedCost();
0598: }
0599:
0600: public void setFixedCost(double fixedCost) {
0601: ((TaskSnapshot) getCurrentSnapshot()).setFixedCost(fixedCost);
0602: }
0603:
0604: /**
0605: * @return Returns the fixedCostAccrual.
0606: */
0607: public final int getFixedCostAccrual() {
0608: return ((TaskSnapshot) getCurrentSnapshot())
0609: .getFixedCostAccrual();
0610: }
0611:
0612: /**
0613: * @param fixedCostAccrual The fixedCostAccrual to set.
0614: */
0615: public final void setFixedCostAccrual(int fixedCostAccrual) {
0616: ((TaskSnapshot) getCurrentSnapshot())
0617: .setFixedCostAccrual(fixedCostAccrual);
0618: }
0619:
0620: public int getPriority() {
0621: return priority;
0622: }
0623:
0624: public void setPriority(int priority) {
0625: this .priority = priority;
0626: }
0627:
0628: public Assignment findAssignment(Resource resource) {
0629: return ((TaskSnapshot) getCurrentSnapshot())
0630: .findAssignment(resource);
0631: }
0632:
0633: public Assignment findAssignment(Task task) {
0634: return ((TaskSnapshot) getCurrentSnapshot())
0635: .findAssignment(task);
0636: }
0637:
0638: public void updateAssignment(Assignment modified) {
0639: ((TaskSnapshot) getCurrentSnapshot())
0640: .updateAssignment(modified);
0641:
0642: }
0643:
0644: public void forEachWorkingInterval(Closure visitor,
0645: boolean mergeWorking, WorkCalendar workCalendarToUse) {
0646: ((TaskSnapshot) getCurrentSnapshot()).forEachWorkingInterval(
0647: visitor, mergeWorking, workCalendarToUse);
0648: }
0649:
0650: /**
0651: * @return
0652: */
0653: public boolean isEstimated() {
0654: return estimated;
0655: }
0656:
0657: /**
0658: * Set estimated status of flag. First level parents will have their status set by the CP. Higher levels
0659: * will need to be set recursively. Note that a parent will only be asked to updated its estimated
0660: * status if one of its children has had its estimated status change.
0661: */
0662: public void setEstimated(boolean estimated) {
0663: boolean changed = this .estimated != estimated;
0664: this .estimated = estimated;
0665: if (changed && isWbsParent()) { // only deal with parents already since CP handles children and sets first parent level
0666: NormalTask parent = (NormalTask) this .getWbsParentTask();
0667: if (parent != null)
0668: parent.updateEstimatedStatus();
0669: }
0670:
0671: }
0672:
0673: private void updateEstimatedStatus() {
0674: Collection children = getWbsChildrenNodes();
0675: Iterator i = children.iterator();
0676: Object current;
0677: NormalTask child;
0678: boolean childEstimated = false;
0679: while (i.hasNext()) {
0680: current = ((Node) i.next()).getImpl();
0681: if (!(current instanceof NormalTask))
0682: continue;
0683: child = (NormalTask) current;
0684: childEstimated |= child.isEstimated();
0685: }
0686: setEstimated(childEstimated);
0687: }
0688:
0689: /**
0690: * set actual start and competion date for parents
0691: *
0692: */
0693: protected void assignParentActualDatesFromChildren() {
0694: NormalTask parent = this ;
0695: while ((parent = (NormalTask) parent.getWbsParentTask()) != null)
0696: parent.assignActualDatesFromChildren();
0697:
0698: }
0699:
0700: /**
0701: * Assigns the actual start and completed date fields of parents based on
0702: * children values
0703: *
0704: */
0705: public void assignActualDatesFromChildren() {
0706: long computedActualStart = Long.MAX_VALUE;
0707: long stop = 0;
0708: Collection children = getWbsChildrenNodes();
0709: Iterator i = children.iterator();
0710: Task child;
0711: long currentActualStart;
0712: long oldActualDuration = Duration.millis(getActualDuration());
0713: Object current;
0714: while (i.hasNext()) {
0715: current = ((Node) i.next()).getImpl();
0716: if (!(current instanceof NormalTask))
0717: continue;
0718: child = (NormalTask) current;
0719: if (!child.inProgress())
0720: continue;
0721: if ((currentActualStart = child.getActualStart()) != 0) // if any task has actual start, use the earliest value
0722: computedActualStart = Math.min(computedActualStart,
0723: currentActualStart);
0724:
0725: stop = Math.max(stop, child.getStop());
0726: }
0727:
0728: long actualDuration = 0;
0729: if (computedActualStart != Long.MAX_VALUE && stop != 0)
0730: actualDuration = getEffectiveWorkCalendar().compare(stop,
0731: getStart(), false);
0732: if (actualDuration != oldActualDuration) {
0733: double percentComplete = ((double) actualDuration)
0734: / getDurationMillis();
0735: currentSchedule.setPercentComplete(percentComplete);
0736: markTaskAsNeedingRecalculation(); // so it redraws
0737: }
0738: }
0739:
0740: /*
0741: * (non-Javadoc)
0742: *
0743: * @see com.projity.pm.task.TaskSpecificFields#taskCalendar()
0744: */
0745: public WorkCalendar getTaskCalendar() {
0746: return getWorkCalendar();
0747: }
0748:
0749: /*
0750: * (non-Javadoc)
0751: *
0752: * @see com.projity.pm.task.TaskSpecificFields#setTaskCalendar(java.lang.String)
0753: */
0754: public void setTaskCalendar(WorkCalendar taskCalendar) {
0755: if (workCalendar == taskCalendar)
0756: return;
0757: CalendarService.getInstance().reassignCalendar(this ,
0758: workCalendar, taskCalendar);
0759: setWorkCalendar(taskCalendar);
0760: invalidateAssignmentCalendars(); // assignments intersection calendars need to be recalculated
0761: }
0762:
0763: public long getBaselineStart(int numBaseline) {
0764: TaskSnapshot snapshot = ((TaskSnapshot) getSnapshot(new Integer(
0765: numBaseline)));
0766: if (snapshot == null)
0767: return 0;
0768: return snapshot.getCurrentSchedule().getStart();
0769: }
0770:
0771: public long getBaselineFinish(int numBaseline) {
0772: TaskSnapshot snapshot = ((TaskSnapshot) getSnapshot(new Integer(
0773: numBaseline)));
0774: if (snapshot == null)
0775: return 0;
0776: return snapshot.getCurrentSchedule().getEnd();
0777: }
0778:
0779: public long getBaselineDuration(int numBaseline) {
0780: TaskSnapshot snapshot = ((TaskSnapshot) getSnapshot(new Integer(
0781: numBaseline)));
0782: if (snapshot == null)
0783: return 0;
0784: return snapshot.getCurrentSchedule().getRawDuration();
0785: }
0786:
0787: public double getBaselineCost(int numBaseline, long start, long end) {
0788: TaskSnapshot snapshot = ((TaskSnapshot) getSnapshot(new Integer(
0789: numBaseline)));
0790: if (snapshot == null)
0791: return 0;
0792: return snapshot.cost(start, end);
0793: }
0794:
0795: public double getBaselineWork(int numBaseline, long start, long end) {
0796: TaskSnapshot snapshot = ((TaskSnapshot) getSnapshot(new Integer(
0797: numBaseline)));
0798: if (snapshot == null)
0799: return 0;
0800: return snapshot.work(start, end);
0801: }
0802:
0803: // public long getWork() {
0804: // DoubleSum sumFunctor = new DoubleSum() {
0805: //
0806: // protected double getValueForElement(Object object) {
0807: // return ((Assignment)object).calcAll(Assignment.WORK);
0808: // }};
0809: //
0810: // CollectionUtils.forAllDo(getAssignments(),sumFunctor);
0811: // return (long) sumFunctor.getValue();
0812: // }
0813:
0814: /*
0815: * (non-Javadoc)
0816: *
0817: * @see com.projity.pm.task.TaskSpecificFields#getResourceInitials()
0818: */
0819: public String getResourceInitials() {
0820: return AssociationListFormat
0821: .getInstance(
0822: AssignmentFormat
0823: .getInstance(AssociationFormatParameters
0824: .getInstance(
0825: this ,
0826: true,
0827: Configuration
0828: .getFieldFromId("Field.initials"),
0829: false, false))).format(
0830: getAssignments());
0831: }
0832:
0833: /*
0834: * (non-Javadoc)
0835: *
0836: * @see com.projity.pm.task.TaskSpecificFields#setResourceInitials()
0837: */
0838: public void setResourceInitials(String resourceInitials)
0839: throws FieldParseException {
0840: getAssignments()
0841: .setAssociations(
0842: resourceInitials,
0843: AssignmentFormat
0844: .getInstance(AssociationFormatParameters
0845: .getInstance(
0846: this ,
0847: true,
0848: Configuration
0849: .getFieldFromId("Field.initials"),
0850: false, false)));
0851: }
0852:
0853: /*
0854: * (non-Javadoc)
0855: *
0856: * @see com.projity.pm.task.TaskSpecificFields#getResourcePhonetics()
0857: */
0858: public String getResourcePhonetics() {
0859: return AssociationListFormat
0860: .getInstance(
0861: AssignmentFormat
0862: .getInstance(AssociationFormatParameters
0863: .getInstance(
0864: this ,
0865: true,
0866: Configuration
0867: .getFieldFromId("Field.phonetics"),
0868: false, true))).format(
0869: getAssignments());
0870:
0871: }
0872:
0873: /*
0874: * (non-Javadoc)
0875: *
0876: * @see com.projity.pm.task.TaskSpecificFields#getResourceGroup()
0877: */
0878: public String getResourceGroup() {
0879: return AssociationListFormat.getInstance(
0880: AssignmentFormat
0881: .getInstance(AssociationFormatParameters
0882: .getInstance(this , true, Configuration
0883: .getFieldFromId("Field.group"),
0884: false, false))).format(
0885: getAssignments());
0886: }
0887:
0888: /*
0889: * (non-Javadoc)
0890: *
0891: * @see com.projity.pm.task.TaskSpecificFields#getResourceNames()
0892: */
0893: public String getResourceNames() {
0894: return AssociationListFormat.getInstance(
0895: AssignmentFormat
0896: .getInstance(AssociationFormatParameters
0897: .getInstance(this , true, Configuration
0898: .getFieldFromId("Field.name"),
0899: true, true))).format(
0900: getAssignments());
0901: }
0902:
0903: /*
0904: * (non-Javadoc)
0905: *
0906: * @see com.projity.pm.task.TaskSpecificFields#setResourceNames(java.lang.String)
0907: */
0908: public void setResourceNames(String resourceNames)
0909: throws FieldParseException {
0910: getAssignments().setAssociations(
0911: resourceNames,
0912: AssignmentFormat
0913: .getInstance(AssociationFormatParameters
0914: .getInstance(this , true, Configuration
0915: .getFieldFromId("Field.name"),
0916: true, true)));
0917:
0918: }
0919:
0920: public double getUnits() {
0921: if (getAssignments().isEmpty())
0922: return 0;
0923: long duration = getDurationMillis();
0924: if (duration == 0.0)
0925: return 1.0D; // degeneratate case
0926: if (!isInitialized()) // the case when reading a file, don't boether to
0927: // calculate
0928: return 1.0;
0929: long work = calcWork();
0930: if (work == 0) // degenerate case with no work yet
0931: return 1.0;
0932: return ((double) work) / duration;
0933: }
0934:
0935: public double getRemainingUnits() {
0936: if (getAssignments().isEmpty())
0937: return 0;
0938: long duration = Duration.millis(getRemainingDuration());
0939: if (duration == 0.0)
0940: return 1.0D; // degeneratate case
0941: if (!isInitialized()) // the case when reading a file, don't boether to
0942: // calculate
0943: return 1.0;
0944: long work = getRemainingWork(null);
0945: // if (work == 0) // degenerate case with no work yet
0946: // return 1.0;
0947: return ((double) work) / duration;
0948:
0949: }
0950:
0951: public void setWork(long work, FieldContext context) {
0952:
0953: if (FieldContext.hasInterval(context)) {
0954: Iterator i = getAssignments().iterator();
0955: while (i.hasNext()) {
0956: Assignment assignment = (Assignment) i.next();
0957: assignment.setWork(work, context);
0958: }
0959: } else {
0960: setWork(work);
0961: }
0962: }
0963:
0964: public void setWork(long work) {
0965: work = Duration.millis(work);
0966: if (hasLaborAssignment() && work < 60000) {
0967: work *= Duration.timeUnitFactor(TimeUnit.HOURS);
0968: }
0969: long remainingWork = work - getActualWork(null);
0970: getSchedulingRule().adjustRemainingWork(this , remainingWork,
0971: true);
0972: }
0973:
0974: public long calcWork() {
0975: if (!hasRealAssignments()) // avoid treating dummy assignment
0976: return 0;
0977:
0978: return getWork(null);
0979: }
0980:
0981: /**
0982: * The the most highly loaded assignment's units. This is used for calculating new assignment's
0983: * units for fixed-duration effort-driven tasks
0984: * @return
0985: */
0986: public double getMostLoadedAssignmentUnits() {
0987: double result = 0;
0988: Iterator i = getAssignments().iterator();
0989: while (i.hasNext())
0990: result = Math.max(result, ((Assignment) i.next())
0991: .getLaborUnits());
0992:
0993: return result;
0994: }
0995:
0996: /*
0997: * (non-Javadoc)
0998: *
0999: * @see com.projity.pm.assignment.Allocation#adjustDuration(long)
1000: */
1001: public void adjustRemainingDuration(long newDuration,
1002: boolean doChildren) {
1003: //~~ setRawDuration(newDuration); // keep units
1004: //hk long newRemainingDuration = Duration.millis(newDuration) - getActualDuration(); // assignments dont treqt
1005: long newRemainingDuration = Duration.millis(newDuration); // - getActualDuration(); // assignments dont treqt
1006: // units
1007: Iterator i = getAssignments().iterator();
1008: while (i.hasNext())
1009: ((Assignment) i.next())
1010: .adjustRemainingDurationIfWorkingAtTaskEnd(newRemainingDuration);
1011:
1012: }
1013:
1014: /**
1015: * Called when an assignment value is modified. We want the task details to
1016: * be modified without changing the assignment details
1017: *
1018: * @param deltaAdded
1019: */
1020: public void adjustUnitsDelta(double deltaAdded) {
1021: getSchedulingRule().adjustRemainingUnits(this ,
1022: getRemainingUnits() + deltaAdded, getRemainingUnits(),
1023: false, false);
1024: }
1025:
1026: /*
1027: * (non-Javadoc)
1028: *
1029: * @see com.projity.pm.assignment.Allocation#adjustUnits(double)
1030: */
1031: public void adjustRemainingUnits(double newRemainingUnits,
1032: double oldRemainingUnits, boolean doChildren,
1033: boolean conserveTotalUnits) {
1034:
1035: if (!doChildren)
1036: return;
1037: double multiplier = 1;
1038: if (conserveTotalUnits) {
1039: multiplier = oldRemainingUnits / newRemainingUnits;
1040: }
1041:
1042: double u = newRemainingUnits;
1043: double remaining = getRemainingUnits();
1044: double factor = u / remaining;
1045: Iterator i = getAssignments().iterator();
1046: while (i.hasNext()) {
1047: Assignment assignment = (Assignment) i.next();
1048: double r = assignment.getLaborUnits();
1049: // if (!assignment.isLabor())
1050: // continue;
1051: if (conserveTotalUnits)
1052: getSchedulingRule().adjustRemainingUnits(
1053: assignment,
1054: assignment.getRemainingLaborUnits()
1055: * multiplier,
1056: assignment.getRemainingLaborUnits(), false,
1057: false);
1058: else {
1059: getSchedulingRule().adjustRemainingUnits(assignment,
1060: factor * r, r, false, false);
1061: }
1062: }
1063:
1064: }
1065:
1066: /*
1067: * (non-Javadoc)
1068: *
1069: * @see com.projity.pm.assignment.Allocation#adjustWork(double)
1070: */
1071: public void adjustRemainingWork(double multiplier,
1072: boolean doChildren) {
1073: // long newDuration = (long) (getDurationMillis() * multiplier);
1074: //~~ setRawDuration(newDuration);
1075: //need to always do children regardless of doChildren flag
1076: Iterator i = getAssignments().iterator();
1077: while (i.hasNext()) {
1078: Assignment assignment = (Assignment) i.next();
1079: if (!assignment.isLabor())
1080: continue;
1081: getSchedulingRule()
1082: .adjustRemainingWork(
1083: assignment,
1084: (long) (assignment.getRemainingWork() * multiplier),
1085: false);
1086: }
1087: }
1088:
1089: /**
1090: * Gets a (singleton) instance of the scheduling rule to use for the task
1091: *
1092: * @return scheduling rule to use in adjust...() calculations
1093: */
1094: public SchedulingRule getSchedulingRule() {
1095: return SchedulingType
1096: .getSchedulingRuleInstance(getSchedulingType());
1097:
1098: }
1099:
1100: public boolean isReadOnlyUnits(FieldContext fieldContext) {
1101: return true;
1102: }
1103:
1104: public long getCompletedThrough() {
1105: long start = getStart();
1106: if (start == 0)
1107: return 0;
1108: long actualDuration = DateTime.closestDate(getDurationMillis()
1109: * getPercentComplete());
1110: return getEffectiveWorkCalendar().add(start, actualDuration,
1111: true);
1112: }
1113:
1114: /**
1115: * Stop is the earliest completion date of the assignments
1116: * @return
1117: */
1118: public long getStop() {
1119: // if (isWbsParent( )) {
1120: // long start = getStart();
1121: // if (start == 0)
1122: // return 0;
1123: // long actualDuration = DateTime.closestDate(getDurationMillis() * getPercentComplete());
1124: // return getEffectiveWorkCalendar().add(start,actualDuration,true);
1125: // }
1126: return getEarliestStop();
1127: //&&&&&
1128: // long stop = 0;
1129: // Assignment assignment;
1130: // Iterator i = getAssignments().iterator();
1131: // while (i.hasNext()) {
1132: // assignment = (Assignment)i.next();
1133: // stop = Math.max(stop,assignment.getStop());
1134: // }
1135: // return stop;
1136: }
1137:
1138: //Used when an assignment advancement changes
1139: public void adjustActualStartFromAssignments() {
1140: Assignment assignment;
1141: Iterator i = getAssignments().iterator();
1142: long start = 0L;
1143: while (i.hasNext()) {
1144: assignment = (Assignment) i.next();
1145: if (assignment.getPercentComplete() > 0.0D) {
1146: start = getStart();
1147: break;
1148: }
1149: }
1150: // System.out.println("adjusting actual start to " + new java.util.Date(start));
1151: setActualStart(start);
1152: }
1153:
1154: /**
1155: * @param stop
1156: */
1157: public void setStop(long stop) {
1158: if (stop == getStop())
1159: return;
1160: stop = DateTime.closestDate(stop);
1161: stop = Math.min(stop, getEnd());
1162:
1163: Iterator i = getAssignments().iterator();
1164: Assignment assignment;
1165: long computedActualStart = Long.MAX_VALUE;
1166: long assignmentActualStart;
1167: while (i.hasNext()) {
1168: assignment = (Assignment) i.next();
1169: assignment.setStop(stop);
1170: assignmentActualStart = assignment.getActualStart();
1171: if (assignmentActualStart != 0
1172: && assignmentActualStart < computedActualStart)
1173: computedActualStart = assignmentActualStart;
1174: }
1175: if (computedActualStart == Long.MAX_VALUE)
1176: computedActualStart = 0;
1177: setActualStart(computedActualStart);
1178: assignParentActualDatesFromChildren();
1179:
1180: // if % complete went down to 0, then the plan changed and need to recalculate all.
1181: if (computedActualStart == 0) {
1182: getDocument().getObjectEventManager().fireUpdateEvent(this ,
1183: this , Configuration.getFieldFromId("Field.start"));
1184: } else {
1185: //TODO duplicate event
1186: //TODO in the case of progress update this event is useless since critical path runs after.
1187: getProject().fireScheduleChanged(this ,
1188: ScheduleEvent.ACTUAL, this );
1189: }
1190:
1191: }
1192:
1193: /**
1194: * @return
1195: */
1196: public long getResume() {
1197: long resume = Long.MAX_VALUE;
1198: Assignment assignment;
1199: Iterator i = getAssignments().iterator();
1200: while (i.hasNext()) {
1201: assignment = (Assignment) i.next();
1202: resume = Math.min(resume, assignment.getResume());
1203: }
1204: return resume;
1205: }
1206:
1207: /**
1208: * @param resume
1209: */
1210: public void setResume(long resume) {
1211: Assignment assignment;
1212: Iterator i = getAssignments().iterator();
1213: while (i.hasNext()) {
1214: assignment = (Assignment) i.next();
1215: assignment.setResume(resume);
1216: }
1217: }
1218:
1219: private void setStopNoExtend(long stop) {
1220: //TODO figure out
1221: long start = getStart();
1222: if (stop < start) {// don't allow completion before start
1223: setActualDuration(0);
1224: stop = start;
1225: } else {
1226: long duration = getEffectiveWorkCalendar().compare(stop,
1227: start, false);
1228: duration = Math.min(duration, getDurationMillis()); // don't ever
1229: // change finish
1230: setActualDuration(duration);
1231: }
1232: // scheduleWindow.setStop(stop);
1233: }
1234:
1235: /***************************************************************************
1236: * TimeDistributedData T********
1237: **************************************************************************/
1238: /**
1239: * For parent tasks, we don't want to count their one day of work
1240: */
1241: private boolean isParentWithoutAssignments() {
1242: return (isWbsParent() && !hasRealAssignments());
1243: }
1244:
1245: public double cost(long start, long end) {
1246: if (isParentWithoutAssignments())
1247: return 0.0D;
1248: return ((TaskSnapshot) getCurrentSnapshot()).cost(start, end);
1249: }
1250:
1251: public long work(long start, long end) {
1252: if (isParentWithoutAssignments())
1253: return 0L;
1254: return ((TaskSnapshot) getCurrentSnapshot()).work(start, end);
1255: }
1256:
1257: public double actualCost(long start, long end) {
1258: if (isParentWithoutAssignments())
1259: return 0.0D;
1260:
1261: return ((TaskSnapshot) getCurrentSnapshot()).actualCost(start,
1262: end);
1263: }
1264:
1265: public long actualWork(long start, long end) {
1266: if (isParentWithoutAssignments())
1267: return 0L;
1268: return ((TaskSnapshot) getCurrentSnapshot()).actualWork(start,
1269: end);
1270: }
1271:
1272: public long remainingWork(long start, long end) {
1273: if (isParentWithoutAssignments())
1274: return 0L;
1275: return ((TaskSnapshot) getCurrentSnapshot()).remainingWork(
1276: start, end);
1277: }
1278:
1279: public double baselineCost(long start, long end) {
1280: if (getBaselineSnapshot() == null)
1281: return 0;
1282:
1283: return getBaselineSnapshot().cost(start, end);
1284: }
1285:
1286: public long baselineWork(long start, long end) {
1287: if (getBaselineSnapshot() == null)
1288: return 0;
1289: return getBaselineSnapshot().work(start, end);
1290: }
1291:
1292: /***************************************************************************
1293: * EarnedValueValues
1294: **************************************************************************/
1295:
1296: public double acwp(long start, long end) {
1297: return ((TaskSnapshot) getCurrentSnapshot()).acwp(start, end);
1298: }
1299:
1300: public double bac(long start, long end) {
1301: return ((TaskSnapshot) getCurrentSnapshot()).bac(start, end);
1302: }
1303:
1304: public double bcwp(long start, long end) {
1305: return ((TaskSnapshot) getCurrentSnapshot()).bcwp(start, end);
1306: }
1307:
1308: public double bcws(long start, long end) {
1309: return ((TaskSnapshot) getCurrentSnapshot()).bcws(start, end);
1310: }
1311:
1312: boolean isInRange(long start, long finish) {
1313: long s = getStart();
1314: return (finish > s && start < getEnd());
1315: }
1316:
1317: private boolean isFieldHidden(FieldContext fieldContext) {
1318: return fieldContext != null
1319: && !isInRange(fieldContext.getStart(), fieldContext
1320: .getEnd());
1321: }
1322:
1323: private boolean isBaselineFieldHidden(int numBaseline,
1324: FieldContext fieldContext) {
1325: TaskSnapshot baseline = (TaskSnapshot) getSnapshot(new Integer(
1326: numBaseline));
1327: if (baseline == null)
1328: return true;
1329:
1330: if (fieldContext == null) // the baseline exists, but no time range
1331: return false;
1332: return (fieldContext.getStart() >= baseline
1333: .getCurrentSchedule().getFinish() || fieldContext
1334: .getEnd() <= baseline.getCurrentSchedule().getStart());
1335: }
1336:
1337: private boolean isEarnedValueFieldHidden(FieldContext fieldContext) {
1338: if (isFieldHidden(fieldContext))
1339: return true;
1340: if (fieldContext == null)
1341: return false;
1342: return project.getStatusDate() < fieldContext.getStart();
1343: }
1344:
1345: /***************************************************************************
1346: * Time Distributed Fields
1347: **************************************************************************/
1348: public boolean fieldHideCost(FieldContext fieldContext) {
1349: return isFieldHidden(fieldContext);
1350: }
1351:
1352: public boolean fieldHideWork(FieldContext fieldContext) {
1353: return isFieldHidden(fieldContext);
1354: }
1355:
1356: public boolean fieldHideActualCost(FieldContext fieldContext) {
1357: return isFieldHidden(fieldContext);
1358: }
1359:
1360: public boolean fieldHideActualWork(FieldContext fieldContext) {
1361: return isFieldHidden(fieldContext);
1362: }
1363:
1364: public boolean fieldHideBaselineCost(int numBaseline,
1365: FieldContext fieldContext) {
1366: return isBaselineFieldHidden(numBaseline, fieldContext);
1367: }
1368:
1369: public boolean fieldHideBaselineWork(int numBaseline,
1370: FieldContext fieldContext) {
1371: return isBaselineFieldHidden(numBaseline, fieldContext);
1372: }
1373:
1374: public boolean fieldHideAcwp(FieldContext fieldContext) {
1375: return isFieldHidden(fieldContext);
1376: }
1377:
1378: public boolean fieldHideBac(FieldContext fieldContext) {
1379: return isFieldHidden(fieldContext);
1380: }
1381:
1382: public boolean fieldHideBcwp(FieldContext fieldContext) {
1383: return isEarnedValueFieldHidden(fieldContext);
1384: }
1385:
1386: public boolean fieldHideBcws(FieldContext fieldContext) {
1387: return isEarnedValueFieldHidden(fieldContext);
1388: }
1389:
1390: public boolean fieldHideCv(FieldContext fieldContext) {
1391: return isFieldHidden(fieldContext);
1392: }
1393:
1394: public boolean fieldHideSv(FieldContext fieldContext) {
1395: return isFieldHidden(fieldContext);
1396: }
1397:
1398: public boolean fieldHideEac(FieldContext fieldContext) {
1399: return isFieldHidden(fieldContext);
1400: }
1401:
1402: public boolean fieldHideVac(FieldContext fieldContext) {
1403: return isFieldHidden(fieldContext);
1404: }
1405:
1406: public boolean fieldHideCpi(FieldContext fieldContext) {
1407: return isFieldHidden(fieldContext);
1408: }
1409:
1410: public boolean fieldHideSpi(FieldContext fieldContext) {
1411: return isFieldHidden(fieldContext);
1412: }
1413:
1414: public boolean fieldHideCvPercent(FieldContext fieldContext) {
1415: return isFieldHidden(fieldContext);
1416: }
1417:
1418: public boolean fieldHideSvPercent(FieldContext fieldContext) {
1419: return isFieldHidden(fieldContext);
1420: }
1421:
1422: public boolean fieldHideTcpi(FieldContext fieldContext) {
1423: return isFieldHidden(fieldContext);
1424: }
1425:
1426: public double getCost(FieldContext fieldContext) {
1427: return getFixedCost(fieldContext)
1428: + cost(FieldContext.start(fieldContext), FieldContext
1429: .end(fieldContext));
1430: }
1431:
1432: public long getWork(FieldContext fieldContext) {
1433: return work(FieldContext.start(fieldContext), FieldContext
1434: .end(fieldContext));
1435: }
1436:
1437: public double getActualFixedCost(FieldContext fieldContext) {
1438: return fixedCost(FieldContext.start(fieldContext), Math.min(
1439: getStop(), FieldContext // only up to completion
1440: .end(fieldContext)));
1441: }
1442:
1443: public double getFixedCost(FieldContext fieldContext) {
1444: if (!FieldContext.hasInterval(fieldContext))
1445: return ((TaskSnapshot) getCurrentSnapshot()).getFixedCost();
1446:
1447: return fixedCost(FieldContext.start(fieldContext), FieldContext
1448: .end(fieldContext));
1449: }
1450:
1451: public double actualFixedCost(long start, long end) {
1452: return fixedCost(start, Math.min(getStop(), end));
1453: }
1454:
1455: /** Calculate the fixed cost for the task given its accrual type and percent complete
1456: */
1457: public double fixedCost(long start, long end) {
1458: long taskStart = getStart();
1459: long taskEnd = getEnd();
1460: double fixed = 0.0;
1461: double fixedCost = getFixedCost();
1462: if (getFixedCostAccrual() == Accrual.START) {
1463: if (taskStart >= start && taskStart <= end) // if task starts in this range
1464: fixed = fixedCost;
1465: } else if (getFixedCostAccrual() == Accrual.PRORATED) {
1466: // find overlapping actual time
1467: start = Math.max(start, taskStart);
1468: end = Math.min(end, taskEnd);
1469: if (start < end) { // if valid range
1470: long overlappingDuration = getEffectiveWorkCalendar()
1471: .compare(end, start, false);
1472: double fraction = ((double) overlappingDuration)
1473: / getDurationMillis();
1474: fixed = fixedCost * fraction;
1475: }
1476: } else { // END accrual by default
1477: if (taskEnd >= start && taskEnd <= end) // if task ends in this range
1478: fixed = fixedCost;
1479: }
1480: return fixed;
1481: }
1482:
1483: public boolean fieldHideActualFixedCost(FieldContext fieldContext) {
1484: return false;
1485: }
1486:
1487: public double getActualCost(FieldContext fieldContext) {
1488: return getActualFixedCost(fieldContext)
1489: + actualCost(FieldContext.start(fieldContext),
1490: FieldContext.end(fieldContext));
1491: }
1492:
1493: public long getActualWork(FieldContext fieldContext) {
1494: return actualWork(FieldContext.start(fieldContext),
1495: FieldContext.end(fieldContext));
1496: }
1497:
1498: public long getRemainingWork(FieldContext fieldContext) {
1499: return remainingWork(FieldContext.start(fieldContext),
1500: FieldContext.end(fieldContext));
1501: }
1502:
1503: public long getRemainingWork() {
1504: return getRemainingWork(null);
1505: }
1506:
1507: public double getRemainingCost(FieldContext fieldContext) {
1508: return getCost(fieldContext) - getActualCost(fieldContext);
1509: }
1510:
1511: //Baseline versions
1512: public double getBaselineCost(int numBaseline,
1513: FieldContext fieldContext) {
1514: TaskSnapshot snapshot = (TaskSnapshot) getSnapshot(new Integer(
1515: numBaseline));
1516: if (snapshot == null)
1517: return 0.0D;
1518: return ((TaskSnapshot) getSnapshot(new Integer(numBaseline)))
1519: .cost(FieldContext.start(fieldContext), FieldContext
1520: .end(fieldContext));
1521: }
1522:
1523: public long getBaselineWork(int numBaseline,
1524: FieldContext fieldContext) {
1525: TaskSnapshot snapshot = (TaskSnapshot) getSnapshot(new Integer(
1526: numBaseline));
1527: if (snapshot == null)
1528: return 0L;
1529: return ((TaskSnapshot) getSnapshot(new Integer(numBaseline)))
1530: .work(FieldContext.start(fieldContext), FieldContext
1531: .end(fieldContext));
1532: }
1533:
1534: /***************************************************************************
1535: * Earned Value Fields
1536: **************************************************************************/
1537: public double getAcwp(FieldContext fieldContext) {
1538: return acwp(FieldContext.start(fieldContext), FieldContext
1539: .end(fieldContext));
1540: }
1541:
1542: public double getBac(FieldContext fieldContext) {
1543: return bac(FieldContext.start(fieldContext), FieldContext
1544: .end(fieldContext));
1545: }
1546:
1547: public double getBcwp(FieldContext fieldContext) {
1548: return bcwp(FieldContext.start(fieldContext), FieldContext
1549: .end(fieldContext));
1550: }
1551:
1552: public double getBcws(FieldContext fieldContext) {
1553: return bcws(FieldContext.start(fieldContext), FieldContext
1554: .end(fieldContext));
1555: }
1556:
1557: public double getCv(FieldContext fieldContext) {
1558: return EarnedValueCalculator.getInstance().cv(this ,
1559: FieldContext.start(fieldContext),
1560: FieldContext.end(fieldContext));
1561: }
1562:
1563: public double getSv(FieldContext fieldContext) {
1564: return EarnedValueCalculator.getInstance().sv(this ,
1565: FieldContext.start(fieldContext),
1566: FieldContext.end(fieldContext));
1567: }
1568:
1569: public double getEac(FieldContext fieldContext) {
1570: return EarnedValueCalculator.getInstance().eac(this ,
1571: FieldContext.start(fieldContext),
1572: FieldContext.end(fieldContext));
1573: }
1574:
1575: public double getVac(FieldContext fieldContext) {
1576: return EarnedValueCalculator.getInstance().vac(this ,
1577: FieldContext.start(fieldContext),
1578: FieldContext.end(fieldContext));
1579: }
1580:
1581: public double getCpi(FieldContext fieldContext) {
1582: return EarnedValueCalculator.getInstance().cpi(this ,
1583: FieldContext.start(fieldContext),
1584: FieldContext.end(fieldContext));
1585: }
1586:
1587: public double getSpi(FieldContext fieldContext) {
1588: return EarnedValueCalculator.getInstance().spi(this ,
1589: FieldContext.start(fieldContext),
1590: FieldContext.end(fieldContext));
1591: }
1592:
1593: public double getCsi(FieldContext fieldContext) {
1594: return EarnedValueCalculator.getInstance().csi(this ,
1595: FieldContext.start(fieldContext),
1596: FieldContext.end(fieldContext));
1597: }
1598:
1599: public double getCvPercent(FieldContext fieldContext) {
1600: return EarnedValueCalculator.getInstance().cvPercent(this ,
1601: FieldContext.start(fieldContext),
1602: FieldContext.end(fieldContext));
1603: }
1604:
1605: public double getSvPercent(FieldContext fieldContext) {
1606: return EarnedValueCalculator.getInstance().svPercent(this ,
1607: FieldContext.start(fieldContext),
1608: FieldContext.end(fieldContext));
1609: }
1610:
1611: public double getTcpi(FieldContext fieldContext) {
1612: return EarnedValueCalculator.getInstance().tcpi(this ,
1613: FieldContext.start(fieldContext),
1614: FieldContext.end(fieldContext));
1615: }
1616:
1617: /*
1618: * (non-Javadoc)
1619: *
1620: * @see com.projity.pm.assignment.HasAssignments#calcDataBetween(java.lang.Object,
1621: * com.projity.algorithm.TimeIteratorGenerator,
1622: * com.projity.algorithm.CalculatedValues)
1623: */
1624: public void calcDataBetween(Object type,
1625: TimeIteratorGenerator generator, CalculatedValues values) {
1626: ((TaskSnapshot) getCurrentSnapshot()).calcDataBetween(type,
1627: generator, values);
1628:
1629: }
1630:
1631: public void setPercentComplete(double percentComplete) {
1632: if (percentComplete > 1.0) {
1633: System.out.println("percent complete more than 100%");
1634: percentComplete = 1.0;
1635: } else if (percentComplete < 0) {
1636: System.out.println("percent complete less than 0%");
1637: percentComplete = 0.0;
1638: }
1639:
1640: long actualDuration = DateTime.closestDate(getDurationMillis()
1641: * percentComplete);
1642: setActualDuration(actualDuration);
1643: long stop = getEffectiveWorkCalendar().add(getStart(),
1644: actualDuration, false);
1645: DeepChildWalker.recursivelyTreatBranch(getProject()
1646: .getTaskOutline(), this , new NumberClosure(stop) {
1647: public void execute(Object arg0) {
1648: if (arg0 == null) {
1649: return;
1650: }
1651: Object nodeObject = ((Node) arg0).getImpl();
1652: if (nodeObject instanceof NormalTask) { // do not treat assignments
1653: NormalTask task = ((NormalTask) nodeObject);
1654: task.setStop(Math.min(longValue(), task.getEnd())); // do within range of task
1655: }
1656: }
1657: });
1658: }
1659:
1660: /*
1661: * (non-Javadoc)
1662: *
1663: * @see com.projity.pm.task.TaskSpecificFields#getPercentWorkComplete()
1664: */
1665: public double getPercentWorkComplete() {
1666: // NodeModel nodeModel = getProject().getTaskOutline();
1667: // Node node = nodeModel.search(this);
1668: // Number value = (Number)
1669: // Configuration.getFieldFromId("Field.work").getValue(node,nodeModel,null);
1670: // if (value.doubleValue() == 0)
1671: // return 0;
1672: // Number actualValue = (Number)
1673: // Configuration.getFieldFromId("Field.actualWork").getValue(node,nodeModel,null);
1674: // return actualValue.doubleValue() / value.doubleValue();
1675: long work = calcSummedWork();
1676: if (work == 0)
1677: return 0;
1678: else
1679: return ((double) calcSummedActualWork()) / work;
1680: }
1681:
1682: private long calcSummedWork() {
1683: NodeModel nodeModel = getProject().getTaskOutline();
1684: Node node = nodeModel.search(this );
1685: if (node == null)
1686: return 0;
1687: Number value = (Number) Configuration.getFieldFromId(
1688: "Field.work").getValue(node, nodeModel, null);
1689: return value.longValue();
1690: }
1691:
1692: private long calcSummedActualWork() {
1693: NodeModel nodeModel = getProject().getTaskOutline();
1694: Node node = nodeModel.search(this );
1695: Number value = (Number) Configuration.getFieldFromId(
1696: "Field.actualWork").getValue(node, nodeModel, null);
1697: return value.longValue();
1698: }
1699:
1700: /*
1701: * (non-Javadoc)
1702: *
1703: * @see com.projity.pm.task.TaskSpecificFields#setPercentWorkComplete(double)
1704: */
1705: public void setPercentWorkComplete(double percentWorkComplete) {
1706: if (percentWorkComplete < 0)
1707: percentWorkComplete = 0;
1708: if (percentWorkComplete > 1)
1709: percentWorkComplete = 1;
1710: double workValue = percentWorkComplete * calcSummedWork();
1711: // System.out.println("work value is " +
1712: // DurationFormat.format((long)workValue) +" get work null is " +
1713: // DurationFormat.format(calcSummedWork()));
1714:
1715: long date = ReverseQuery.getDateAtValue(WORK, this , workValue,
1716: true); // allow use of default assignments
1717: DeepChildWalker.recursivelyTreatBranch(getProject()
1718: .getTaskOutline(), this , new NumberClosure(date) {
1719: public void execute(Object arg0) {
1720: if (arg0 == null)
1721: return;
1722: Object nodeObject = ((Node) arg0).getImpl();
1723: if (nodeObject instanceof NormalTask) // do not treat assignments
1724: ((NormalTask) nodeObject)
1725: .setStopNoExtend(getLongValue());
1726: }
1727: });
1728:
1729: }
1730:
1731: // /*
1732: // * (non-Javadoc)
1733: // *
1734: // * @see com.projity.pm.criticalpath.ScheduleWindow#getScheduleChildren()
1735: // */
1736: // public Collection getScheduleChildren() {
1737: // return getWbsChildrenNodes();
1738: // }
1739:
1740: /**
1741: * Cleans up all links to and form this task and removes all assignments,
1742: * including baseline ones.
1743: *
1744: * @param eventSource -
1745: * if not null, then events will be sent indicating the removal
1746: * of links and assignments
1747: */
1748: void cleanUp(Object eventSource, boolean deep, boolean undo,
1749: boolean cleanDependencies) {
1750: super .cleanUp(eventSource, deep, undo, cleanDependencies); // gets rid of dependencies
1751:
1752: // for all snapshots
1753: if (deep) {
1754: TaskSnapshot snapshot;
1755: for (int i = 0; i < Settings.numBaselines(); i++) {
1756: Integer snapshotId = new Integer(i);
1757: snapshot = (TaskSnapshot) getSnapshot(snapshotId);
1758: if (snapshot != null) {
1759: // send events only for current snapshot
1760: Object useEventSource = (getCurrentSnapshot() == snapshot) ? eventSource
1761: : null;
1762:
1763: LinkedList toRemove = new LinkedList(); //fix
1764: AssignmentService.getInstance().remove(
1765: snapshot.getAssignments(), toRemove);
1766: AssignmentService.getInstance().remove(toRemove,
1767: useEventSource, false);
1768:
1769: if (snapshot != getCurrentSnapshot())
1770: getProject().fireBaselineChanged(eventSource,
1771: this , snapshotId, false);
1772: }
1773:
1774: }
1775: }
1776: }
1777:
1778: /*
1779: * (non-Javadoc)
1780: *
1781: * @see com.projity.pm.assignment.HasTimeDistributedData#childrenToRollup()
1782: */
1783: public Collection childrenToRollup() {
1784: return ((TaskSnapshot) getCurrentSnapshot())
1785: .getHasAssignments().childrenToRollup();
1786: }
1787:
1788: // some functions useful for API
1789: public double getCost() {
1790: return getCost(null);
1791: }
1792:
1793: public double getBaselineCost() {
1794: return getBaselineCost(0, null);
1795: }
1796:
1797: public double getBaselineCost(int number) {
1798: return getBaselineCost(number, null);
1799: }
1800:
1801: public double getWork() {
1802: return getWork(null);
1803: }
1804:
1805: public double getBaselineWork() {
1806: return getBaselineWork(0, null);
1807: }
1808:
1809: public double getBaselineWork(int number) {
1810: return getBaselineWork(number, null);
1811: }
1812:
1813: /**
1814: * Useful for drawing bars
1815: */
1816: public long getTotalSlackStart() {
1817: return (getConstraintType() == ConstraintType.ALAP) ? getEarlyStart()
1818: : getEarlyFinish();
1819:
1820: }
1821:
1822: /**
1823: * Useful for drawing bars
1824: */
1825: public long getTotalSlackEnd() {
1826: return (getConstraintType() == ConstraintType.ALAP) ? getLateStart()
1827: : getLateFinish();
1828: }
1829:
1830: /**
1831: * Offset the given date by the duration of the remaining duration.
1832: */
1833: public long calcOffsetFrom(long startDate, long dependencyDate,
1834: boolean ahead, boolean remainingOnly, boolean useSooner) {
1835:
1836: // This is a task based implementation- for parents dont use their assignments
1837: if (isWbsParent()) {
1838: long d = remainingOnly ? Duration
1839: .millis(getRemainingDuration())
1840: : getDurationMillis();
1841: if (!ahead)
1842: d = -d;
1843: return getEffectiveWorkCalendar().add(startDate, d,
1844: useSooner);
1845: }
1846: //
1847: //
1848: // This is an assignment based implementation
1849:
1850: Iterator i = getAssignments().iterator();
1851: long result;
1852: Assignment assignment;
1853: if (startDate < 0)
1854: result = ahead ? Long.MIN_VALUE : 0;
1855: else
1856: result = ahead ? 0 : Long.MAX_VALUE;
1857: while (i.hasNext()) {
1858: assignment = (Assignment) i.next();
1859: long offsetDate = assignment.calcOffsetFrom(startDate,
1860: dependencyDate, ahead, remainingOnly, useSooner);
1861: result = ahead ? Math.max(result, offsetDate) : Math.min(
1862: result, offsetDate);
1863: }
1864: return result;
1865: }
1866:
1867: /* (non-Javadoc)
1868: * @see com.projity.pm.assignment.HasAssignments#calcActiveAssignmentDuration(com.projity.pm.calendar.WorkCalendar)
1869: */
1870: public long calcActiveAssignmentDuration(
1871: WorkCalendar workCalendarToUse) {
1872: return ((TaskSnapshot) getCurrentSnapshot())
1873: .calcActiveAssignmentDuration(workCalendarToUse);
1874: }
1875:
1876: /**
1877: * Move remaining work to date - used when doing a project update for this task
1878: */
1879: public void moveRemainingToDate(long date) {
1880: date = getEffectiveWorkCalendar().adjustInsideCalendar(date,
1881: false);
1882: if (getActualStart() == 0L)
1883: setStart(date); // if not started, change start
1884: else if (inProgress()) {
1885: Iterator i = getAssignments().iterator();
1886: Assignment assignment;
1887: while (i.hasNext()) {
1888: assignment = (Assignment) i.next();
1889: assignment.moveRemainingToDate(date);
1890: }
1891: } // do nothing for completed tasks
1892: }
1893:
1894: /* (non-Javadoc)
1895: * @see com.projity.pm.scheduling.Schedule#moveInterval(java.lang.Object, long, long, com.projity.pm.scheduling.ScheduleInterval)
1896: */
1897: public void moveInterval(Object eventSource, long start, long end,
1898: ScheduleInterval oldInterval, boolean isChild) {
1899: WorkCalendar cal = getEffectiveWorkCalendar();
1900: start = cal.adjustInsideCalendar(start, false);
1901: boolean shifting = cal.compare(start, oldInterval.getStart(),
1902: false) != 0;
1903: long assignmentStart = getEarliestAssignmentStart();
1904: long amountFromStart = cal.compare(oldInterval.getStart(),
1905: assignmentStart, false); // possible that they are not the same but there is no working time between them
1906: if (shifting && amountFromStart == 0L) { // see if first bar shifted -The first bar is drawn from the first assignment and not from the task start.
1907: // To figure out the new task start, see how much the shift of this bar is, then apply that difference to the task start
1908: long shift = cal.compare(start, assignmentStart, false);
1909: long newTaskStart = cal.add(getStart(), shift, false);
1910: setStart(newTaskStart);
1911: } else {
1912: long amount = cal.compare(end, oldInterval.getEnd(), false);
1913: if (amount == 0L) // skip if nothing moved
1914: return;
1915:
1916: Iterator i = getAssignments().iterator();
1917: Assignment assignment;
1918: while (i.hasNext()) {
1919: assignment = (Assignment) i.next();
1920: assignment.moveInterval(eventSource, start, end,
1921: oldInterval, true);
1922: }
1923: }
1924: setRawDuration(getDurationMillis()); // this fixes all sorts of pbs
1925:
1926: recalculate(eventSource); // need to recalculate
1927: assignParentActualDatesFromChildren();
1928:
1929: // //Undo
1930: // UndoableEditSupport undoableEditSupport=getProject().getUndoController().getEditSupport();
1931: // if (undoableEditSupport!=null&&!(eventSource instanceof UndoableEdit)){
1932: // undoableEditSupport.postEdit(new ScheduleEdit(this,new ScheduleInterval(start,end),oldInterval,isChild,eventSource));
1933: // }
1934:
1935: }
1936:
1937: /* (non-Javadoc)
1938: * @see com.projity.pm.scheduling.Schedule#split(java.lang.Object, long, long)
1939: */
1940: public void split(Object eventSource, long from, long to) {
1941: from = getEffectiveWorkCalendar().adjustInsideCalendar(from,
1942: false);
1943: to = getEffectiveWorkCalendar().adjustInsideCalendar(to, false);
1944:
1945: if (from == to) { // if from is same as two, split one day
1946: to = getEffectiveWorkCalendar().add(from,
1947: CalendarOption.getInstance().getMillisPerDay(),
1948: false);
1949: }
1950:
1951: Iterator i = getAssignments().iterator();
1952: Assignment assignment;
1953: while (i.hasNext()) {
1954: assignment = (Assignment) i.next();
1955: assignment.split(eventSource, from, to);
1956: }
1957: recalculate(eventSource); // need to recalculate
1958: assignParentActualDatesFromChildren();
1959:
1960: }
1961:
1962: protected transient static BarClosure barClosureInstance = new BarClosure();
1963:
1964: public void consumeIntervals(IntervalConsumer consumer) {
1965: if (isWbsParent() || isSubproject()) { //TODO this shouldn't be needed since default assignment should be ok. See why
1966: consumer.consumeInterval(new ScheduleInterval(getStart(),
1967: getEnd()));
1968: return;
1969: }
1970: barClosureInstance.initialize(consumer, this );
1971: forEachWorkingInterval(barClosureInstance, true,
1972: getEffectiveWorkCalendar());
1973:
1974: // Below is a hack to prevent hanging on void node promotion
1975: if (barClosureInstance.getCount() == 0) { // if no bars drawn
1976: consumer.consumeInterval(new ScheduleInterval(getStart(),
1977: getEnd()));
1978: }
1979: }
1980:
1981: /**
1982: * Overloads task setEnd but calls it
1983: */
1984: public void setEnd(long end) {
1985: long start = getStart();
1986: if (start == 0) { // if the end date is entered on a new line creating the task need to set the start correctly
1987: start = CalendarOption.getInstance().makeValidStart(
1988: DateTime.midnightToday(), true);
1989: getCurrentSchedule().setStart(start);
1990: }
1991: end = CalendarOption.getInstance().makeValidEnd(end, true);
1992: if (end < start)
1993: end = start;
1994: long oldEnd = getEnd();
1995: if (end != oldEnd) {
1996: super .setEnd(end);
1997: Iterator i = getAssignments().iterator();
1998: Assignment assignment;
1999: while (i.hasNext()) {
2000: assignment = (Assignment) i.next();
2001: assignment.setEnd(end);
2002: }
2003: // System.out.println("Old End" + new Date(oldEnd) + " input end " + new Date(end )+ " resulting End " + new Date(getEnd()) + " duration " + DurationFormat.format(getDuration()));
2004: setRawDuration(getDurationMillis());
2005: }
2006: assignParentActualDatesFromChildren();
2007: }
2008:
2009: /**
2010: * @param actualStart
2011: */
2012: public void setActualStart(long actualStart) {
2013: actualStart = getEffectiveWorkCalendar().adjustInsideCalendar(
2014: actualStart, false); //TODO not good if it starts off calendar
2015:
2016: setActualStartNoEvent(actualStart);
2017: markTaskAsNeedingRecalculation();
2018: getProject().fireScheduleChanged(this , ScheduleEvent.ACTUAL,
2019: this );
2020: }
2021:
2022: public void setActualStartNoEvent(long actualStart) {
2023: long old = getActualStart();
2024: if (actualStart == old)
2025: return;
2026: // if (actualStart != 0) {
2027: // if (getPercentComplete() == 0) {
2028: // currentSchedule.setPercentComplete(INSTANT_COMPLETION);
2029: // setPercentComplete(INSTANT_COMPLETION);
2030: // }
2031: // currentSchedule.setStart(actualStart);
2032: // }
2033: this .actualStart = actualStart;
2034: assignParentActualDatesFromChildren();
2035:
2036: }
2037:
2038: /* (non-Javadoc)
2039: * @see com.projity.pm.task.TaskSpecificFields#isIgnoreResourceCalendar()
2040: */
2041: public boolean isIgnoreResourceCalendar() {
2042: return ((TaskSnapshot) getCurrentSnapshot())
2043: .isIgnoreResourceCalendar();
2044: }
2045:
2046: /* (non-Javadoc)
2047: * @see com.projity.pm.task.TaskSpecificFields#setIgnoreResourceCalendar(boolean)
2048: */
2049: public void setIgnoreResourceCalendar(boolean ignoreResourceCalendar) {
2050: ((TaskSnapshot) getCurrentSnapshot())
2051: .setIgnoreResourceCalendar(ignoreResourceCalendar);
2052: }
2053:
2054: public boolean isDefault() {
2055: return this == UNASSIGNED;
2056: }
2057:
2058: private static short DEFAULT_VERSION = 2;
2059: private short version = DEFAULT_VERSION;
2060:
2061: public short getVersion() {
2062: return version;
2063: }
2064:
2065: /* The serialization version must be private. This lets subclasses call this code */
2066: protected void doWriteObject(ObjectOutputStream s)
2067: throws IOException {
2068: s.defaultWriteObject();
2069: hasKey.serialize(s);
2070: customFields.serialize(s);
2071: if (version < 1)
2072: currentSchedule.serialize(s);
2073: else {
2074: int sCount = 0;
2075: for (int i = 0; i < Settings.numBaselines(); i++) {
2076: TaskSnapshot snapshot = (TaskSnapshot) getSnapshot(new Integer(
2077: i));
2078: if (snapshot != null)
2079: sCount++;
2080: }
2081: s.writeInt(sCount);
2082: for (int i = 0; i < Settings.numBaselines(); i++) {
2083: TaskSnapshot snapshot = (TaskSnapshot) getSnapshot(new Integer(
2084: i));
2085: if (snapshot == null)
2086: continue;
2087: s.writeInt(i);
2088: snapshot.serialize(s);
2089: }
2090: }
2091: }
2092:
2093: private void writeObject(ObjectOutputStream s) throws IOException {
2094: doWriteObject(s);
2095: }
2096:
2097: private void readObject(ObjectInputStream s) throws IOException,
2098: ClassNotFoundException {
2099: s.defaultReadObject();
2100:
2101: hasKey = HasKeyImpl.deserialize(s, this );
2102: customFields = CustomFieldsImpl.deserialize(s);
2103: if (version < 1)
2104: currentSchedule = TaskSchedule.deserialize(s);
2105: else {
2106: snapshots = new SnapshottableImpl(Settings.numBaselines());
2107: int sCount = s.readInt();
2108: for (int i = 0; i < sCount; i++) {
2109: int snapshotId = s.readInt();
2110: TaskSnapshot snapshot = TaskSnapshot.deserialize(s,
2111: this );
2112: setSnapshot(new Integer(snapshotId), snapshot);
2113: }
2114: }
2115:
2116: if (version < 1)
2117: super .initializeTransientTaskObjects();
2118: else
2119: super .initializeTransientTaskObjectsAfterDeserialization();
2120: // barClosureInstance = new BarClosure();
2121: // This shouldn't be called -hk 4/feb/05
2122: // initializeDates();
2123:
2124: version = DEFAULT_VERSION;
2125: }
2126:
2127: public Object clone() {
2128: Task task = (Task) super .clone();
2129: // task.barClosureInstance = new BarClosure();
2130:
2131: return task;
2132: }
2133:
2134: public void cloneTo(Task task) {
2135: if (task instanceof NormalTask) {
2136: NormalTask n = (NormalTask) task;
2137: n.estimated = estimated;
2138: n.priority = priority;
2139: n.version = version;
2140: n.workCalendar = workCalendar;
2141: }
2142:
2143: super .cloneTo(task);
2144: }
2145:
2146: public void serialize(ObjectOutputStream s) throws IOException {
2147: }
2148:
2149: public boolean isReadOnlyWork(FieldContext fieldContext) {
2150: if (!hasLaborAssignment())
2151: return true;
2152: if (fieldContext == null)
2153: return false;
2154: return !hasActiveAssignment(fieldContext.getStart(),
2155: fieldContext.getEnd());
2156: }
2157:
2158: public void setActualWork(long actualWork, FieldContext context) {
2159:
2160: if (FieldContext.hasInterval(context)) {
2161: Iterator i = getAssignments().iterator();
2162: while (i.hasNext()) {
2163: Assignment assignment = (Assignment) i.next();
2164: assignment.setActualWork(actualWork, context);
2165: }
2166: } else {
2167: long workValue = Duration.millis(actualWork);
2168: if (workValue == 0L) {
2169: setPercentComplete(0);
2170: } else {
2171: long date = ReverseQuery.getDateAtValue(WORK, this ,
2172: workValue, false);
2173: setStop(date);
2174: }
2175: }
2176: }
2177:
2178: public boolean isReadOnlyActualWork(FieldContext fieldContext) {
2179: return false;
2180: }
2181:
2182: public void setRemainingWork(long remainingWork,
2183: FieldContext fieldContext) {
2184: setActualWork(getWork(fieldContext)
2185: - Duration.millis(remainingWork), fieldContext);
2186: }
2187:
2188: public boolean isReadOnlyRemainingWork(FieldContext fieldContext) {
2189: return isReadOnlyWork(fieldContext);
2190: }
2191:
2192: /* (non-Javadoc)
2193: * @see com.projity.pm.assignment.TimeDistributedFields#setFixedCost(double, com.projity.field.FieldContext)
2194: */
2195: public void setFixedCost(double fixedCost, FieldContext fieldContext) {
2196: if (!FieldContext.hasInterval(fieldContext))
2197: setFixedCost(fixedCost);
2198: }
2199:
2200: /* (non-Javadoc)
2201: * @see com.projity.pm.assignment.TimeDistributedFields#isReadOnlyFixedCost(com.projity.field.FieldContext)
2202: */
2203: public boolean isReadOnlyFixedCost(FieldContext fieldContext) {
2204: return FieldContext.hasInterval(fieldContext);
2205: }
2206:
2207: /* (non-Javadoc)
2208: * @see com.projity.pm.assignment.HasTimeDistributedData#isLabor()
2209: */
2210: public boolean isLabor() {
2211: return true;
2212: }
2213:
2214: /* (non-Javadoc)
2215: * @see com.projity.pm.assignment.HasAssignments#hasLaborAssignment()
2216: */
2217: public boolean hasLaborAssignment() {
2218: return ((TaskSnapshot) getCurrentSnapshot())
2219: .hasLaborAssignment();
2220: }
2221:
2222: public void setRawDuration(long duration) {
2223: currentSchedule.setRawDuration(duration);
2224: }
2225:
2226: public void setParentDuration() {
2227: if (!isWbsParent())
2228: return;
2229: currentSchedule.assignDatesFromChildren();
2230: long duration = getDurationMillis();
2231: getSchedulingRule().adjustRemainingDuration(this ,
2232: duration - Duration.millis(getActualDuration()), true);
2233: }
2234:
2235: /* (non-Javadoc)
2236: * @see com.projity.pm.assignment.HasAssignments#invalidateAssignmentCalendars()
2237: */
2238: public void invalidateAssignmentCalendars() {
2239: ((TaskSnapshot) getCurrentSnapshot())
2240: .invalidateAssignmentCalendars();
2241: }
2242:
2243: /* (non-Javadoc)
2244: * @see com.projity.pm.calendar.HasCalendar#invalidateCalendar()
2245: */
2246: public Document invalidateCalendar() {
2247: invalidateAssignmentCalendars();
2248: markTaskAsNeedingRecalculation();
2249: return getProject();
2250: }
2251:
2252: public boolean hasActiveAssignment(long start, long end) {
2253: return ((TaskSnapshot) getCurrentSnapshot())
2254: .hasActiveAssignment(start, end);
2255: }
2256:
2257: public boolean isInvalidIntersectionCalendar() {
2258: Iterator i = getAssignments().iterator();
2259: while (i.hasNext()) {
2260: if (((Assignment) i.next()).isInvalidIntersectionCalendar())
2261: return true;
2262: }
2263: return false;
2264: }
2265:
2266: public HasIndicators getIndicators() {
2267: return this ;
2268: }
2269:
2270: public long getEarliestAssignmentStart() {
2271: return ((TaskSnapshot) getCurrentSnapshot())
2272: .getEarliestAssignmentStart();
2273: }
2274:
2275: public boolean isParentWithAssignments() {
2276: return isWbsParent() && hasRealAssignments();
2277: }
2278:
2279: public void setComplete(boolean complete) {
2280: ScheduleUtil.setComplete(this , complete);
2281: }
2282:
2283: public boolean applyTimesheet(Collection fieldArray,
2284: long timesheetUpdateDate) {
2285: return TimesheetHelper.applyTimesheet(getAssignments(),
2286: fieldArray, timesheetUpdateDate);
2287: }
2288:
2289: public long getLastTimesheetUpdate() {
2290: return TimesheetHelper.getLastTimesheetUpdate(getAssignments());
2291: }
2292:
2293: public boolean isPendingTimesheetUpdate() {
2294: return TimesheetHelper
2295: .isPendingTimesheetUpdate(getAssignments());
2296: }
2297:
2298: public int getTimesheetStatus() {
2299: return TimesheetHelper.getTimesheetStatus(getAssignments());
2300: }
2301:
2302: public String getTimesheetStatusName() {
2303: return TimesheetHelper
2304: .getTimesheetStatusName(getTimesheetStatus());
2305: }
2306:
2307: public final long getEarliestStop() {
2308: long stop = Long.MAX_VALUE;
2309: Schedule s;
2310: Object nodeImpl;
2311: if (isWbsParent()) {
2312: Collection children = getWbsChildrenNodes();
2313: Iterator i = children.iterator();
2314: while (i.hasNext()) {
2315: Object x = i.next();
2316: if (!(x instanceof Node))
2317: continue;
2318: nodeImpl = ((Node) x).getImpl();
2319: if (!(nodeImpl instanceof Schedule))
2320: continue;
2321: s = (Schedule) nodeImpl;
2322: stop = Math.min(stop, s.getEarliestStop());
2323: }
2324: } else {
2325: Iterator i = getAssignments().iterator();
2326: while (i.hasNext()) {
2327: Assignment ass = (Assignment) i.next();
2328: stop = Math.min(stop, ass.getEarliestStop());
2329: }
2330: }
2331: return stop;
2332: }
2333:
2334: public void setCompletedThrough(long completedThrough) {
2335: completedThrough = DateTime.closestDate(completedThrough);
2336: completedThrough = Math.min(completedThrough, getEnd());
2337: if (completedThrough == getCompletedThrough())
2338: return;
2339:
2340: Iterator i = getAssignments().iterator();
2341: Assignment assignment;
2342: long computedActualStart = Long.MAX_VALUE;
2343: long assignmentActualStart;
2344: while (i.hasNext()) {
2345: assignment = (Assignment) i.next();
2346: assignment.setCompletedThrough(completedThrough);
2347: assignmentActualStart = assignment.getActualStart();
2348: if (assignmentActualStart != 0
2349: && assignmentActualStart < computedActualStart)
2350: computedActualStart = assignmentActualStart;
2351: }
2352: if (computedActualStart == Long.MAX_VALUE)
2353: computedActualStart = 0;
2354: setActualStart(computedActualStart);
2355: assignParentActualDatesFromChildren();
2356:
2357: // if % complete went down to 0, then the plan changed and need to recalculate all.
2358: if (computedActualStart == 0) {
2359: getDocument().getObjectEventManager().fireUpdateEvent(this ,
2360: this , Configuration.getFieldFromId("Field.start"));
2361: } else {
2362: //TODO duplicate event
2363: //TODO in the case of progress update this event is useless since critical path runs after.
2364: getProject().fireScheduleChanged(this ,
2365: ScheduleEvent.ACTUAL, this );
2366: }
2367: }
2368:
2369: public long getFinishOffset() {
2370: return EarnedValueCalculator.getInstance()
2371: .getFinishOffset(this );
2372: }
2373:
2374: public long getStartOffset() {
2375: return EarnedValueCalculator.getInstance().getStartOffset(this );
2376: }
2377:
2378: public ImageLink getBudgetStatusIndicator() {
2379: return EarnedValueCalculator.getInstance()
2380: .getBudgetStatusIndicator(getCpi(null));
2381: }
2382:
2383: public ImageLink getScheduleStatusIndicator() {
2384: return EarnedValueCalculator.getInstance()
2385: .getBudgetStatusIndicator(getSpi(null));
2386: }
2387:
2388: public Object backupDetail() {
2389: return backupDetail(null);
2390: }
2391:
2392: public Object backupDetail(Object snapshotId) {
2393: TaskSnapshot snapshot = (TaskSnapshot) ((snapshotId == null) ? getCurrentSnapshot()
2394: : getSnapshot(snapshotId));
2395: TaskSnapshotBackup snapshotBackup = TaskSnapshotBackup.backup(
2396: snapshot,/*snapshotId!=null*/true);
2397: TaskBackup backup = new TaskBackup();
2398: backup.snapshot = snapshotBackup;
2399: backup.windowEarlyFinish = windowEarlyFinish;
2400: backup.windowEarlyStart = windowEarlyStart;
2401: backup.windowLateFinish = windowLateFinish;
2402: backup.windowLateStart = windowLateStart;
2403: backup.actualStart = actualStart;
2404: //TODO Backup other fields?
2405: return backup;
2406: }
2407:
2408: public void restoreDetail(Object source, Object backup,
2409: boolean isChild) {
2410: restoreDetail(source, backup, isChild,
2411: (TaskSnapshot) getCurrentSnapshot());
2412: }
2413:
2414: public void restoreDetail(Object source, Object backup,
2415: boolean isChild, TaskSnapshot snapshot) {
2416: TaskBackup b = (TaskBackup) backup;
2417: windowEarlyFinish = b.windowEarlyFinish;
2418: windowEarlyStart = b.windowEarlyStart;
2419: windowLateFinish = b.windowLateFinish;
2420: windowLateStart = b.windowLateStart;
2421: actualStart = b.actualStart;
2422: TaskSnapshotBackup.restore(snapshot, b.snapshot);
2423: if (!isChild)
2424: recalculate(source); //to send update event
2425: }
2426:
2427: public void renumber() {
2428: forSnapshotsAssignments(new Closure() {
2429: public void execute(Object arg0) {
2430: ((Assignment) arg0).renumber();
2431: }
2432: }, true);
2433: hasKey.renumber();
2434: }
2435:
2436: public boolean isLocal() {
2437: return hasKey.isLocal();
2438: }
2439:
2440: public void setLocal(boolean local) {
2441: hasKey.setLocal(local);
2442: }
2443:
2444: }
|