TaskUpdate#

An edit to one existing task of a live project. It goes in the update list of SchedulingChanges.tasks, which Project#apply and Project#preview take. Create it with new TaskUpdate(id) and chain a withX(...) setter for each field to change.

Declaration#

public class TaskUpdate extends ValueRecord implements DeepCloneable<TaskUpdate>

Constructors#

TaskUpdate(Id)#

public TaskUpdate(Id id)

Creates an update for the task with the given id. Every other field is Patch.missing(), so the update changes nothing until a field is set.

Name Type Description
id Id Id of the task to edit.

Fields#

Every field except id is a Patch<T>. Patch.missing() (the default) keeps the stored value, Patch.of(value) sets it, and Patch.nullValue() clears it. The On nullValue() column shows what a cleared field holds afterwards. For the meaning of each value, see the field of the same name on TaskData.

Each field has a fluent setter of the same name, withX(Patch<T> value), that returns this update.

Field Type On nullValue() Description
id Id required Id of the task to edit.
parent Patch<Id> root level Moves the task under another parent. A value equal to SchedulingConfig.rootId is read as nullValue().
startDate Patch<Moment> null New start, for example after a drag.
endDate Patch<Moment> null New end.
duration Patch<Double> null New working time in the task's durationUnit, for example after a resize.
constraintType Patch<ConstraintType> null New scheduling constraint.
constraintDate Patch<Moment> null New constraint date.
autoScheduling Patch<Boolean> true false makes the task fixed.
unscheduled Patch<Boolean> false true takes the task out of the plan.
progress Patch<Double> 0.0 New completed fraction.
calendarId Patch<Id> null New working calendar. Patch.of(null) also clears it.
priority Patch<Integer> 500 New leveling priority, 0..1000.
levelingDelay Patch<Double> 0.0 New leveling delay, as elapsed time in the task's durationUnit.
pauses Patch<Vec<Pause>> empty Replaces the whole pause list. The task gets a deep copy of the list.

Patch.of(null) holds a null value, which isn't the same as Patch.nullValue(). On parent, pauses, autoScheduling, unscheduled, progress, priority and levelingDelay it throws NullPointerException when the update is applied. Use Patch.nullValue() to clear these fields.

Dates after an update#

An update starts from the task's current scheduled start, end and duration. On a leaf task (TaskType.TASK), the fields set in the update decide which of the three is kept and which is derived again:

Set in the update Kept Derived again
startDate, no endDate start, duration end
endDate only end, start duration
duration, no endDate start, duration end
startDate + endDate, no duration start, end duration
calendarId, or parent under CalendarMode.TASK_INHERITED, no date field start, duration end
pauses or levelingDelay, no date field start, duration end
  • A levelingDelay update with neither startDate nor endDate also moves the stored dates by the change in delay (elapsed time) and snaps them onto working time.
  • When a task works on several calendars in a project with scheduleFromEnd on, a pauses or levelingDelay update without dates keeps the end and derives the start instead.
  • Under CalendarMode.TASK_INHERITED, a calendarId or parent update also re-derives the end of each descendant leaf task that has no calendarId of its own. Its start and duration stay.
  • An explicit start on non-working time stays unsnapped when the task has no predecessor.

To write a result entry back as an update, see Mutation.

Methods#

deepClone#

public TaskUpdate deepClone()

Returns a copy that shares no list with this update, including the pauses value.

Returns: a new TaskUpdate with the same values.

copy#

public TaskUpdate copy()

Returns a shallow copy. The pauses list, if set, is shared with this update.

Returns: a new TaskUpdate with the same field values.

equals, hashCode and toString come from ValueRecord and work over the public fields, e.g. TaskUpdate{id=a, parent=Patch{kind=MISSING}, …}.

Errors#

An update is rejected as a single operation, at path tasks.update[i]. Project#apply and Project#preview describe how a rejection is reported.

Message When it occurs
unknown task id No task has id.
a validation message The edited task breaks a TaskData rule or a ProjectData rule, for example an unknown calendarId or parent.

Example#

Move a task to a new start and make it one day longer:

import org.dhtmlx.plen.*;
import java.util.List;

public class MoveTask {
  public static void main(String[] args) throws Exception {
    Moment monday = Moment.fromYmdHm(2026, 4, 6, 8, 0);
    Moment wednesday = Moment.fromYmdHm(2026, 4, 8, 8, 0);

    ProjectData data = new ProjectData()
        .withTasks(List.of(new TaskData(Id.str("design")).withStartDate(monday).withDuration(2.0)));

    Project project = new Project();
    project.solve(data, new SolveOptions());

    SchedulingChanges changes = new SchedulingChanges();
    changes.tasks.update.add(new TaskUpdate(Id.str("design"))
        .withStartDate(Patch.of(wednesday))
        .withDuration(Patch.of(3.0)));

    ApplyReport report = project.apply(changes);
    if (report.rejected.isEmpty()) {
      ScheduleResult result = project.solve(null, new SolveOptions());
      for (Mutation task : result.updates) {
        System.out.println(task.id + ": " + task.startDate + " - " + task.endDate);
      }
    }
  }
}
  • TaskData - the stored task and the meaning of each field
  • Patch<T> - the three-state type of every editable field
  • Mutation - result entries to write back as updates
  • SchedulingChanges - the change set that carries the update
  • Data Updates - which dates a task update keeps