/* * file: ProjectFile.java * author: Jon Iles * copyright: (c) Packwood Software 2002-2006 * date: 15/08/2002 */ /* * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2.1 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package net.sf.mpxj; import java.util.Date; import java.util.LinkedList; import java.util.List; import net.sf.mpxj.common.NumberHelper; /** * This class represents a project plan. */ public final class ProjectFile implements ChildTaskContainer { /** * Retrieve project configuration data. * * @return ProjectConfig instance. */ public ProjectConfig getProjectConfig() { return m_config; } /** * This method allows a task to be added to the file programatically. * * @return new task object */ public Task addTask() { return m_tasks.add(); } /** * This method is used to remove a task from the project. * * @param task task to be removed */ public void removeTask(Task task) { m_tasks.remove(task); } /** * This method can be called to ensure that the IDs of all * tasks in this project are sequential, and start from an * appropriate point. If tasks are added to and removed from * the list of tasks, then the project is loaded into Microsoft * project, if the ID values have gaps in the sequence, there will * be blank task rows shown. */ public void renumberTaskIDs() { m_tasks.renumberIDs(); } /** * This method can be called to ensure that the IDs of all * resources in this project are sequential, and start from an * appropriate point. If resources are added to and removed from * the list of resources, then the project is loaded into Microsoft * project, if the ID values have gaps in the sequence, there will * be blank resource rows shown. */ public void renumberResourceIDs() { m_resources.renumberIDs(); } /** * This method is called to ensure that all unique ID values * held by MPXJ are within the range supported by MS Project. * If any of these values fall outside of this range, the unique IDs * of the relevant entities are renumbered. */ public void validateUniqueIDsForMicrosoftProject() { m_tasks.validateUniqueIDsForMicrosoftProject(); m_resources.validateUniqueIDsForMicrosoftProject(); m_assignments.validateUniqueIDsForMicrosoftProject(); m_calendars.validateUniqueIDsForMicrosoftProject(); } /** * Microsoft Project bases the order of tasks displayed on their ID * value. This method takes the hierarchical structure of tasks * represented in MPXJ and renumbers the ID values to ensure that * this structure is displayed as expected in Microsoft Project. This * is typically used to deal with the case where a hierarchical task * structure has been created programmatically in MPXJ. */ public void synchronizeTaskIDToHierarchy() { m_tasks.synchronizeTaskIDToHierarchy(); } /** * This method is used to retrieve a list of all of the top level tasks * that are defined in this project file. * * @return list of tasks */ @Override public List<Task> getChildTasks() { return m_childTasks; } /** * This method is used to retrieve a list of all of the tasks * that are defined in this project file. * * @return list of all tasks */ public TaskContainer getAllTasks() { return m_tasks; } /** * This method is used to add a new calendar to the file. * * @return new calendar object */ public ProjectCalendar addCalendar() { return m_calendars.add(); } /** * Removes a calendar. * * @param calendar calendar to be removed */ public void removeCalendar(ProjectCalendar calendar) { m_calendars.remove(calendar); } /** * This is a convenience method used to add a calendar called * "Standard" to the file, and populate it with a default working week * and default working hours. * * @return a new default calendar */ public ProjectCalendar addDefaultBaseCalendar() { return m_calendars.addDefaultBaseCalendar(); } /** * This is a convenience method to add a default derived * calendar. * * @return new ProjectCalendar instance */ public ProjectCalendar addDefaultDerivedCalendar() { return m_calendars.addDefaultDerivedCalendar(); } /** * This method retrieves the list of calendars defined in * this file. * * @return list of calendars */ public ProjectCalendarContainer getCalendars() { return m_calendars; } /** * This method is used to retrieve the project properties. * * @return project properties */ public ProjectProperties getProjectProperties() { return m_properties; } /** * This method is used to add a new resource to the file. * * @return new resource object */ public Resource addResource() { return m_resources.add(); } /** * This method is used to remove a resource from the project. * * @param resource resource to be removed */ public void removeResource(Resource resource) { m_resources.remove(resource); } /** * Retrieves a list of all resources in this project. * * @return list of all resources */ public ResourceContainer getAllResources() { return m_resources; } /** * Retrieves a list of all resource assignments in this project. * * @return list of all resources */ public ResourceAssignmentContainer getAllResourceAssignments() { return m_assignments; } /** * This method has been provided to allow the subclasses to * instantiate ResourecAssignment instances. * * @param task parent task * @return new resource assignment instance */ public ResourceAssignment newResourceAssignment(Task task) { return (new ResourceAssignment(this, task)); } /** * Retrieves the named calendar. This method will return * null if the named calendar is not located. * * @param calendarName name of the required calendar * @return ProjectCalendar instance */ public ProjectCalendar getCalendarByName(String calendarName) { return m_calendars.getByName(calendarName); } /** * Retrieves the calendar referred to by the supplied unique ID * value. This method will return null if the required calendar is not * located. * * @param calendarID calendar unique ID * @return ProjectCalendar instance */ public ProjectCalendar getCalendarByUniqueID(Integer calendarID) { return m_calendars.getByUniqueID(calendarID); } /** * This method is used to calculate the duration of work between two fixed * dates according to the work schedule defined in the named calendar. The * calendar used is the "Standard" calendar. If this calendar does not exist, * and exception will be thrown. * * @param startDate start of the period * @param endDate end of the period * @return new Duration object * @throws MPXJException normally when no Standard calendar is available */ public Duration getDuration(Date startDate, Date endDate) throws MPXJException { return (getDuration("Standard", startDate, endDate)); } /** * This method is used to calculate the duration of work between two fixed * dates according to the work schedule defined in the named calendar. * The name of the calendar to be used is passed as an argument. * * @param calendarName name of the calendar to use * @param startDate start of the period * @param endDate end of the period * @return new Duration object * @throws MPXJException normally when no Standard calendar is available */ public Duration getDuration(String calendarName, Date startDate, Date endDate) throws MPXJException { ProjectCalendar calendar = getCalendarByName(calendarName); if (calendar == null) { throw new MPXJException(MPXJException.CALENDAR_ERROR + ": " + calendarName); } return (calendar.getDuration(startDate, endDate)); } /** * This method allows an arbitrary task to be retrieved based * on its ID field. * * @param id task identified * @return the requested task, or null if not found */ public Task getTaskByID(Integer id) { return m_tasks.getByID(id); } /** * This method allows an arbitrary task to be retrieved based * on its UniqueID field. * * @param id task identified * @return the requested task, or null if not found */ public Task getTaskByUniqueID(Integer id) { return m_tasks.getByUniqueID(id); } /** * This method allows an arbitrary resource to be retrieved based * on its ID field. * * @param id resource identified * @return the requested resource, or null if not found */ public Resource getResourceByID(Integer id) { return m_resources.getByID(id); } /** * This method allows an arbitrary resource to be retrieved based * on its UniqueID field. * * @param id resource identified * @return the requested resource, or null if not found */ public Resource getResourceByUniqueID(Integer id) { return m_resources.getByUniqueID(id); } /** * This method is used to recreate the hierarchical structure of the * project file from scratch. The method sorts the list of all tasks, * then iterates through it creating the parent-child structure defined * by the outline level field. */ public void updateStructure() { m_tasks.updateStructure(); } /** * Find the earliest task start date. We treat this as the * start date for the project. * * @return start date */ public Date getStartDate() { Date startDate = null; for (Task task : m_tasks) { // // If a hidden "summary" task is present we ignore it // if (NumberHelper.getInt(task.getUniqueID()) == 0) { continue; } // // Select the actual or forecast start date. Note that the // behaviour is different for milestones. The milestone end date // is always correct, the milestone start date may be different // to reflect a missed deadline. // Date taskStartDate; if (task.getMilestone() == true) { taskStartDate = task.getActualFinish(); if (taskStartDate == null) { taskStartDate = task.getFinish(); } } else { taskStartDate = task.getActualStart(); if (taskStartDate == null) { taskStartDate = task.getStart(); } } if (taskStartDate != null) { if (startDate == null) { startDate = taskStartDate; } else { if (taskStartDate.getTime() < startDate.getTime()) { startDate = taskStartDate; } } } } return (startDate); } /** * Find the latest task finish date. We treat this as the * finish date for the project. * * @return finish date */ public Date getFinishDate() { Date finishDate = null; for (Task task : m_tasks) { // // If a hidden "summary" task is present we ignore it // if (NumberHelper.getInt(task.getUniqueID()) == 0) { continue; } // // Select the actual or forecast start date // Date taskFinishDate; taskFinishDate = task.getActualFinish(); if (taskFinishDate == null) { taskFinishDate = task.getFinish(); } if (taskFinishDate != null) { if (finishDate == null) { finishDate = taskFinishDate; } else { if (taskFinishDate.getTime() > finishDate.getTime()) { finishDate = taskFinishDate; } } } } return (finishDate); } /** * This method returns a list of the views defined in this MPP file. * * @return list of views */ public ViewContainer getViews() { return m_views; } /** * This method returns the tables defined in an MPP file. * * @return list of tables */ public TableContainer getTables() { return m_tables; } /** * This method returns the filters defined in an MPP file. * * @return filters */ public FilterContainer getFilters() { return m_filters; } /** * Retrieves a list of all groups. * * @return list of all groups */ public GroupContainer getGroups() { return m_groups; } /** * Retrieves all the subprojects for this project. * * @return all sub project details */ public SubProjectContainer getSubProjects() { return m_subProjects; } /** * Retrieve the event manager for this project. * * @return event manager */ public EventManager getEventManager() { return m_eventManager; } /** * Retrieves the custom field configuration for this project. * * @return custom field configuration */ public CustomFieldContainer getCustomFields() { return m_customFields; } /** * Retrieves the default calendar for this project based on the calendar name * given in the project properties. If a calendar of this name cannot be found, then * the first calendar listed for the project will be returned. If the * project contains no calendars, then a default calendar is added. * * @return default projectCalendar instance */ public ProjectCalendar getDefaultCalendar() { String calendarName = m_properties.getDefaultCalendarName(); ProjectCalendar calendar = getCalendarByName(calendarName); if (calendar == null) { if (m_calendars.isEmpty()) { calendar = addDefaultBaseCalendar(); } else { calendar = m_calendars.get(0); } } return calendar; } /** * Sets the default calendar for this project. * * @param calendar default calendar instance */ public void setDefaultCalendar(ProjectCalendar calendar) { m_properties.setDefaultCalendarName(calendar.getName()); } /** * Retrieve the calendar used internally for timephased baseline calculation. * * @return baseline calendar */ public ProjectCalendar getBaselineCalendar() { // // Attempt to locate the calendar normally used by baselines // If this isn't present, fall back to using the default // project calendar. // ProjectCalendar result = getCalendarByName("Used for Microsoft Project 98 Baseline Calendar"); if (result == null) { result = getDefaultCalendar(); } return result; } private final ProjectConfig m_config = new ProjectConfig(this); private final ProjectProperties m_properties = new ProjectProperties(this); private final ResourceContainer m_resources = new ResourceContainer(this); private final TaskContainer m_tasks = new TaskContainer(this); private final List<Task> m_childTasks = new LinkedList<Task>(); private final ResourceAssignmentContainer m_assignments = new ResourceAssignmentContainer(this); private final ProjectCalendarContainer m_calendars = new ProjectCalendarContainer(this); private final TableContainer m_tables = new TableContainer(); private final FilterContainer m_filters = new FilterContainer(); private final GroupContainer m_groups = new GroupContainer(); private final SubProjectContainer m_subProjects = new SubProjectContainer(); private final ViewContainer m_views = new ViewContainer(); private final EventManager m_eventManager = new EventManager(); private final CustomFieldContainer m_customFields = new CustomFieldContainer(); }