package uk.ac.lkl.migen.mockup.polydials.xml;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.swing.JComponent;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import uk.ac.lkl.migen.mockup.polydials.model.CounterGroup;
import uk.ac.lkl.migen.mockup.polydials.model.CounterGroupExpression;
import uk.ac.lkl.migen.mockup.polydials.model.CounterGroupTerm;
import uk.ac.lkl.migen.mockup.polydials.model.CounterModel;
import uk.ac.lkl.migen.mockup.polydials.model.Equivalence;
import uk.ac.lkl.migen.mockup.polydials.model.ModuloCounter;
import uk.ac.lkl.migen.mockup.polydials.ui.CounterGroupManager;
import uk.ac.lkl.migen.mockup.polydials.ui.Dial;
import uk.ac.lkl.migen.mockup.polydials.ui.DialSetView;
/**
*
*
*
* @author $Author: toontalk@gmail.com $
* @version $Revision: 2830 $
* @version $Date: 2009-06-15 23:36:24 -0700 (Mon, 15 Jun 2009) $
*
*/
public class Reader {
private File file;
private CounterModel model;
private DialSetView dialView;
private HashMap<String, ModuloCounter> idToCounterMap;
private HashMap<String, CounterGroup> idToCounterGroupMap;
public Reader(String filename) {
this(new File(filename));
}
public Reader(File file) {
this.file = file;
}
public void read(DialSetView dialView) throws BuilderException {
try {
this.dialView = dialView;
model = dialView.getModel();
model.clear();
idToCounterMap = new HashMap<String, ModuloCounter>();
idToCounterGroupMap = new HashMap<String, CounterGroup>();
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(file);
// this all needs cleanup
NodeList list = document.getElementsByTagName("CounterSet");
if (list.getLength() != 1)
throw new IllegalArgumentException(
"File should have a single CounterSet block");
Node counterSetNode = list.item(0);
processCounterSetElement((Element) counterSetNode);
list = document.getElementsByTagName("CounterGroupSet");
if (list.getLength() != 1)
throw new IllegalArgumentException(
"File should have a single CounterGroupSet block");
Node counterGroupSetNode = list.item(0);
processCounterGroupSetElement((Element) counterGroupSetNode);
list = document.getElementsByTagName("Equivalences");
if (list.getLength() > 1)
throw new IllegalArgumentException(
"File should have a single Equivalences block");
// is optional. Needs refining.
if (list.getLength() == 1) {
Node equivalencesNode = list.item(0);
processEquivalencesElement((Element) equivalencesNode);
}
list = document.getElementsByTagName("DialSet");
if (list.getLength() != 1)
throw new IllegalArgumentException(
"File should have a single DialSet block");
Node dialSetNode = list.item(0);
processDialSetElement((Element) dialSetNode);
list = document.getElementsByTagName("ButtonSet");
if (list.getLength() != 1)
throw new IllegalArgumentException(
"File should have a single ButtonSet block");
Node buttonSetNode = list.item(0);
processButtonSetElement((Element) buttonSetNode);
} catch (ParserConfigurationException e) {
// todo: re-throw own error
throw new IllegalArgumentException("Unable to create factory");
} catch (SAXException e) {
// todo: re-throw own error
throw new IllegalArgumentException("Unable to parse xml file");
} catch (IOException e) {
// todo: re-throw own error
throw new IllegalArgumentException("Problem reading file: '"
+ file.getAbsolutePath() + "'");
}
}
private void processDialSetElement(Element element) throws BuilderException {
NodeList list = element.getElementsByTagName("Dial");
int numChildren = list.getLength();
for (int i = 0; i < numChildren; i++) {
Node child = list.item(i);
processDialElement((Element) child);
}
}
private void processEquivalencesElement(Element element)
throws BuilderException {
NodeList list = element.getElementsByTagName("Equivalence");
int numChildren = list.getLength();
for (int i = 0; i < numChildren; i++) {
Node child = list.item(i);
processEquivalenceElement((Element) child);
}
}
private void processEquivalenceElement(Element element)
throws BuilderException {
NodeList list = element.getElementsByTagName("CounterGroupExpression");
int numChildren = list.getLength();
if (numChildren != 2)
throw new BuilderException(
"Equivalence must contain two expressions.");
Element leftExpressionElement = (Element) list.item(0);
Element rightExpressionElement = (Element) list.item(1);
CounterGroupExpression leftExpression =
new CounterGroupExpression(model);
setCoefficients(leftExpression, leftExpressionElement);
CounterGroupExpression rightExpression =
new CounterGroupExpression(model);
setCoefficients(rightExpression, rightExpressionElement);
Equivalence equivalence =
new Equivalence(model, leftExpression, rightExpression);
model.addEquivalence(equivalence);
}
private void setCoefficients(CounterGroupExpression expression,
Element expressionElement) {
NodeList list =
expressionElement.getElementsByTagName("CounterGroupTerm");
int numChildren = list.getLength();
for (int i = 0; i < numChildren; i++) {
Element child = (Element) list.item(i);
String counterGroupId = child.getAttribute("counterGroupId");
int coefficient =
Integer.parseInt(child.getAttribute("coefficient"));
CounterGroup counterGroup = idToCounterGroupMap.get(counterGroupId);
CounterGroupTerm term = expression.getTerm(counterGroup);
term.setCoefficient(coefficient);
}
}
private void processDialElement(Element element) throws BuilderException {
String counterId = element.getAttribute("counterId");
ModuloCounter counter = idToCounterMap.get(counterId);
if (counter == null)
throw new BuilderException("Unable to resolve counterId: "
+ counterId);
int x;
try {
String xString = element.getAttribute("x");
x = Integer.parseInt(xString);
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
int y;
try {
String yString = element.getAttribute("y");
y = Integer.parseInt(yString);
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
// optional (for backwards compatibility)
Integer size = null;
try {
String sizeString = element.getAttribute("size");
if (! sizeString.equals(""))
size = Integer.parseInt(sizeString);
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
Color color;
try {
// backwards compatible
String colorString = element.getAttribute("color");
if (colorString.equals(""))
color = null;
else {
String[] colorParts = colorString.split(",", 3);
int red = Integer.parseInt(colorParts[0]);
int green = Integer.parseInt(colorParts[1]);
int blue = Integer.parseInt(colorParts[2]);
color = new Color(red, green, blue);
}
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
Dial dial = dialView.getCanvas().getDial(counter);
dial.setLocation(x, y);
if (size != null)
dial.setDialSize(size);
if (color != null)
dial.setFillColor(color);
}
private void processButtonSetElement(Element element)
throws BuilderException {
NodeList list = element.getElementsByTagName("Button");
int numChildren = list.getLength();
for (int i = 0; i < numChildren; i++) {
Node child = list.item(i);
processButtonElement((Element) child);
}
}
@SuppressWarnings("unchecked")
private void processButtonElement(Element element) throws BuilderException {
String counterGroupId = element.getAttribute("counterGroupId");
CounterGroup counterGroup = idToCounterGroupMap.get(counterGroupId);
if (counterGroup == null)
throw new BuilderException("Unable to resolve counterGroupId: "
+ counterGroupId);
int x;
try {
String xString = element.getAttribute("x");
x = Integer.parseInt(xString);
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
int y;
try {
String yString = element.getAttribute("y");
y = Integer.parseInt(yString);
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
// hack - use generification
CounterGroupManager counterGroupManager =
dialView.getCanvas().getCounterGroupManager();
JComponent component = counterGroupManager.getComponent(counterGroup);
component.setLocation(x, y);
}
private void processCounterSetElement(Element element)
throws BuilderException {
NodeList list = element.getElementsByTagName("Counter");
int numChildren = list.getLength();
for (int i = 0; i < numChildren; i++) {
Node child = list.item(i);
processCounterElement((Element) child);
}
}
private void processCounterElement(Element element) throws BuilderException {
String id = element.getAttribute("id");
int modulo;
try {
String moduloString = element.getAttribute("modulo");
modulo = Integer.parseInt(moduloString);
if (modulo <= 0)
throw new BuilderException("Modulo must be strictly positive");
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
int value;
try {
String valueString = element.getAttribute("value");
value = Integer.parseInt(valueString);
} catch (NumberFormatException e) {
throw new BuilderException(e);
}
ModuloCounter counter = new ModuloCounter(modulo);
counter.setValue(value);
model.addCounter(counter);
idToCounterMap.put(id, counter);
}
private void processCounterGroupSetElement(Element element)
throws BuilderException {
NodeList list = element.getElementsByTagName("CounterGroup");
int numChildren = list.getLength();
for (int i = 0; i < numChildren; i++) {
Node child = list.item(i);
processCounterGroupElement((Element) child);
}
}
private void processCounterGroupElement(Element element)
throws BuilderException {
NodeList list = element.getElementsByTagName("Counter");
int numChildren = list.getLength();
CounterGroup counterGroup = new CounterGroup(model);
for (int i = 0; i < numChildren; i++) {
Node child = list.item(i);
String counterId = ((Element) child).getAttribute("counterId");
ModuloCounter counter = idToCounterMap.get(counterId);
if (counter == null)
throw new BuilderException("Unable to resolve counterId: "
+ counterId);
counterGroup.addCounter(counter);
}
if (counterGroup.size() == 0)
return;
model.addCounterGroup(counterGroup);
String counterGroupId = element.getAttribute("id");
idToCounterGroupMap.put(counterGroupId, counterGroup);
}
}
|