package caltool.model.schedule;
import caltool.model.caldb.*;
import mvp.*;
/****
*
* Class Schedule is the top-level model class in the schedule package. It
* provides methods to schedule the four types of calendar item. It also
* contains a Categories data field, which is the sub-model for editing
* scheduled item categories.
*
* @author Gene Fisher (gfisher@calpoly.edu)
* @version 1feb13
*
*/
public class Schedule extends Model {
/**
* Construct this with the given companion view and the parent CalendarDB
* model. The CalendarDB is provided to access to its service methods that
* store items in the current user calendar. Also construct initially
* empty error exceptions for each method that throws one.
*/
/*@
ensures
this.view == view &&
this.calDB == calDB &&
this.scheduleEventPrecondViolation != null &&
!this.scheduleEventPrecondViolation.anyErrors();
// 3 other checks omitted temporarily for simplicity
@*/
public Schedule(View view, CalendarDB calDB) {
super(view);
this.calDB = calDB;
scheduleEventPrecondViolation = new ScheduleEventPrecondViolation();
scheduleAppointmentPrecondViolation =
new ScheduleAppointmentPrecondViolation();
scheduleMeetingPrecondViolation =
new ScheduleMeetingPrecondViolation();
scheduleTaskPrecondViolation = new ScheduleTaskPrecondViolation();
}
/**
* ScheduleAppointment adds the given Appointment to the current Calendar
* if an appointment of the same time, duration, and title is not already
* scheduled.
*/
/*@
normal_behavior
requires
//
// The Title field is not empty.
//
(appt.title != null && appt.title.length() >= 1)
&&
//
// The startOrDueDate field is a valid date value.
//
((appt.startOrDueDate != null) && appt.startOrDueDate.isValid())
&&
//
// If non-empty, the EndDate field is a valid date value.
//
((appt.endDate != null) || appt.endDate.isValid())
&&
//
// The current workspace is not null.
//
(calDB.getCurrentCalendar() != null)
&&
//
// No appt of same title and start date is in the current workspace
// calendar. The UserCalendar.getItem method does the work.
//
calDB.getCurrentCalendar().getItem(appt.getKey()) == null;
ensures
//
// If preconds met, a scheduled item is in the output calendar if
// and only if it is the new appt to be added or it is in the
// input calendar.
//
(\forall ScheduledItem item;
\old(calDB).getCurrentCalendar().getItem(item.getKey()) != null <==>
(item.equals(appt) ||
\old(calDB).getCurrentCalendar().getItem(item.getKey()) != null))
&&
//
// Also, requiresSaving and hasChanged are both true in the output
// calendar.
//
calDB.getCurrentCalendar().requiresSaving()
&&
calDB.getCurrentCalendar().hasChanged();
//
// Throw exceptions if preconds violated.
//
exceptional_behavior
signals (ScheduleAppointmentPrecondViolation e)
validateInputs(appt).anyErrors()
||
alreadyScheduled(appt)
||
calDB.getCurrentCalendar() == null;
@*/
public void scheduleAppointment(Appointment appt) {
System.out.println("In Schedule.scheduleAppointment.");
}
/**
* ScheduleMeeting adds a Meeting to the current calendar, based on the the
* given MeetingRequest. The work is done by the three suboperations,
* which determine a list of possible meetings times, set
* meeting-scheduling options, and confirm the scheduling of a specific
* meeting selected from the possibles list.
*/
public void scheduleMeeting(MeetingRequest meeting_req) {
System.out.println("In Schedule.scheduleMeeting.");
}
/**
* Produce the list of possible meeting times that satisfy the given
* MeetingRequest.
*/
public PossibleMeetingTimes listMeetingTimes(MeetingRequest request) {
System.out.println("In schedule.listMeetingTimes.");
return null;
}
/**
* Set the meeting options in the CalendarDB to those given.
*
*/
public void setMeetingOptions(MeetingSchedulingOptions options) {
System.out.println("In schedule.setMeetingOptions.");
}
/**
* ConfirmMeeting takes a CalendarDB, MeetingRequest, list of
* PossibleMeetingTimes, and a selected time from the list. It outputs a
* new CalendarDB with the given request scheduled at the selected time.
*/
public void confirmMeeting(MeetingRequest meeting_req,
PossibleMeetingTimes possible_times, int selected_time) {
System.out.println("In Schedule.confirmMeeting");
}
/**
* ScheduleTask adds the given Task to the given CalendarDB, if a task of
* the same start date, title, and priority is not already scheduled.
*/
public void scheduleTask(Task task) {
System.out.println("In Schedule.scheduleTask.");
}
/**
* ScheduleEvent adds the given Event to the given CalendarDB, if an event
* of the same start date and title is not already scheduled.
*/
/*@
normal_behavior
requires
//
// The Title field is not empty.
//
(event.title != null && event.title.length() >= 1)
&&
//
// The startOrDueDate field is a valid date value.
//
(event.startOrDueDate != null) && event.startOrDueDate.isValid()
&&
//
// If non-empty, the EndDate field is a valid date value.
//
(event.endDate != null) ==> event.endDate.isValid()
&&
//
// The current workspace is not null.
//
(calDB.getCurrentCalendar() != null)
&&
//
// No event of same title and start date is in the current workspace
// calendar. The UserCalendar.getItem method does the work.
//
calDB.getCurrentCalendar().getItem(event.getKey()) == null;
ensures
//
// If preconds met, a scheduled item is in the output calendar if
// and only if it is the new appt to be added or it is in the
// input calendar.
//
(\forall ScheduledItem item;
\old(calDB).getCurrentCalendar().getItem(item.getKey()) != null <==>
(item.equals(event) ||
\old(calDB).getCurrentCalendar().getItem(item.getKey()) != null))
&&
//
// Also, requiresSaving and hasChanged are both true in the output
// calendar.
//
calDB.getCurrentCalendar().requiresSaving()
&&
calDB.getCurrentCalendar().hasChanged();
//
// Throw exceptions if preconds violated.
//
exceptional_behavior
signals (ScheduleEventPrecondViolation e)
validateInputs(event).anyErrors()
||
alreadyScheduled(event)
||
calDB.getCurrentCalendar() == null;
@*/
public void scheduleEvent(Event event)
throws ScheduleEventPrecondViolation {
/*
* Clear out the error fields in precond violation exception object.
*/
scheduleEventPrecondViolation.clear();
/*
* Throw a precond violation if the validity check fails on the title,
* start date, or end date.
*/
if (validateInputs(event).anyErrors()) {
throw scheduleEventPrecondViolation;
}
/*
* Throw a precond violation if an event of the same start date and
* title is already scheduled.
*/
if (alreadyScheduled(event)) {
scheduleEventPrecondViolation.setAlreadyScheduledError();
throw scheduleEventPrecondViolation;
}
/*
* Throw a precond violation if there is no currently active calendar.
* Note that this condition will not be violated when interacting
* through the view, since the 'Schedule Event' menu item is disabled
* whenever the there is no active calendar.
*/
if (calDB.getCurrentCalendar() == null) {
scheduleEventPrecondViolation.setNoActiveCalendarError();
throw scheduleEventPrecondViolation;
}
/*
* If preconditions are met, add the given event to the currently
* active calendar.
*/
calDB.getCurrentCalendar().add(event);
}
/**
* Change the given old appointment to the given new one in the
* current calendar.
*/
public void changeAppointment(Appointment oldAppt, Appointment newAppt) {
System.out.println("In Schedule.changeAppointment.");
}
/**
* Delete the given appointment from the current calendar.
*/
public void deleteAppointment(Appointment appt) {
System.out.println("In Schedule.deleteAppointment.");
}
/*-*
* Access methods
*/
/**
* Return the categories component.
*/
/*@
requires (* no precond *) ;
ensures \result == this.categories ;
@*/
public Categories getCategories() {
return categories;
}
/*-*
* Set methods.
*/
/**
* Set the priority of the given task to the given priority value. The
* value must be between 0 and 10, inclusive. Throw an exception if it's
* not in this range.
*/
/*@
normal_behavior
requires
priority >= 0 && priority <= 10;
ensures
task.priority == priority;
exceptional_behavior
signals (ScheduleAppointmentPrecondViolation e)
! (priority >= 0 && priority <= 10);
@*/
public void setTaskPriority(Task task, int priority)
throws ScheduleTaskPrecondViolation {
/*
* Throw a precond violation priority is out of range.
*/
if ((priority < 0) || (priority > 10)) {
scheduleTaskPrecondViolation.clear();
scheduleTaskPrecondViolation.setPriorityOutOfRangeError();
throw scheduleTaskPrecondViolation;
}
/*
* Otherwise set the priority in the task.
*/
task.priority = priority;
}
/**
* Convert this to a printable string. Note that the categories field is
* only converted shallow since no methods of this change the contents of
* categories. The deep string conversion is of calDB.getCurrentCalendar,
* since it's the object to which the scheduling methods effect change.
*/
public String toString() {
return
"Categories: " + categories + "\n" +
"caldDB.currentCalendar:\n" /* +
(calDB != null && calDB.getCurrentCalendar() != null ?
calDB.getCurrentCalendar().toString() : "" */;
}
/*-*
* Protected methods
*/
/**
* Return true if there is an already scheduled event of the same title on
* any of the same dates as the given event.
*/
protected boolean alreadyScheduled(ScheduledItem item) {
/*
* Implementation forthcoming.
*/
return false;
/*
* The following won't fully work, since we must check all dates.
*
return calDB.getCurrentCalendar().getItem(
new ItemKey(e.startDate, null, null, e.title)) == null;
*
*/
}
/**
* Validate the ScheduleEvent
* precondition. Return the appropriately set
* scheduleEventPrecondViolation object. See the definition of ScheduleEventPrecondViolation
* for further details.
*/
protected ScheduleEventPrecondViolation validateInputs(Event event) {
if ((event.title == null) || (event.title.length() == 0)) {
scheduleEventPrecondViolation.setEmptyTitleError();
}
if (! event.startOrDueDate.isValid()) {
scheduleEventPrecondViolation.setInvalidStartDateError();
}
if ((event.endDate != null) && (! event.endDate.isValid())) {
scheduleEventPrecondViolation.setInvalidEndDateError();
}
return scheduleEventPrecondViolation;
}
/**
* Validate the ScheduleAppointment
* precondition. Return the appropriately set
* scheduleAppointmentPrecondViolation object. See the definition of ScheduleAppointmentPrecondViolation
* for further details.
*/
protected ScheduleAppointmentPrecondViolation validateInputs(
Appointment appt) {
if ((appt.title == null) || (appt.title.length() == 0)) {
scheduleAppointmentPrecondViolation.setEmptyTitleError();
}
if (! appt.startOrDueDate.isValid()) {
scheduleAppointmentPrecondViolation.setInvalidStartDateError();
}
if ((appt.endDate != null) && (! appt.endDate.isValid())) {
scheduleAppointmentPrecondViolation.setInvalidEndDateError();
}
return scheduleAppointmentPrecondViolation;
}
protected ScheduleTaskPrecondViolation validateInputs(Task task) {
// Implementation forthcoming
return scheduleTaskPrecondViolation;
}
/*-*
* Derived data fields
*/
/** Category list in which scheduled item categories are defined */
protected Categories categories;
/*-*
* Process data fields
*/
/** Calendar database that contains the current calendar in which scheduled
* items are stored */
protected CalendarDB calDB;
/** Precond violation exception objects */
protected ScheduleAppointmentPrecondViolation
scheduleAppointmentPrecondViolation;
protected ScheduleMeetingPrecondViolation scheduleMeetingPrecondViolation;
protected ScheduleTaskPrecondViolation scheduleTaskPrecondViolation;
protected ScheduleEventPrecondViolation scheduleEventPrecondViolation;
}