/*
* file: PlannerWriter.java
* author: Jon Iles
* copyright: (c) Packwood Software 2005
* date: Mar 16, 2007
*/
/*
* 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.planner;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import net.sf.mpxj.ConstraintType;
import net.sf.mpxj.DateRange;
import net.sf.mpxj.Day;
import net.sf.mpxj.Duration;
import net.sf.mpxj.EventManager;
import net.sf.mpxj.ProjectCalendar;
import net.sf.mpxj.ProjectCalendarException;
import net.sf.mpxj.ProjectCalendarHours;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.ProjectProperties;
import net.sf.mpxj.Relation;
import net.sf.mpxj.RelationType;
import net.sf.mpxj.Resource;
import net.sf.mpxj.ResourceAssignment;
import net.sf.mpxj.ResourceType;
import net.sf.mpxj.Task;
import net.sf.mpxj.TaskType;
import net.sf.mpxj.common.DateHelper;
import net.sf.mpxj.planner.schema.Allocation;
import net.sf.mpxj.planner.schema.Allocations;
import net.sf.mpxj.planner.schema.Calendars;
import net.sf.mpxj.planner.schema.Constraint;
import net.sf.mpxj.planner.schema.DayType;
import net.sf.mpxj.planner.schema.DayTypes;
import net.sf.mpxj.planner.schema.Days;
import net.sf.mpxj.planner.schema.DefaultWeek;
import net.sf.mpxj.planner.schema.Interval;
import net.sf.mpxj.planner.schema.ObjectFactory;
import net.sf.mpxj.planner.schema.OverriddenDayType;
import net.sf.mpxj.planner.schema.OverriddenDayTypes;
import net.sf.mpxj.planner.schema.Predecessor;
import net.sf.mpxj.planner.schema.Predecessors;
import net.sf.mpxj.planner.schema.Project;
import net.sf.mpxj.planner.schema.Resources;
import net.sf.mpxj.planner.schema.Tasks;
import net.sf.mpxj.writer.AbstractProjectWriter;
/**
* This class creates a new Planner file from the contents of
* a ProjectFile instance.
*/
public final class PlannerWriter extends AbstractProjectWriter
{
/**
* {@inheritDoc}
*/
@Override public void write(ProjectFile projectFile, OutputStream stream) throws IOException
{
try
{
m_projectFile = projectFile;
m_eventManager = projectFile.getEventManager();
if (CONTEXT == null)
{
throw CONTEXT_EXCEPTION;
}
Marshaller marshaller = CONTEXT.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
if (m_encoding != null)
{
marshaller.setProperty(Marshaller.JAXB_ENCODING, m_encoding);
}
//
// The Planner implementation used as the basis for this work, 0.14.1
// does not appear to have a particularly robust parser, and rejects
// files with the full XML declaration produced by JAXB. The
// following property suppresses this declaration.
//
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
m_factory = new ObjectFactory();
m_plannerProject = m_factory.createProject();
writeProjectProperties();
writeCalendars();
writeResources();
writeTasks();
writeAssignments();
marshaller.marshal(m_plannerProject, stream);
}
catch (JAXBException ex)
{
throw new IOException(ex.toString());
}
finally
{
m_projectFile = null;
m_factory = null;
m_plannerProject = null;
}
}
/**
* This method writes project properties to a Planner file.
*/
private void writeProjectProperties()
{
ProjectProperties properties = m_projectFile.getProjectProperties();
m_plannerProject.setCompany(properties.getCompany());
m_plannerProject.setManager(properties.getManager());
m_plannerProject.setName(getString(properties.getName()));
m_plannerProject.setProjectStart(getDateTime(properties.getStartDate()));
m_plannerProject.setCalendar(getIntegerString(m_projectFile.getDefaultCalendar().getUniqueID()));
m_plannerProject.setMrprojectVersion("2");
}
/**
* This method writes calendar data to a Planner file.
*
* @throws JAXBException on xml creation errors
*/
private void writeCalendars() throws JAXBException
{
//
// Create the new Planner calendar list
//
Calendars calendars = m_factory.createCalendars();
m_plannerProject.setCalendars(calendars);
writeDayTypes(calendars);
List<net.sf.mpxj.planner.schema.Calendar> calendar = calendars.getCalendar();
//
// Process each calendar in turn
//
for (ProjectCalendar mpxjCalendar : m_projectFile.getCalendars())
{
net.sf.mpxj.planner.schema.Calendar plannerCalendar = m_factory.createCalendar();
calendar.add(plannerCalendar);
writeCalendar(mpxjCalendar, plannerCalendar);
}
}
/**
* Write the standard set of day types.
*
* @param calendars parent collection of calendars
*/
private void writeDayTypes(Calendars calendars)
{
DayTypes dayTypes = m_factory.createDayTypes();
calendars.setDayTypes(dayTypes);
List<DayType> typeList = dayTypes.getDayType();
DayType dayType = m_factory.createDayType();
typeList.add(dayType);
dayType.setId("0");
dayType.setName("Working");
dayType.setDescription("A default working day");
dayType = m_factory.createDayType();
typeList.add(dayType);
dayType.setId("1");
dayType.setName("Nonworking");
dayType.setDescription("A default non working day");
dayType = m_factory.createDayType();
typeList.add(dayType);
dayType.setId("2");
dayType.setName("Use base");
dayType.setDescription("Use day from base calendar");
}
/**
* This method writes data for a single calendar to a Planner file.
*
* @param mpxjCalendar MPXJ calendar instance
* @param plannerCalendar Planner calendar instance
* @throws JAXBException on xml creation errors
*/
private void writeCalendar(ProjectCalendar mpxjCalendar, net.sf.mpxj.planner.schema.Calendar plannerCalendar) throws JAXBException
{
//
// Populate basic details
//
plannerCalendar.setId(getIntegerString(mpxjCalendar.getUniqueID()));
plannerCalendar.setName(getString(mpxjCalendar.getName()));
//
// Set working and non working days
//
DefaultWeek dw = m_factory.createDefaultWeek();
plannerCalendar.setDefaultWeek(dw);
dw.setMon(getWorkingDayString(mpxjCalendar, Day.MONDAY));
dw.setTue(getWorkingDayString(mpxjCalendar, Day.TUESDAY));
dw.setWed(getWorkingDayString(mpxjCalendar, Day.WEDNESDAY));
dw.setThu(getWorkingDayString(mpxjCalendar, Day.THURSDAY));
dw.setFri(getWorkingDayString(mpxjCalendar, Day.FRIDAY));
dw.setSat(getWorkingDayString(mpxjCalendar, Day.SATURDAY));
dw.setSun(getWorkingDayString(mpxjCalendar, Day.SUNDAY));
//
// Set working hours
//
OverriddenDayTypes odt = m_factory.createOverriddenDayTypes();
plannerCalendar.setOverriddenDayTypes(odt);
List<OverriddenDayType> typeList = odt.getOverriddenDayType();
Sequence uniqueID = new Sequence(0);
//
// This is a bit arbitrary, so not ideal, however...
// The idea here is that MS Project allows us to specify working hours
// for each day of the week individually. Planner doesn't do this,
// but instead allows us to specify working hours for each day type.
// What we are doing here is stepping through the days of the week to
// find the first working day, then using the hours for that day
// as the hours for the working day type in Planner.
//
for (int dayLoop = 1; dayLoop < 8; dayLoop++)
{
Day day = Day.getInstance(dayLoop);
if (mpxjCalendar.isWorkingDay(day))
{
processWorkingHours(mpxjCalendar, uniqueID, day, typeList);
break;
}
}
//
// Process exception days
//
Days plannerDays = m_factory.createDays();
plannerCalendar.setDays(plannerDays);
List<net.sf.mpxj.planner.schema.Day> dayList = plannerDays.getDay();
processExceptionDays(mpxjCalendar, dayList);
m_eventManager.fireCalendarWrittenEvent(mpxjCalendar);
//
// Process any derived calendars
//
List<net.sf.mpxj.planner.schema.Calendar> calendarList = plannerCalendar.getCalendar();
for (ProjectCalendar mpxjDerivedCalendar : mpxjCalendar.getDerivedCalendars())
{
net.sf.mpxj.planner.schema.Calendar plannerDerivedCalendar = m_factory.createCalendar();
calendarList.add(plannerDerivedCalendar);
writeCalendar(mpxjDerivedCalendar, plannerDerivedCalendar);
}
}
/**
* Process the standard working hours for a given day.
*
* @param mpxjCalendar MPXJ Calendar instance
* @param uniqueID unique ID sequence generation
* @param day Day instance
* @param typeList Planner list of days
*/
private void processWorkingHours(ProjectCalendar mpxjCalendar, Sequence uniqueID, Day day, List<OverriddenDayType> typeList)
{
if (isWorkingDay(mpxjCalendar, day))
{
ProjectCalendarHours mpxjHours = mpxjCalendar.getCalendarHours(day);
if (mpxjHours != null)
{
OverriddenDayType odt = m_factory.createOverriddenDayType();
typeList.add(odt);
odt.setId(getIntegerString(uniqueID.next()));
List<Interval> intervalList = odt.getInterval();
for (DateRange mpxjRange : mpxjHours)
{
Date rangeStart = mpxjRange.getStart();
Date rangeEnd = mpxjRange.getEnd();
if (rangeStart != null && rangeEnd != null)
{
Interval interval = m_factory.createInterval();
intervalList.add(interval);
interval.setStart(getTimeString(rangeStart));
interval.setEnd(getTimeString(rangeEnd));
}
}
}
}
}
/**
* Process exception days.
*
* @param mpxjCalendar MPXJ Calendar instance
* @param dayList Planner list of exception days
*/
private void processExceptionDays(ProjectCalendar mpxjCalendar, List<net.sf.mpxj.planner.schema.Day> dayList)
{
for (ProjectCalendarException mpxjCalendarException : mpxjCalendar.getCalendarExceptions())
{
Date rangeStartDay = mpxjCalendarException.getFromDate();
Date rangeEndDay = mpxjCalendarException.getToDate();
if (DateHelper.getDayStartDate(rangeStartDay).getTime() == DateHelper.getDayEndDate(rangeEndDay).getTime())
{
//
// Exception covers a single day
//
net.sf.mpxj.planner.schema.Day day = m_factory.createDay();
dayList.add(day);
day.setType("day-type");
day.setDate(getDateString(mpxjCalendarException.getFromDate()));
day.setId(mpxjCalendarException.getWorking() ? "0" : "1");
}
else
{
//
// Exception covers a range of days
//
Calendar cal = Calendar.getInstance();
cal.setTime(rangeStartDay);
while (cal.getTime().getTime() < rangeEndDay.getTime())
{
net.sf.mpxj.planner.schema.Day day = m_factory.createDay();
dayList.add(day);
day.setType("day-type");
day.setDate(getDateString(cal.getTime()));
day.setId(mpxjCalendarException.getWorking() ? "0" : "1");
cal.add(Calendar.DAY_OF_YEAR, 1);
}
}
/**
* @TODO we need to deal with date ranges here
*/
}
}
/**
* This method writes resource data to a Planner file.
*/
private void writeResources()
{
Resources resources = m_factory.createResources();
m_plannerProject.setResources(resources);
List<net.sf.mpxj.planner.schema.Resource> resourceList = resources.getResource();
for (Resource mpxjResource : m_projectFile.getAllResources())
{
net.sf.mpxj.planner.schema.Resource plannerResource = m_factory.createResource();
resourceList.add(plannerResource);
writeResource(mpxjResource, plannerResource);
}
}
/**
* This method writes data for a single resource to a Planner file.
*
* @param mpxjResource MPXJ Resource instance
* @param plannerResource Planner Resource instance
*/
private void writeResource(Resource mpxjResource, net.sf.mpxj.planner.schema.Resource plannerResource)
{
ProjectCalendar resourceCalendar = mpxjResource.getResourceCalendar();
if (resourceCalendar != null)
{
plannerResource.setCalendar(getIntegerString(resourceCalendar.getUniqueID()));
}
plannerResource.setEmail(mpxjResource.getEmailAddress());
plannerResource.setId(getIntegerString(mpxjResource.getUniqueID()));
plannerResource.setName(getString(mpxjResource.getName()));
plannerResource.setNote(mpxjResource.getNotes());
plannerResource.setShortName(mpxjResource.getInitials());
plannerResource.setType(mpxjResource.getType() == ResourceType.MATERIAL ? "2" : "1");
//plannerResource.setStdRate();
//plannerResource.setOvtRate();
plannerResource.setUnits("0");
//plannerResource.setProperties();
m_eventManager.fireResourceWrittenEvent(mpxjResource);
}
/**
* This method writes task data to a Planner file.
*
* @throws JAXBException on xml creation errors
*/
private void writeTasks() throws JAXBException
{
Tasks tasks = m_factory.createTasks();
m_plannerProject.setTasks(tasks);
List<net.sf.mpxj.planner.schema.Task> taskList = tasks.getTask();
for (Task task : m_projectFile.getChildTasks())
{
writeTask(task, taskList);
}
}
/**
* This method writes data for a single task to a Planner file.
*
* @param mpxjTask MPXJ Task instance
* @param taskList list of child tasks for current parent
*/
private void writeTask(Task mpxjTask, List<net.sf.mpxj.planner.schema.Task> taskList) throws JAXBException
{
net.sf.mpxj.planner.schema.Task plannerTask = m_factory.createTask();
taskList.add(plannerTask);
plannerTask.setEnd(getDateTimeString(mpxjTask.getFinish()));
plannerTask.setId(getIntegerString(mpxjTask.getUniqueID()));
plannerTask.setName(getString(mpxjTask.getName()));
plannerTask.setNote(mpxjTask.getNotes());
plannerTask.setPercentComplete(getIntegerString(mpxjTask.getPercentageWorkComplete()));
plannerTask.setPriority(mpxjTask.getPriority() == null ? null : getIntegerString(mpxjTask.getPriority().getValue() * 10));
plannerTask.setScheduling(getScheduling(mpxjTask.getType()));
plannerTask.setStart(getDateTimeString(DateHelper.getDayStartDate(mpxjTask.getStart())));
if (mpxjTask.getMilestone())
{
plannerTask.setType("milestone");
}
else
{
plannerTask.setType("normal");
}
plannerTask.setWork(getDurationString(mpxjTask.getWork()));
plannerTask.setWorkStart(getDateTimeString(mpxjTask.getStart()));
ConstraintType mpxjConstraintType = mpxjTask.getConstraintType();
if (mpxjConstraintType != ConstraintType.AS_SOON_AS_POSSIBLE)
{
Constraint plannerConstraint = m_factory.createConstraint();
plannerTask.setConstraint(plannerConstraint);
if (mpxjConstraintType == ConstraintType.START_NO_EARLIER_THAN)
{
plannerConstraint.setType("start-no-earlier-than");
}
else
{
if (mpxjConstraintType == ConstraintType.MUST_START_ON)
{
plannerConstraint.setType("must-start-on");
}
}
plannerConstraint.setTime(getDateTimeString(mpxjTask.getConstraintDate()));
}
//
// Write predecessors
//
writePredecessors(mpxjTask, plannerTask);
m_eventManager.fireTaskWrittenEvent(mpxjTask);
//
// Write child tasks
//
List<net.sf.mpxj.planner.schema.Task> childTaskList = plannerTask.getTask();
for (Task task : mpxjTask.getChildTasks())
{
writeTask(task, childTaskList);
}
}
/**
* This method writes predecessor data to a Planner file.
* We have to deal with a slight anomaly in this method that is introduced
* by the MPX file format. It would be possible for someone to create an
* MPX file with both the predecessor list and the unique ID predecessor
* list populated... which means that we must process both and avoid adding
* duplicate predecessors. Also interesting to note is that MSP98 populates
* the predecessor list, not the unique ID predecessor list, as you might
* expect.
*
* @param mpxjTask MPXJ task instance
* @param plannerTask planner task instance
*/
private void writePredecessors(Task mpxjTask, net.sf.mpxj.planner.schema.Task plannerTask)
{
Predecessors plannerPredecessors = m_factory.createPredecessors();
plannerTask.setPredecessors(plannerPredecessors);
List<Predecessor> predecessorList = plannerPredecessors.getPredecessor();
int id = 0;
List<Relation> predecessors = mpxjTask.getPredecessors();
if (predecessors != null)
{
for (Relation rel : predecessors)
{
Integer taskUniqueID = rel.getTargetTask().getUniqueID();
Predecessor plannerPredecessor = m_factory.createPredecessor();
plannerPredecessor.setId(getIntegerString(++id));
plannerPredecessor.setPredecessorId(getIntegerString(taskUniqueID));
plannerPredecessor.setLag(getDurationString(rel.getLag()));
plannerPredecessor.setType(RELATIONSHIP_TYPES.get(rel.getType()));
predecessorList.add(plannerPredecessor);
m_eventManager.fireRelationWrittenEvent(rel);
}
}
}
/**
* This method writes assignment data to a Planner file.
*
*/
private void writeAssignments()
{
Allocations allocations = m_factory.createAllocations();
m_plannerProject.setAllocations(allocations);
List<Allocation> allocationList = allocations.getAllocation();
for (ResourceAssignment mpxjAssignment : m_projectFile.getAllResourceAssignments())
{
Allocation plannerAllocation = m_factory.createAllocation();
allocationList.add(plannerAllocation);
plannerAllocation.setTaskId(getIntegerString(mpxjAssignment.getTask().getUniqueID()));
plannerAllocation.setResourceId(getIntegerString(mpxjAssignment.getResourceUniqueID()));
plannerAllocation.setUnits(getIntegerString(mpxjAssignment.getUnits()));
m_eventManager.fireAssignmentWrittenEvent(mpxjAssignment);
}
}
/**
* Convert a Planner date-time value into a Java date.
*
* 20070222T080000Z
*
* @param value Planner date-time
* @return Java Date instance
*/
private String getDateTime(Date value)
{
StringBuilder result = new StringBuilder(16);
if (value != null)
{
Calendar cal = Calendar.getInstance();
cal.setTime(value);
result.append(m_fourDigitFormat.format(cal.get(Calendar.YEAR)));
result.append(m_twoDigitFormat.format(cal.get(Calendar.MONTH) + 1));
result.append(m_twoDigitFormat.format(cal.get(Calendar.DAY_OF_MONTH)));
result.append("T");
result.append(m_twoDigitFormat.format(cal.get(Calendar.HOUR_OF_DAY)));
result.append(m_twoDigitFormat.format(cal.get(Calendar.MINUTE)));
result.append(m_twoDigitFormat.format(cal.get(Calendar.SECOND)));
result.append("Z");
}
return (result.toString());
}
/**
* Convert an Integer value into a String.
*
* @param value Integer value
* @return String value
*/
private String getIntegerString(Number value)
{
return (value == null ? null : Integer.toString(value.intValue()));
}
/**
* Convert an int value into a String.
*
* @param value int value
* @return String value
*/
private String getIntegerString(int value)
{
return (Integer.toString(value));
}
/**
* Used to determine if a particular day of the week is normally
* a working day.
*
* @param mpxjCalendar ProjectCalendar instance
* @param day Day instance
* @return boolean flag
*/
private boolean isWorkingDay(ProjectCalendar mpxjCalendar, Day day)
{
boolean result = false;
switch (mpxjCalendar.getWorkingDay(day))
{
case WORKING:
{
result = true;
break;
}
case NON_WORKING:
{
result = false;
break;
}
case DEFAULT:
{
result = isWorkingDay(mpxjCalendar.getParent(), day);
break;
}
}
return (result);
}
/**
* Returns a flag represented as a String, indicating if
* the supplied day is a working day.
*
* @param mpxjCalendar MPXJ ProjectCalendar instance
* @param day Day instance
* @return boolean flag as a string
*/
private String getWorkingDayString(ProjectCalendar mpxjCalendar, Day day)
{
String result = null;
switch (mpxjCalendar.getWorkingDay(day))
{
case WORKING:
{
result = "0";
break;
}
case NON_WORKING:
{
result = "1";
break;
}
case DEFAULT:
{
result = "2";
break;
}
}
return (result);
}
/**
* Convert a Java date into a Planner time.
*
* 0800
*
* @param value Java Date instance
* @return Planner time value
*/
private String getTimeString(Date value)
{
Calendar cal = Calendar.getInstance();
cal.setTime(value);
int hours = cal.get(Calendar.HOUR_OF_DAY);
int minutes = cal.get(Calendar.MINUTE);
StringBuilder sb = new StringBuilder(4);
sb.append(m_twoDigitFormat.format(hours));
sb.append(m_twoDigitFormat.format(minutes));
return (sb.toString());
}
/**
* Convert a Java date into a Planner date.
*
* 20070222
*
* @param value Java Date instance
* @return Planner date
*/
private String getDateString(Date value)
{
Calendar cal = Calendar.getInstance();
cal.setTime(value);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
StringBuilder sb = new StringBuilder(8);
sb.append(m_fourDigitFormat.format(year));
sb.append(m_twoDigitFormat.format(month));
sb.append(m_twoDigitFormat.format(day));
return (sb.toString());
}
/**
* Convert a Java date into a Planner date-time string.
*
* 20070222T080000Z
*
* @param value Java date
* @return Planner date-time string
*/
private String getDateTimeString(Date value)
{
String result = null;
if (value != null)
{
Calendar cal = Calendar.getInstance();
cal.setTime(value);
StringBuilder sb = new StringBuilder(16);
sb.append(m_fourDigitFormat.format(cal.get(Calendar.YEAR)));
sb.append(m_twoDigitFormat.format(cal.get(Calendar.MONTH) + 1));
sb.append(m_twoDigitFormat.format(cal.get(Calendar.DAY_OF_MONTH)));
sb.append('T');
sb.append(m_twoDigitFormat.format(cal.get(Calendar.HOUR_OF_DAY)));
sb.append(m_twoDigitFormat.format(cal.get(Calendar.MINUTE)));
sb.append(m_twoDigitFormat.format(cal.get(Calendar.SECOND)));
sb.append('Z');
result = sb.toString();
}
return result;
}
/**
* Converts an MPXJ Duration instance into the string representation
* of a Planner duration.
*
* Planner represents durations as a number of seconds in its
* file format, however it displays durations as days and hours,
* and seems to assume that a working day is 8 hours.
*
* @param value string representation of a duration
* @return Duration instance
*/
private String getDurationString(Duration value)
{
String result = null;
if (value != null)
{
double seconds = 0;
switch (value.getUnits())
{
case MINUTES:
case ELAPSED_MINUTES:
{
seconds = value.getDuration() * 60;
break;
}
case HOURS:
case ELAPSED_HOURS:
{
seconds = value.getDuration() * (60 * 60);
break;
}
case DAYS:
{
double minutesPerDay = m_projectFile.getProjectProperties().getMinutesPerDay().doubleValue();
seconds = value.getDuration() * (minutesPerDay * 60);
break;
}
case ELAPSED_DAYS:
{
seconds = value.getDuration() * (24 * 60 * 60);
break;
}
case WEEKS:
{
double minutesPerWeek = m_projectFile.getProjectProperties().getMinutesPerWeek().doubleValue();
seconds = value.getDuration() * (minutesPerWeek * 60);
break;
}
case ELAPSED_WEEKS:
{
seconds = value.getDuration() * (7 * 24 * 60 * 60);
break;
}
case MONTHS:
{
double minutesPerDay = m_projectFile.getProjectProperties().getMinutesPerDay().doubleValue();
double daysPerMonth = m_projectFile.getProjectProperties().getDaysPerMonth().doubleValue();
seconds = value.getDuration() * (daysPerMonth * minutesPerDay * 60);
break;
}
case ELAPSED_MONTHS:
{
seconds = value.getDuration() * (30 * 24 * 60 * 60);
break;
}
case YEARS:
{
double minutesPerDay = m_projectFile.getProjectProperties().getMinutesPerDay().doubleValue();
double daysPerMonth = m_projectFile.getProjectProperties().getDaysPerMonth().doubleValue();
seconds = value.getDuration() * (12 * daysPerMonth * minutesPerDay * 60);
break;
}
case ELAPSED_YEARS:
{
seconds = value.getDuration() * (365 * 24 * 60 * 60);
break;
}
default:
{
break;
}
}
result = Long.toString((long) seconds);
}
return (result);
}
/**
* Convert a string representation of the task type
* into a TaskType instance.
*
* @param value string value
* @return TaskType value
*/
private String getScheduling(TaskType value)
{
String result = "fixed-work";
if (value != null && value == TaskType.FIXED_DURATION)
{
result = "fixed-duration";
}
return (result);
}
/**
* Writes a string value, ensuring that null is mapped to an empty string.
*
* @param value string value
* @return string value
*/
private String getString(String value)
{
return (value == null ? "" : value);
}
/**
* Set the encoding used to write the file. By default UTF-8 is used.
*
* @param encoding encoding name
*/
public void setEncoding(String encoding)
{
m_encoding = encoding;
}
/**
* Retrieve the encoding used to write teh file. If this value is null,
* UTF-8 is used.
*
* @return encoding name
*/
public String getEncoding()
{
return m_encoding;
}
private String m_encoding;
private ProjectFile m_projectFile;
private EventManager m_eventManager;
private ObjectFactory m_factory;
private Project m_plannerProject;
private NumberFormat m_twoDigitFormat = new DecimalFormat("00");
private NumberFormat m_fourDigitFormat = new DecimalFormat("0000");
private static Map<RelationType, String> RELATIONSHIP_TYPES = new HashMap<RelationType, String>();
static
{
RELATIONSHIP_TYPES.put(RelationType.FINISH_FINISH, "FF");
RELATIONSHIP_TYPES.put(RelationType.FINISH_START, "FS");
RELATIONSHIP_TYPES.put(RelationType.START_FINISH, "SF");
RELATIONSHIP_TYPES.put(RelationType.START_START, "SS");
}
/**
* Cached context to minimise construction cost.
*/
private static JAXBContext CONTEXT;
/**
* Note any error occurring during context construction.
*/
private static JAXBException CONTEXT_EXCEPTION;
static
{
try
{
//
// JAXB RI property to speed up construction
//
System.setProperty("com.sun.xml.bind.v2.runtime.JAXBContextImpl.fastBoot", "true");
//
// Construct the context
//
CONTEXT = JAXBContext.newInstance("net.sf.mpxj.planner.schema", PlannerWriter.class.getClassLoader());
}
catch (JAXBException ex)
{
CONTEXT_EXCEPTION = ex;
CONTEXT = null;
}
}
}