All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.mpxj.ProjectFile Maven / Gradle / Ivy

Go to download

Library that provides facilities to allow project information to be manipulated in Java and .Net. Supports a range of data formats: Microsoft Project Exchange (MPX), Microsoft Project (MPP,MPT), Microsoft Project Data Interchange (MSPDI XML), Microsoft Project Database (MPD), Planner (XML), Primavera (PM XML, XER, and database), Asta Powerproject (PP, MDB), Asta Easyplan (PP), Phoenix Project Manager (PPX), FastTrack Schedule (FTS), and the Standard Data Exchange Format (SDEF).

The newest version!
/*
 * 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.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import net.sf.mpxj.common.NumberHelper;
import net.sf.mpxj.common.ObjectSequence;

/**
 * This class represents a project plan.
 */
public final class ProjectFile implements ChildTaskContainer, ChildResourceContainer, UniqueIdObjectSequenceProvider
{
   /**
    * Default constructor.
    */
   public ProjectFile()
   {
      m_shared = new ProjectFileSharedData();
   }

   /**
    * Constructor allowing a ProjectFileSharedData instance to be passed.
    *
    * @param shared ProjectFileSharedData instance
    */
   public ProjectFile(ProjectFileSharedData shared)
   {
      m_shared = shared;
   }

   /**
    * Retrieve project configuration data.
    *
    * @return ProjectConfig instance.
    */
   public ProjectConfig getProjectConfig()
   {
      return m_config;
   }

   /**
    * This method allows a task to be added to the file programmatically.
    *
    * @return new task object
    */
   @Override 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 is used to retrieve a list of all top level tasks
    * defined in this project file.
    *
    * @return list of tasks
    */
   @Override public List getChildTasks()
   {
      return m_childTasks;
   }

   /**
    * This method is used to retrieve a list of all top level resources
    * defined in this project file.
    *
    * @return list of resources
    */
   @Override public List getChildResources()
   {
      return m_childResources;
   }

   /**
    * This method is used to retrieve a list of all tasks
    * defined in this project file.
    *
    * @return list of all tasks
    */
   public TaskContainer getTasks()
   {
      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
    */
   @Override 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 getResources()
   {
      return m_resources;
   }

   /**
    * Retrieves a list of all resource assignments in this project.
    *
    * @return list of all resources
    */
   public ResourceAssignmentContainer getResourceAssignments()
   {
      return m_assignments;
   }

   /**
    * Retrieves a list of all relations in this project.
    *
    * @return list of all relations
    */
   public RelationContainer getRelations()
   {
      return m_relations;
   }

   /**
    * 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 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();
      m_resources.updateStructure();
   }

   /**
    * Find the earliest task start date.
    *
    * @return start date
    */
   public LocalDateTime getEarliestStartDate()
   {
      LocalDateTime 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.
         //
         LocalDateTime taskStartDate;
         if (task.getMilestone())
         {
            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.isBefore(startDate))
               {
                  startDate = taskStartDate;
               }
            }
         }
      }

      return (startDate);
   }

   /**
    * Find the latest task finish date.
    *
    * @return finish date
    */
   public LocalDateTime getLatestFinishDate()
   {
      LocalDateTime 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
         //
         LocalDateTime taskFinishDate;
         taskFinishDate = task.getActualFinish();
         if (taskFinishDate == null)
         {
            taskFinishDate = task.getFinish();
         }

         if (taskFinishDate != null)
         {
            if (finishDate == null)
            {
               finishDate = taskFinishDate;
            }
            else
            {
               if (taskFinishDate.isAfter(finishDate))
               {
                  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;
   }

   /**
    * Retrieve the event manager for this project.
    *
    * @return event manager
    */
   public EventManager getEventManager()
   {
      return m_eventManager;
   }

   /**
    * Retrieves the custom fields for this project.
    *
    * @return custom fields
    */
   public CustomFieldContainer getCustomFields()
   {
      return m_shared.getCustomFields();
   }

   /**
    * Retrieves the activity code configuration for this project.
    *
    * @return activity codes
    */
   public ActivityCodeContainer getActivityCodes()
   {
      return m_shared.getActivityCodes();
   }

   /**
    * Retrieves the project code configuration for this project.
    *
    * @return project codes
    */
   public ProjectCodeContainer getProjectCodes()
   {
      return m_shared.getProjectCodes();
   }

   /**
    * Retrieves the resource code configuration for this project.
    *
    * @return resource codes
    */
   public ResourceCodeContainer getResourceCodes()
   {
      return m_shared.getResourceCodes();
   }

   /**
    * Retrieves the role code configuration for this project.
    *
    * @return role codes
    */
   public RoleCodeContainer getRoleCodes()
   {
      return m_shared.getRoleCodes();
   }

   /**
    * Retrieves the resource assignment code configuration for this project.
    *
    * @return resource assignment codes
    */
   public ResourceAssignmentCodeContainer getResourceAssignmentCodes()
   {
      return m_shared.getResourceAssignmentCodes();
   }

   /**
    * Retrieves the shifts for this project.
    *
    * @return shifts
    */
   public ShiftContainer getShifts()
   {
      return m_shared.getShifts();
   }

   /**
    * Retrieves the shift periods for this project.
    *
    * @return shift periods
    */
   public ShiftPeriodContainer getShiftPeriods()
   {
      return m_shared.getShiftPeriods();
   }

   /**
    * Retrieves the data link configuration for this project.
    *
    * @return data links
    */
   public DataLinkContainer getDataLinks()
   {
      return m_dataLinks;
   }

   /**
    * Retrieves the expense categories available for this schedule.
    *
    * @return expense categories
    */
   public ExpenseCategoryContainer getExpenseCategories()
   {
      return m_shared.getExpenseCategories();
   }

   /**
    * Retrieves the cost accounts available for this schedule.
    *
    * @return cost accounts
    */
   public CostAccountContainer getCostAccounts()
   {
      return m_shared.getCostAccounts();
   }

   /**
    * Retrieves the user defined fields available for this schedule.
    *
    * @return user defined fields
    */
   public UserDefinedFieldContainer getUserDefinedFields()
   {
      return m_shared.getUserDefinedFields();
   }

   /**
    * Retrieves the work contours available for this schedule.
    *
    * @return work contours
    */
   public WorkContourContainer getWorkContours()
   {
      return m_shared.getWorkContours();
   }

   /**
    * Retrieves the notes topics available for this schedule.
    *
    * @return notes topics
    */
   public NotesTopicContainer getNotesTopics()
   {
      return m_shared.getNotesTopics();
   }

   /**
    * Retrieve the locations available for this schedule.
    *
    * @return locations
    */
   public LocationContainer getLocations()
   {
      return m_shared.getLocations();
   }

   /**
    * Retrieve the units of measure available for this schedule.
    *
    * @return units of measure
    */
   public UnitOfMeasureContainer getUnitsOfMeasure()
   {
      return m_shared.getUnitsOfMeasure();
   }

   /**
    * 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()
   {
      return getProjectProperties().getDefaultCalendar();
   }

   /**
    * Sets the default calendar for this project.
    *
    * @param calendar default calendar instance
    */
   public void setDefaultCalendar(ProjectCalendar calendar)
   {
      if (calendar != null)
      {
         m_properties.setDefaultCalendar(calendar);
      }
   }

   /**
    * Retrieve the calendar used internally for timephased baseline calculation.
    * All baseline timephased data is relative to this calendar.
    * The calendar is created at the point the first baseline is taken and is
    * a copy of the default calendar at that time.
    *
    * @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(m_properties.getBaselineCalendarName());
      if (result == null)
      {
         result = getDefaultCalendar();
      }
      return result;
   }

   /**
    * Retrieve the baselines linked to this project.
    * The baseline at index zero is the default baseline,
    * the values at the remaining indexes (1-10) are the
    * numbered baselines. The list will contain null
    * if a particular baseline has not been set.
    *
    * @return list of baselines
    */
   public List getBaselines()
   {
      return Arrays.asList(m_baselines);
   }

   /**
    * Store the supplied project as the default baseline, and use it to set the
    * baseline cost, duration, finish, fixed cost accrual, fixed cost, start and
    * work attributes for the tasks in the current project.
    *
    * @param baseline baseline project
    */
   public void setBaseline(ProjectFile baseline)
   {
      setBaseline(baseline, 0);
   }

   /**
    * Retrieve the default baseline project.
    *
    * @return ProjectFile instance or null
    */
   public ProjectFile getBaseline()
   {
      return getBaseline(0);
   }

   /**
    * Store the supplied project as baselineN, and use it to set the
    * baselineN cost, duration, finish, fixed cost accrual, fixed cost, start and
    * work attributes for the tasks in the current project.
    * The index argument selects which of the 10 baselines to populate. Passing
    * an index of 0 populates the default baseline.
    *
    * @param baseline baseline project
    * @param index baseline to populate (0-10)
    */
   public void setBaseline(ProjectFile baseline, int index)
   {
      if (index < 0 || index >= m_baselines.length)
      {
         throw new IllegalArgumentException(index + " is not a valid baseline index");
      }

      m_baselines[index] = baseline;
      if (index == 0)
      {
         m_properties.setBaselineDate(baseline.getProjectProperties().getCreationDate());
      }
      else
      {
         m_properties.setBaselineDate(index, baseline.getProjectProperties().getCreationDate());
      }

      m_config.getBaselineStrategy().populateBaseline(this, baseline, index);
   }

   /**
    * Retrieve baselineN from Baseline, Baseline1, Baseline2 ... Baseline10.
    * Returns null if the specified baseline has not been set.
    *
    * @param index 0-10 representing Baseline, Baseline1, Baseline2 ... Baseline10
    * @return ProjectFile instance or null
    */
   public ProjectFile getBaseline(int index)
   {
      if (index < 0 || index >= m_baselines.length)
      {
         throw new IllegalArgumentException(index + " is not a valid baseline index");
      }
      return m_baselines[index];
   }

   /**
    * Clear the default baseline for this project.
    */
   public void clearBaseline()
   {
      clearBaseline(0);
   }

   /**
    * Clear baselineN (1-10) for this project.
    *
    * @param index baseline index
    */
   public void clearBaseline(int index)
   {
      m_config.getBaselineStrategy().clearBaseline(this, index);
   }

   /**
    * Set a map of tasks in this project to tasks in baseline project.
    * Populated when a baseline is added.
    *
    * @param index baseline index
    * @param map map of current project tasks to baseline project tasks
    */
   void setBaselineTaskMap(int index, Map map)
   {
      m_baselineTaskMap.put(Integer.valueOf(index), map);
   }

   /**
    * Map of tasks in this project to tasks in a baseline project.
    * Populated when a baseline is added.
    *
    * @param index baseline index
    * @return map of current project tasks to baseline project tasks
    */
   Map getBaselineTaskMap(int index)
   {
      return m_baselineTaskMap.getOrDefault(Integer.valueOf(index), Collections.emptyMap());
   }

   /**
    * A convenience method used to retrieve a set of FieldType instances representing
    * all populated fields in the project.
    *
    * @return set of all populated fields
    */
   public Set getPopulatedFields()
   {
      return Stream.of(m_tasks.getPopulatedFields(), m_resources.getPopulatedFields(), m_assignments.getPopulatedFields(), m_properties.getPopulatedFields()).flatMap(Collection::stream).collect(Collectors.toSet());
   }

   /**
    * Calling this method will recursively expand any subprojects
    * in the current file and in turn any subprojects those files contain.
    * The tasks from the subprojects will be attached
    * to what was originally the subproject task. Assuming all subproject
    * files can be located and loaded correctly, this will present
    * a complete view of the project.
    * 

* Note that the current project and any subprojects are still independent * projects, so while you can recursively descend through the hierarchy * of tasks to visit all tasks from all files, the {@code ProjectFile.getTasks()} * collection will still only contain the tasks from the original project, * not all the subprojects. *

* Passing {@code true} for the {@code replaceExternalTasks} flag will * replace any predecessor or successor relationships with external tasks * with new relationships which link to the original tasks. For each * external task where this is successful, the external task itself will * be removed as it is just a placeholder and is no longer required. * * @param replaceExternalTasks flag indicating if external tasks should be replaced */ public void expandSubprojects(boolean replaceExternalTasks) { getTasks().stream().map(Task::expandSubproject).filter(Objects::nonNull).forEach(p -> p.expandSubprojects(replaceExternalTasks)); if (replaceExternalTasks) { replaceExternalTasks(); } } /** * Calling this method will replace any predecessors or successors which link to external tasks with new predecessors or successors * which link to the correct tasks across projects. As the external task instance are just placeholders, * these are now removed as they serve no further purpose. */ private void replaceExternalTasks() { List externalTasks = new ArrayList<>(); findExternalTasks(getChildTasks(), externalTasks); Set replacedTasks = externalTasks.stream().map(t -> replaceRelations(t)).filter(t -> t != null).collect(Collectors.toSet()); removeExternalTasks(getChildTasks(), replacedTasks); } /** * Replaces any predecessor or successor relations for this external task. * * @param externalTask external task to replace * @return the external task if relations successfully replaced, or null if not replaced */ private Task replaceRelations(Task externalTask) { ProjectFile originalProjectFile = findProject(externalTask.getSubprojectFile()); if (originalProjectFile == null) { return null; } Task originalTask = findTask(originalProjectFile, externalTask); if (originalTask == null) { return null; } replaceRelations(externalTask, originalTask); return externalTask; } /** * Given a project's filename, find the relevant ProjectFile instance. * * @param name project filename * @return ProjectFile instance or null if the project can't be found */ private ProjectFile findProject(String name) { if (name.equals(m_properties.getProjectFilePath())) { return this; } return m_externalProjects.read(name); } /** * Find the original task in a ProjectFile instance which is represented by * an external task. * * @param file project containing the original task * @param externalTask external task representing the original task * @return Task instance, or null if we can't find the original task */ private Task findTask(ProjectFile file, Task externalTask) { Integer id = externalTask.getSubprojectTaskUniqueID(); if (id != null) { Task result = file.getTaskByUniqueID(id); if (result != null) { return result; } } id = externalTask.getSubprojectTaskID(); if (id != null) { return file.getTaskByID(id); } return null; } /** * Where we have predecessor or successor Relation instances which link to external tasks, * replace these with new Relation instance which link to the original task. * * @param externalTask external Task instance * @param originalTask original Task instance */ private void replaceRelations(Task externalTask, Task originalTask) { RelationContainer relations = externalTask.getParentFile().getRelations(); // create copies to avoid concurrent modification List successors = new ArrayList<>(relations.getRawSuccessors(externalTask)); List predecessors = new ArrayList<>(relations.getPredecessors(externalTask)); for (Relation originalRelation : successors) { relations.remove(originalRelation); originalRelation.getSuccessorTask().addPredecessor(new Relation.Builder().from(originalRelation).predecessorTask(originalTask)); } for (Relation originalRelation : predecessors) { relations.remove(originalRelation); originalTask.addPredecessor(new Relation.Builder().from(originalRelation)); } } /** * Recursively descend through the hierarchy of tasks to identify external tasks, * and return them in the supplied list. * * @param tasks list of tasks to examine * @param externalTasks list of external tasks */ private void findExternalTasks(List tasks, List externalTasks) { externalTasks.addAll(tasks.stream().filter(t -> t.getExternalTask()).collect(Collectors.toList())); tasks.forEach(t -> findExternalTasks(t.getChildTasks(), externalTasks)); } /** * This method recursively descends through the hierarchy of tasks * to remove any external tasks which are no longer required. * * @param tasks list of tasks to examine * @param replacedTasks set of external tasks to remove */ private void removeExternalTasks(List tasks, Set replacedTasks) { tasks.removeIf(t -> replacedTasks.contains(t)); for (Task task : tasks) { removeExternalTasks(task.getChildTasks(), replacedTasks); } } /** * Called by a reader class when reading a schedule is complete. */ public void readComplete() { fixUniqueIdClashes(); } /** * This method is called to renumber any Unique ID values which * were found to have duplicates. */ public void fixUniqueIdClashes() { getTasks().fixUniqueIdClashes(); getResources().fixUniqueIdClashes(); getCalendars().fixUniqueIdClashes(); getResourceAssignments().fixUniqueIdClashes(); getRelations().fixUniqueIdClashes(); } /** * Retrieve the ObjectSequence instance used to generate Unique ID values for a given class. * * @param c target class * @return ObjectSequence instance */ @Override public ObjectSequence getUniqueIdObjectSequence(Class c) { return ProjectFileSharedData.contains(c) ? m_shared.getUniqueIdObjectSequence(c) : m_uniqueIdObjectSequences.computeIfAbsent(c.getName(), x -> new ObjectSequence(1)); } /** * Add an error which has been ignored while reading this schedule. * * @param ex ignored error */ public void addIgnoredError(Exception ex) { m_ignoredErrors.add(ex); } /** * Retrieve a list of errors ignored when reading this schedule. * * @return list of errors */ public List getIgnoredErrors() { return m_ignoredErrors; } void addExternalProject(String fileName, ProjectFile projectFile) { m_externalProjects.add(fileName, projectFile); } ProjectFile readExternalProject(String fileName) { return m_externalProjects.read(fileName); } private final ProjectConfig m_config = new ProjectConfig(); 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 m_childTasks = new ArrayList<>(); private final List m_childResources = new ArrayList<>(); private final ResourceAssignmentContainer m_assignments = new ResourceAssignmentContainer(this); private final RelationContainer m_relations = new RelationContainer(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 ViewContainer m_views = new ViewContainer(); private final EventManager m_eventManager = new EventManager(); private final DataLinkContainer m_dataLinks = new DataLinkContainer(); private final ExternalProjectContainer m_externalProjects = new ExternalProjectContainer(this); private final ProjectFile[] m_baselines = new ProjectFile[11]; private final Map> m_baselineTaskMap = new HashMap<>(); private final List m_ignoredErrors = new ArrayList<>(); private final Map m_uniqueIdObjectSequences = new HashMap<>(); private final ProjectFileSharedData m_shared; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy