/**
   * Given a new arrival date, re-calculate the speed
   *
   * @param arrivalDate the new arrival date
   */
  private void recalculateSpeeds(Date arrivalDate) {
    // Stop widget listeners
    boolean wasQuiescent = quiescent;
    quiescent = true;

    // Special case if the arrival date is before the start time
    if (route.getStarttime().after(arrivalDate)) {
      // Reset arrival to a valid time
      arrivalPicker.setDate(route.getEta());
      arrivalSpinner.setValue(route.getEta());

      quiescent = wasQuiescent;
      return;
    }

    // Total distance
    Dist distanceToTravel = new Dist(DistType.NAUTICAL_MILES, route.getRouteDtg());
    // And we want to get there in milliseconds:
    Time timeToTravel =
        new Time(TimeType.MILLISECONDS, arrivalDate.getTime() - route.getStarttime().getTime());

    // Subtract the distance and time from the locked way points
    for (int i = 0; i < route.getWaypoints().size() - 1; i++) {
      if (locked[i]) {
        distanceToTravel =
            distanceToTravel.subtract(new Dist(DistType.NAUTICAL_MILES, route.getWpRng(i)));
        timeToTravel =
            timeToTravel.subtract(new Time(TimeType.MILLISECONDS, route.getWpTtg(i + 1)));
      }
    }

    // Ensure the remaining time is actually positive (say, more than a minute)
    if (timeToTravel.in(TimeType.MINUTES).doubleValue() < 1.0) {
      // Reset arrival to a valid time
      arrivalPicker.setDate(route.getEta());
      arrivalSpinner.setValue(route.getEta());

      quiescent = wasQuiescent;
      return;
    }

    // So we need to travel how fast?
    double speed = distanceToTravel.inTime(timeToTravel).in(SpeedType.KNOTS).doubleValue();

    for (int i = 0; i < route.getWaypoints().size(); i++) {
      if (!locked[i]) {
        route.getWaypoints().get(i).setSpeed(speed);
      }
    }

    // Update fields
    updateFields();

    // Restore the quiescent state
    quiescent = wasQuiescent;
  }
  /** Called in order to adjust the route start time and the UI accordingly */
  private void adjustStartTime() {

    // Stop widget listeners
    boolean wasQuiescent = quiescent;
    quiescent = true;

    // Get start time or default now
    if (!readOnlyRoute) {
      route.adjustStartTime();
    }
    Date starttime = route.getStarttime();

    departurePicker.setDate(starttime);
    departureSpinner.setValue(starttime);

    // Attempt to get ETA (only possible if GPS data is available)
    Date etaStart = route.getEta(starttime);
    if (etaStart != null) {
      // GPS data available.
      arrivalPicker.setDate(etaStart);
      arrivalSpinner.setValue(etaStart);
    } else {
      // No GPS data available.
      // Find the default ETA.
      Date defaultEta = route.getEtas().get(route.getEtas().size() - 1);
      arrivalPicker.setDate(defaultEta);
      arrivalSpinner.setValue(defaultEta);
    }

    // Recalculate and update route fields
    updateFields();

    // Restore the quiescent state
    quiescent = wasQuiescent;
  }