rjc.jplanner.model.Plan.java Source code

Java tutorial

Introduction

Here is the source code for rjc.jplanner.model.Plan.java

Source

/**************************************************************************
 *  Copyright (C) 2015 by Richard Crook                                   *
 *  https://github.com/dazzle50/JPlannerSWT                               *
 *                                                                        *
 *  This program is free software: you can redistribute it and/or modify  *
 *  it under the terms of the GNU General Public License as published by  *
 *  the Free Software Foundation, either version 3 of the License, or     *
 *  (at your option) any later version.                                   *
 *                                                                        *
 *  This program 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 General Public License for more details.                          *
 *                                                                        *
 *  You should have received a copy of the GNU General Public License     *
 *  along with this program.  If not, see http://www.gnu.org/licenses/    *
 **************************************************************************/

package rjc.jplanner.model;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;

import org.apache.commons.lang.StringEscapeUtils;

import rjc.jplanner.JPlanner;
import rjc.jplanner.XmlLabels;
import rjc.jplanner.command.UndoStack;

/*************************************************************************************************/
/************************** Holds the complete data model for the plan ***************************/
/*************************************************************************************************/

public class Plan {
    private String m_title; // plan title as set in properties
    private DateTime m_start; // plan start date-time as set in properties
    private Calendar m_calendar; // plan's default calendar
    private String m_datetimeFormat; // format to display date-times
    private String m_dateFormat; // format to display dates
    private String m_filename; // filename when saved or loaded
    private String m_fileLocation; // file location
    private String m_savedBy; // who saved last
    private DateTime m_savedWhen; // when was last saved
    private String m_notes; // plan notes as on plan tab

    private UndoStack m_undostack; // undo stack for plan editing

    public Tasks tasks; // list of plan tasks
    public Resources resources; // list of plan resources
    public Calendars calendars; // list of plan calendars
    public Days daytypes; // list of plan day types

    /**************************************** constructor ******************************************/
    public Plan() {
        // construct empty but usable Plan
        tasks = new Tasks();
        resources = new Resources();
        calendars = new Calendars();
        daytypes = new Days();

        m_undostack = new UndoStack();

        m_title = "";
        m_datetimeFormat = "EEE dd/MM/yyyy HH:mm";
        m_dateFormat = "dd/MM/yyyy";
        m_filename = "";
        m_fileLocation = "";
        m_savedBy = "";
        m_notes = "";
    }

    /***************************************** toString ********************************************/
    @Override
    public String toString() {
        // convert to string
        String hash = super.toString();
        String id = hash.substring(hash.lastIndexOf('.') + 1);
        return id + "[" + m_title + ", " + m_start + ", " + tasks.size() + " Tasks, " + resources.size()
                + " Resources, " + calendars.size() + " Calendars, " + daytypes.size() + " DayTypes]";
    }

    /**************************************** initialise *******************************************/
    public void initialise() {
        // initialise plan with default settings and contents
        daytypes.initialise();
        calendars.initialise();
        resources.initialise();
        tasks.initialise();

        m_calendar = calendar(0);
        m_start = m_calendar.roundUp(new DateTime(Date.now(), Time.MIN_VALUE));
    }

    /************************************** tasksNotNullCount **************************************/
    public int tasksNotNullCount() {
        // return number of not-null tasks in plan (skipping special task 0)
        int count = 0;
        for (int id = 1; id < tasks.size(); id++)
            if (!tasks.get(id).isNull())
                count++;

        return count;
    }

    /************************************ resourcesNotNullCount ************************************/
    public int resourcesNotNullCount() {
        // return number of not-null resources in plan (skipping special resource 0)
        int count = 0;
        for (int id = 1; id < resources.size(); id++)
            if (!resources.get(id).isNull())
                count++;

        return count;
    }

    /**************************************** tasksCount *******************************************/
    public int tasksCount() {
        // return number of tasks in plan (including null tasks)
        return tasks.size();
    }

    /************************************** resourcesCount *****************************************/
    public int resourcesCount() {
        // return number of resources in plan (including null resources)
        return resources.size();
    }

    /************************************** calendarsCount *****************************************/
    public int calendarsCount() {
        // return number of calendars in plan
        return calendars.size();
    }

    /***************************************** daysCount *******************************************/
    public int daysCount() {
        // return number of day-types in plan
        return daytypes.size();
    }

    /******************************************** task *********************************************/
    public Task task(int index) {
        // return task corresponding to index
        return tasks.get(index);
    }

    public int index(Task task) {
        return tasks.indexOf(task);
    }

    /****************************************** resource *******************************************/
    public Resource resource(int index) {
        // return resource corresponding to index
        return resources.get(index);
    }

    public int index(Resource res) {
        return resources.indexOf(res);
    }

    /****************************************** calendar *******************************************/
    public Calendar calendar(int index) {
        // return calendar corresponding to index
        return calendars.get(index);
    }

    public int index(Calendar cal) {
        return calendars.indexOf(cal);
    }

    /********************************************* day *********************************************/
    public Day day(int index) {
        // return day-type corresponding to index
        return daytypes.get(index);
    }

    public int index(Day day) {
        return daytypes.indexOf(day);
    }

    /******************************************** title ********************************************/
    public String title() {
        return m_title;
    }

    /******************************************** notes ********************************************/
    public String notes() {
        return m_notes;
    }

    /******************************************** start ********************************************/
    public DateTime start() {
        return m_start;
    }

    /****************************************** earliest *******************************************/
    public DateTime earliest() {
        // return start date-time of earliest starting plan task, or null if no tasks
        DateTime earliest = DateTime.MAX_VALUE;

        for (Task task : tasks)
            if (!task.isNull() && !task.isSummary() && task.start().isLessThan(earliest))
                earliest = task.start();

        if (earliest == DateTime.MAX_VALUE)
            return null;
        return earliest;
    }

    /********************************************* end *********************************************/
    public DateTime end() {
        // return end date-time of latest ending plan task, or null if no tasks
        DateTime latest = DateTime.MIN_VALUE;

        for (Task task : tasks)
            if (!task.isNull() && !task.isSummary() && latest.isLessThan(task.end()))
                latest = task.end();

        if (latest == DateTime.MIN_VALUE)
            return null;
        return latest;
    }

    /******************************************* calendar ******************************************/
    public Calendar calendar() {
        return m_calendar;
    }

    /**************************************** datetimeFormat ***************************************/
    public String datetimeFormat() {
        return m_datetimeFormat;
    }

    /****************************************** dateFormat *****************************************/
    public String dateFormat() {
        return m_dateFormat;
    }

    /******************************************* filename ******************************************/
    public String filename() {
        return m_filename;
    }

    /***************************************** fileLocation ****************************************/
    public String fileLocation() {
        return m_fileLocation;
    }

    /******************************************* savedBy *******************************************/
    public String savedBy() {
        return m_savedBy;
    }

    /****************************************** savedWhen ******************************************/
    public DateTime savedWhen() {
        return m_savedWhen;
    }

    /****************************************** undostack ******************************************/
    public UndoStack undostack() {
        return m_undostack;
    }

    /******************************************* setNotes ******************************************/
    public void setNotes(String notes) {
        m_notes = notes;
    }

    /******************************************* setTitle ******************************************/
    public void setTitle(String title) {
        m_title = title;
    }

    /******************************************* setStart ******************************************/
    public void setStart(DateTime start) {
        m_start = start;
    }

    /****************************************** setCalendar ****************************************/
    public void setCalendar(Calendar cal) {
        m_calendar = cal;
    }

    /*************************************** setDatetimeFormat *************************************/
    public void setDatetimeFormat(String DTformat) {
        m_datetimeFormat = DTformat;
    }

    /**************************************** setDateFormat ****************************************/
    public void setDateFormat(String Dformat) {
        m_dateFormat = Dformat;
    }

    /*************************************** setFileDetails ****************************************/
    public void setFileDetails(String name, String loc, String user, DateTime when) {
        // set details related to file 
        m_filename = name;
        m_fileLocation = loc;
        m_savedBy = user;
        m_savedWhen = when;
    }

    /****************************************** savePlan *******************************************/
    public boolean savePlan(XMLStreamWriter xsw, FileOutputStream fos) {
        // save plan to specified XML stream
        try {
            // write plan data to XML stream
            xsw.writeStartElement(XmlLabels.XML_PLAN_DATA);
            xsw.writeAttribute(XmlLabels.XML_TITLE, m_title);
            xsw.writeAttribute(XmlLabels.XML_START, m_start.toString());
            xsw.writeAttribute(XmlLabels.XML_CALENDAR, Integer.toString(index(m_calendar)));
            xsw.writeAttribute(XmlLabels.XML_DT_FORMAT, m_datetimeFormat);
            xsw.writeAttribute(XmlLabels.XML_D_FORMAT, m_dateFormat);

            // because XMLStreamWriter doesn't encode new-lines correctly 
            // write notes attribute directly instead of xsw.writeAttribute( XML_NOTES, m_notes );
            String notes = StringEscapeUtils.escapeXml(m_notes).replaceAll("\\n", "&#10;");
            notes = notes.replaceAll("\\r", "");
            notes = " " + XmlLabels.XML_NOTES + "=\"" + notes + "\"";
            fos.write(notes.getBytes(Charset.forName(XmlLabels.ENCODING)));

            // write day, calendar, resource, and task data to XML stream
            daytypes.writeXML(xsw);
            calendars.writeXML(xsw);
            resources.writeXML(xsw);
            tasks.writeXML(xsw);

            xsw.writeEndElement(); // XML_PLAN_DATA
            return true;
        } catch (XMLStreamException | IOException exception) {
            // some sort of exception thrown
            exception.printStackTrace();
            return false;
        }
    }

    /******************************************* loadXML *******************************************/
    public void loadXML(XMLStreamReader xsr, String filename, String fileloc) throws XMLStreamException {
        // as id of plan-calendar read before the calendars, need temporary store
        int calendarId = -1;

        // load plan from XML stream
        while (xsr.hasNext()) {
            // if reached end of plan data, exit loop
            if (xsr.isEndElement() && xsr.getLocalName().equals(XmlLabels.XML_PLAN_DATA))
                break;

            // if start element read data
            if (xsr.isStartElement())
                switch (xsr.getLocalName()) {
                case XmlLabels.XML_JPLANNER:
                    loadXmlJPlanner(xsr);
                    break;
                case XmlLabels.XML_PLAN_DATA:
                    calendarId = loadXmlPlan(xsr);
                    break;
                case XmlLabels.XML_DAY_DATA:
                    daytypes.loadXML(xsr);
                    break;
                case XmlLabels.XML_CAL_DATA:
                    calendars.loadXML(xsr);
                    break;
                case XmlLabels.XML_RES_DATA:
                    resources.loadXML(xsr);
                    break;
                case XmlLabels.XML_TASK_DATA:
                    tasks.loadXML(xsr);
                    break;
                default:
                    JPlanner.trace("Unhandled start element '" + xsr.getLocalName() + "'");
                    break;
                }

            xsr.next();
        }

        // if calendar-id still negative, default to first calendar
        if (calendarId < 0)
            m_calendar = calendar(0);
        else
            m_calendar = calendar(calendarId);

        m_filename = filename;
        m_fileLocation = fileloc;
    }

    /***************************************** loadXmlPlan *****************************************/
    private int loadXmlPlan(XMLStreamReader xsr) throws XMLStreamException {
        // as calendars not yet loaded just keep calendar-id
        int calendarId = -1;

        // read XML plan attributes
        for (int i = 0; i < xsr.getAttributeCount(); i++)
            switch (xsr.getAttributeLocalName(i)) {
            case XmlLabels.XML_TITLE:
                m_title = xsr.getAttributeValue(i);
                break;
            case XmlLabels.XML_START:
                m_start = new DateTime(xsr.getAttributeValue(i));
                break;
            case XmlLabels.XML_DT_FORMAT:
                m_datetimeFormat = xsr.getAttributeValue(i);
                break;
            case XmlLabels.XML_D_FORMAT:
                m_dateFormat = xsr.getAttributeValue(i);
                break;
            case XmlLabels.XML_CALENDAR:
                calendarId = Integer.parseInt(xsr.getAttributeValue(i));
                break;
            case XmlLabels.XML_NOTES:
                m_notes = xsr.getAttributeValue(i);
                break;
            default:
                JPlanner.trace("Unhandled attribute '" + xsr.getAttributeLocalName(i) + "'");
                break;
            }

        // return calendar-id to be set as default calendar
        return calendarId;
    }

    /*************************************** loadXmlJPlanner ***************************************/
    private void loadXmlJPlanner(XMLStreamReader xsr) throws XMLStreamException {
        // read XML JPlanner attributes
        for (int i = 0; i < xsr.getAttributeCount(); i++)
            switch (xsr.getAttributeLocalName(i)) {
            case XmlLabels.XML_SAVEUSER:
                m_savedBy = xsr.getAttributeValue(i);
                break;
            case XmlLabels.XML_SAVEWHEN:
                m_savedWhen = new DateTime(xsr.getAttributeValue(i));
                break;
            case XmlLabels.XML_FORMAT:
            case XmlLabels.XML_SAVENAME:
            case XmlLabels.XML_SAVEWHERE:
                break;
            default:
                JPlanner.trace("Unhandled attribute '" + xsr.getAttributeLocalName(i) + "'");
                break;
            }
    }

    /******************************************* errors ********************************************/
    public String errors() {
        // check what errors plan may have
        if (daysCount() == 0)
            return "No day-types";

        if (calendarsCount() == 0)
            return "No calendars";

        if (index(calendar()) == -1)
            return "Invalid default calendar";

        return null;
    }

    /******************************************* stretch *******************************************/
    public DateTime stretch(DateTime dt, boolean stretchTasks) {
        // if input date-time is null return null
        if (dt == null)
            return dt;

        // return date-time stretched across full 24 hrs if plan stretchTasks flag is true
        if (stretchTasks) {
            Time time = m_calendar.day(dt.date()).stretch(dt.time());
            return new DateTime(dt.date(), time);
        }

        // plan stretchTasks flag not true, so return original date-time
        return dt;
    }

    /****************************************** schedule *******************************************/
    public void schedule() {
        // schedule the plan!
        JPlanner.trace("============================== SCHEDULE started ==============================");
        resources.clearAllocations();
        tasks.schedule();
        JPlanner.trace("============================== SCHEDULE finished ==============================");
    }

}