/*
* Copyright (C) 2007 Snorre Gylterud, Stein Magnus Jodal, Johannes Knutsen,
* Erik Bagge Ottesen, Ralf Bjarne Taraldset, and Iterate AS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*/
package no.ntnu.mmfplanner.util;
import java.io.IOException;
import java.io.OutputStream;
import no.ntnu.mmfplanner.model.Category;
import no.ntnu.mmfplanner.model.Mmf;
import no.ntnu.mmfplanner.model.Project;
import no.ntnu.mmfplanner.ui.TabPanePanelPlacement;
import no.ntnu.mmfplanner.ui.TabPanePanelPlacement.PanelInfo;
import nu.xom.Attribute;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Serializer;
/**
* Utility class for serializing a MMF Project into an XML file.
*/
public class XmlSerializer {
/**
* Helper method for appending a new child text element to an element.
*/
private static void appendTextNode(Element e, String name, Object text) {
Element child = new Element(name);
if ((text != null) && !"".equals(text)) {
child.appendChild("" + text);
}
e.appendChild(child);
}
/**
* Creates an Element describing the entire project and all it's MMFs and
* categories.
*/
public static Element tabPanePanelPlacementToElement(
TabPanePanelPlacement placement) {
// Create panels
Element epanels = new Element("panels");
for (PanelInfo panelInfo : placement.getPanels()) {
epanels.appendChild(panelInfoToElement(panelInfo));
}
return epanels;
}
/**
* Creates an Element describing panelInfo of a panel
*/
public static Element panelInfoToElement(PanelInfo panelInfo) {
// Panel info
Element epanel = new Element("panel");
epanel.addAttribute(new Attribute("id", panelInfo.id));
appendTextNode(epanel, "visible", panelInfo.visible);
appendTextNode(epanel, "placement", panelInfo.placement);
return epanel;
}
/**
* Creates an Element describing the entire project and all it's MMFs and
* categories.
*/
public static Element projectToElement(Project project) {
// project and properties
Element eproj = new Element("project");
appendTextNode(eproj, "name", project.getName());
appendTextNode(eproj, "periods", project.getPeriods());
appendTextNode(eproj, "interestrate", project.getInterestRate());
appendTextNode(eproj, "nextid", project.getNextId());
appendTextNode(eproj, "maxmmfs", project.getMaxMmfsPerPeriod());
// categories
Element ecategories = new Element("categories");
for (Category cat : project.getCategories()) {
ecategories.appendChild(categoryToElement(project, cat));
}
eproj.appendChild(ecategories);
// mmfs
Element emmfs = new Element("mmfs");
for (int i = 0; i < project.size(); i++) {
emmfs.appendChild(mmfToElement(project, project.get(i)));
}
eproj.appendChild(emmfs);
return eproj;
}
/**
* Creates an element describing the given category.
*
* Id's are added to the category according to index in the given project,
* this id is only valid in the context of the current version of the given
* project, and can not be assumed to be valid in the future. If the
* category is not in the given project, an id of -1 is returned.
*/
public static Element categoryToElement(Project project, Category category) {
Element ecat = new Element("category");
ecat.addAttribute(new Attribute("id", ""
+ project.getCategories().indexOf(category)));
appendTextNode(ecat, "name", category.getName());
if (null == category.getColor()) {
appendTextNode(ecat, "color", null);
} else {
appendTextNode(ecat, "color", GuiUtil.getColorString(category
.getColor()));
}
if (null == category.getParent()) {
appendTextNode(ecat, "parent", null);
} else {
appendTextNode(ecat, "parent", project.getCategories().indexOf(
category.getParent()));
}
return ecat;
}
/**
* Creates and returns an element describing the given mmf.
*
* For category an id is used corresponding to the categories index in the
* given project, this id is only valid in the context of the current
* version of the given project, and can not be assumed to be valid in the
* future. If the category is not in the given project, an id of -1 is
* returned.
*/
public static Element mmfToElement(Project project, Mmf mmf) {
// mmf and properties
Element emmf = new Element("mmf");
emmf.addAttribute(new Attribute("id", mmf.getId()));
appendTextNode(emmf, "name", mmf.getName());
appendTextNode(emmf, "period", mmf.getPeriod());
appendTextNode(emmf, "locked", mmf.isLocked());
appendTextNode(emmf, "swimlane", mmf.getSwimlane());
if (null == mmf.getCategory()) {
appendTextNode(emmf, "category_ref", null);
} else {
appendTextNode(emmf, "category_ref", mmf.getProject()
.getCategories().indexOf(mmf.getCategory()));
}
// precursors
appendTextNode(emmf, "precursors", mmf.getPrecursorString());
// revenues
Element erevenues = new Element("revenues");
for (int period = 1; period <= mmf.getRevenueLength(); period++) {
Element erev = new Element("revenue");
appendTextNode(erev, "period", "" + period);
appendTextNode(erev, "value", "" + mmf.getRevenue(period));
erevenues.appendChild(erev);
}
emmf.appendChild(erevenues);
return emmf;
}
/**
* Converts the project to a XML Element and adds a XML Document as wrapper
* around the element.
*
* @see #projectToElement()
* @param mainFrame.getProject()
* the project to create a document for
* @return a XML Document element for the given project
*/
public static Document workspaceToDocument(TabPanePanelPlacement placement,
Project project) {
Element eproj = projectToElement(project);
Element esettings = new Element("settings");
if (placement != null) {
Element epanels = tabPanePanelPlacementToElement(placement);
esettings.appendChild(epanels);
}
Element eprojects = new Element("mmfproject");
eprojects.appendChild(eproj);
eprojects.appendChild(esettings);
Document doc = new Document(eprojects);
// FIXME: should verify how to correctly validate the dtd on open, or
// disable validation completely
// DocType doctype = new DocType("mmfproject",
// "https://github.com/jodal/mmfplanner/raw/HEAD/dist/mmfproject.dtd");
// doc.setDocType(doctype);
return doc;
}
/**
* Writes the project to the given {@link OutputStream} in a nicely
* formatted and valid XML-format, using UTF-8.
*
* @throws IOException
* if the underlying IO layer gives an error
* @see Serializer#write()
*/
public static void writeWorkspace(TabPanePanelPlacement placement,
Project project, OutputStream os) throws IOException {
Document doc = workspaceToDocument(placement, project);
Serializer serializer = new Serializer(os, "UTF-8");
serializer.setIndent(2);
// serializer.setMaxLength(80);
serializer.write(doc);
}
}