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 13feb13 * */ 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(); } /** * Return the categories component. */ /*@ requires (* no precond *) ; ensures \result == this.categories ; @*/ public Categories getCategories() { return categories; } /** * 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); } /** * 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."); } /** * 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 */ /*-* * 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) validateInputs(task).anyErrors(); @*/ 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.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; } /*-* * 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; }