/** * Catroid: An on-device visual programming system for Android devices Copyright (C) 2010-2014 The * Catrobat Team (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero General Public License, version 3, * is available at http://developer.catrobat.org/license_additional_term * * 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. */ package org.catrobat.html5player.client; import java.util.ArrayList; import java.util.List; import org.catrobat.html5player.client.bricks.*; import org.catrobat.html5player.client.common.LookData; import org.catrobat.html5player.client.common.SoundInfo; import org.catrobat.html5player.client.formulaeditor.Formula; import org.catrobat.html5player.client.formulaeditor.UserVariable; import org.catrobat.html5player.client.scripts.BroadcastScript; import org.catrobat.html5player.client.scripts.Script; import org.catrobat.html5player.client.scripts.StartScript; import org.catrobat.html5player.client.scripts.WhenScript; import com.google.gwt.user.client.Window; import com.google.gwt.xml.client.Attr; import com.google.gwt.xml.client.DOMException; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.Element; import com.google.gwt.xml.client.Node; import com.google.gwt.xml.client.NodeList; import com.google.gwt.xml.client.Text; import com.google.gwt.xml.client.XMLParser; import com.mouchel.gwt.xpath.client.XPath; public class Parser { private String currentXML; private SpriteManager manager; private boolean parsingComplete = false; private boolean ignoreUnimplementedBricks = false; public Parser() { } public void parseXML(SpriteManager spriteManager, String xmlString) { try { currentXML = xmlString; manager = spriteManager; Document messageDom = XMLParser.parse(currentXML); if (hasDomDocumentPageNotFoundError(messageDom)) { return; } if (!isVersionOK(messageDom)) { return; } parseScreenResolution(messageDom); parseUserVariableList(getChildElementByTagName(messageDom.getDocumentElement(),"variables")); parseProgramVariableList(getChildElementByTagName(messageDom.getDocumentElement(),"variables")); if (parseAndCreateObjects(messageDom)) { parserFinished(); CatrobatDebug.info("Parser finished"); } } catch (DOMException e) { Window.alert("Could not parse XML document. " + e.getMessage()); } } // ########################################################################## // for fixing the problem with xpathEvaluateFirst witch returns null if there are multiple entries private Element xpathEvaluateFirst(Element objectNode, String objectReference, Class<Element> type){ List<Element> refs = XPath.evaluate(objectNode, objectReference, type); if(refs == null || refs.size() == 0){ return null; } return refs.get(0); } private boolean hasDomDocumentPageNotFoundError(Document messageDom) { NodeList errornodes = ((Element) messageDom.getFirstChild()).getElementsByTagName("error"); if (errornodes != null && errornodes.getLength() != 0) { Element errorElement = (Element) errornodes.item(0); NodeList codes = errorElement.getElementsByTagName("code"); if (codes != null && codes.getLength() != 0) { if (codes.item(0).toString().contains("ajax_request_page_not_found")) { Window .alert("Project specification not supported or no project found for the given project number."); return true; } } } return false; } private boolean isVersionOK(Document messageDom) { NodeList header = ((Element) messageDom.getFirstChild()).getElementsByTagName("header"); if (header != null && header.getLength() != 0) { Element version = getChildElementByTagName(header.item(0),"catrobatLanguageVersion"); if (version != null) { double v = Double.parseDouble(version.getFirstChild().toString()); if (v >= 0.6) { return true; } } } Window.alert("Project version not supported!"); return false; } public static Element getChildElementByTagName(Node context, String name) { if (context == null || context.getNodeType() != Node.ELEMENT_NODE) return null; NodeList children = context.getChildNodes(); int childLength = children.getLength(); for (int i = 0; i < childLength; i++) { Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE && (((Element) child).getNodeName().equals(name) || ((Element) child).getTagName() .equals(name))) { return (Element) child; } } return null; } private List<Element> getChildElementsByTagName(Node context, String name) { List<Element> result = new ArrayList<Element>(); if (context != null) { NodeList children = context.getChildNodes(); int childLength = children.getLength(); for (int i = 0; i < childLength; i++) { Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE && ((Element) child).getNodeName().equals(name)) { result.add((Element) child); } } } return result; } private List<Element> getChildElements(Node context) { List<Element> result = new ArrayList<Element>(); if (context != null) { NodeList children = context.getChildNodes(); int childLength = children.getLength(); for (int i = 0; i < childLength; i++) { Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { result.add((Element) child); } } } return result; } private String getText(Node context) { if (context == null) return null; StringBuffer text = new StringBuffer(); if (context.getNodeType() == Node.ELEMENT_NODE) { NodeList children = context.getChildNodes(); int childLength = children.getLength(); boolean wrap = false; for (int i = 0; i < childLength; i++) { Node child = children.item(i); if (child.getNodeType() == Node.TEXT_NODE) { if (wrap) { text.append("\n"); } wrap = true; text.append(((Text) child).getData()); } } } else if (context.getNodeType() == Node.TEXT_NODE) { text.append(((Text) context).getData()); } else if (context.getNodeType() == Node.ATTRIBUTE_NODE) { text.append(((Attr) context).getValue()); } return text.toString(); } // ########################################################################## /** * Checks if a reference has the correct syntax for XPath to evaluate. If a reference refers to * the first element of a set of elements, than there must be square brackets with a 1 in between * * @param reference * @param substring Element to check as a String * @return A reference with correct syntax */ private String checkReference(String reference, String substring) { String checkedReference = ""; if (reference.matches("(.*)" + substring + "(\\[){1}(\\d){1,}(\\]){1}(.*)")) { CatrobatDebug.debug("reference (" + reference + ") contains square brackets"); return reference; } else { CatrobatDebug.debug("reference (" + reference + ") does not contain square brackets"); //int offset = reference.lastIndexOf(substring) + substring.length(); StringBuilder newReference = new StringBuilder(reference); //newReference.insert(offset, "[1]"); checkedReference = newReference.toString(); } return checkedReference; } // ########################################################################## private void parseUserVariableList(Node tree) { if(tree == null) return; // Element userVariables = getChildElementByTagName(tree,"objectVariableList"); if(userVariables == null) return; for(int i = 0; i < getChildElements(userVariables).size();i++) { Element entry = getChildElements(userVariables).get(i); Element object = getChildElements(entry).get(0); //extend for ALL objects of an entry!! //String objectReference = checkReference(object.getAttribute("reference"), null);//evt nicht checken object = xpathEvaluateFirst(object, object.getAttribute("reference"), Element.class); //evt nicht checken Element nameObjEl = getChildElementByTagName(object,"name"); //evt nicht checken String nameSprite = ""; if(nameObjEl != null) { nameSprite = nameObjEl.getFirstChild().toString(); //evt nicht checken } // Element list = getChildElements(entry).get(1); //beutify if(list.hasChildNodes()) { for(int j = 0; j < getChildElements(list).size();j++) { Element var = getChildElements(list).get(j); if (var.hasAttribute("reference")) { String objectReference = checkReference(var.getAttribute("reference"), "userVariable"); //HIER CHECKEN Element userVariable = xpathEvaluateFirst(var, objectReference, Element.class); //HIER CHECKEN if(userVariable == null){ return; } String name = ""; double value = 0.0; Element nameEl = getChildElementByTagName(userVariable,"name"); if(nameEl != null) { name = nameEl.getFirstChild().toString(); } Element valueEl = getChildElementByTagName(userVariable,"value"); if(valueEl != null) { value = Double.parseDouble(valueEl.getFirstChild().toString()); } Stage.getInstance().getUserVariables().addSpriteUserVariable(nameSprite, name, value); } } } } } private void parseProgramVariableList(Node tree) { if(tree == null) return; Element prorgamVariables = getChildElementByTagName(tree,"programVariableList"); if(prorgamVariables == null) return; for(int i = 0; i < getChildElements(prorgamVariables).size();i++) { Element var = getChildElements(prorgamVariables).get(i); if (var.hasAttribute("reference")) { String objectReference = checkReference(var.getAttribute("reference"), "userVariable"); Element userVariable = xpathEvaluateFirst(var, objectReference, Element.class); if(userVariable == null){ return; } String name = ""; double value = 0.0; Element nameEl = getChildElementByTagName(userVariable,"name"); if(nameEl != null) { name = nameEl.getFirstChild().toString(); } Element valueEl = getChildElementByTagName(userVariable,"value"); if(valueEl != null) { value = Double.parseDouble(valueEl.getFirstChild().toString()); } Stage.getInstance().getUserVariables().addProjectUserVariable(name, value); } } } private void parseScreenResolution(Document messageDom) { Node header = getChildElementByTagName(messageDom.getDocumentElement(), "header"); Node nodeScreenHeight = getChildElementByTagName(header, Const.SCREEN_HEIGHT); Node nodeScreenWidth = getChildElementByTagName(header, Const.SCREEN_WIDTH); int dimX = 0; int dimY = 0; if (nodeScreenWidth != null) { dimX = Integer.valueOf(nodeScreenWidth.getFirstChild().getNodeValue()); } else { CatrobatDebug.warn("Method parseScreenResolution: nodeScreenWidth is null"); } if (nodeScreenHeight != null) { dimY = Integer.valueOf(nodeScreenHeight.getFirstChild().getNodeValue()); } else { CatrobatDebug.warn("Method parseScreenResolution: nodeScreenHeight is null"); } setRootCanvasSize(dimX, dimY); } private boolean parseAndCreateObjects(Document messageDom) { Element objectListNode = getChildElementByTagName(messageDom.getDocumentElement(), "objectList"); List<Element> objectNodes = getChildElementsByTagName(objectListNode, "object"); int objectCounter = 0; for (Element objectNode : objectNodes) { String name; Node lookList; Node scriptList; Node soundList; if (objectNode.hasAttribute("reference")) { String objectReference = checkReference(objectNode.getAttribute("reference"), "object"); Element referencedObjectNode = xpathEvaluateFirst(objectNode, objectReference, Element.class); objectNode = referencedObjectNode; } name = getText(getChildElementByTagName(objectNode, "name")); lookList = getChildElementByTagName(objectNode, "lookList"); scriptList = getChildElementByTagName(objectNode, "scriptList"); soundList = getChildElementByTagName(objectNode, "soundList"); Sprite object = createObject(name, lookList, scriptList, soundList); if (object == null) { Window.alert("Could not parse XML document. There are unsupported elements!"); //Window.alert(name+""); //Window.alert(lookList+""); //Window.alert(scriptList+""); //Window.alert(soundList+""); return false; } if(!object.isBackground()) { object.getLook().setZPosition(objectCounter); } else { object.getLook().setZPosition(Integer.MIN_VALUE); objectCounter++; } manager.addSprite(object); objectCounter--; } return true; } public Sprite createObject(String name, Node lookList, Node scriptList, Node soundList) { Sprite object = manager.getSprite(name, true); if(object == null){ System.out.println("object creation of "+name+" failed"); } if (name.equals(Const.BACK_GROUND_GER) || name.equals(Const.BACK_GROUND_ENG)) { object.setBackground(true); } List<Element> looks = getChildElementsByTagName(lookList, "look"); if (looks == null || looks.isEmpty()) { System.out.println("look not found for object "+name +"!"); looks = getChildElementsByTagName(lookList, "look"); } for (Element look : looks) { LookData lookData = new LookData(); String filename = getText(getChildElementByTagName(look, "fileName")); CatrobatDebug.debug("FileName: " + filename); lookData.setFilename(filename); String lookName = getText(getChildElementByTagName(look, "name")); lookData.setName(lookName); CatrobatDebug.debug("Name: " + lookName); lookData.setHeight(0); lookData.setWidth(0); object.addLookData(lookData); CatrobatDebug.debug("LookData: " + lookData.getName()); CatrobatDebug.debug("File: " + lookData.getFilename() + " Height: " + lookData.getHeight() + " Width: " + lookData.getWidth()); // add image name and url to ImageHandler // String url = Const.PROJECT_PATH + Stage.getInstance().getProjectNumber() + "/images/"+ // filename; String url = "http://" + Window.Location.getHost() + "/Html5Player/fileupload?name=" + filename; ImageHandler.get().addImage(filename, url); } List<Element> scripts = getChildElements(scriptList); int startScriptCounter = 0; //to check if Sprite only has WhenScript for (Element scriptElement : scripts) { Script script = checkScript(scriptElement, object); if(script == null) { System.out.println("error parsing script: "+scriptElement.toString()); return null; } Element brickListElement = getChildElementByTagName(scriptElement, "brickList"); if (brickListElement != null) { List<Element> brickElements = getChildElements(brickListElement); List<IfLogicBrick> openIfLogicBricks = new ArrayList<IfLogicBrick>(); for (Element brickElement : brickElements) { Brick brick = null; try { brick = checkBrick(brickElement, object, script); } catch (Exception e) { System.out.println(brickElement); System.out.println("Brick Creation Exception: "+e.toString()); return null; } if (brick != null && script != null) { if(openIfLogicBricks.size() > 0){ if(brick instanceof IfLogicElseBrick){ openIfLogicBricks.get(openIfLogicBricks.size()-1).setIfPartInitialized(true); } else if(brick instanceof IfLogicEndBrick){ openIfLogicBricks.remove(openIfLogicBricks.size()-1); }else{ openIfLogicBricks.get(openIfLogicBricks.size()-1).addAction(brick, object.getName()); if(brick instanceof IfLogicBrick){ openIfLogicBricks.add((IfLogicBrick) brick); } } } else{ script.addBrick(brick); if(brick instanceof IfLogicBrick){ openIfLogicBricks.add((IfLogicBrick) brick); } } } else { CatrobatDebug.brick("Brick Parsing Problem: "+brickElement.toString() +"-"+ script.toString() +"-"+ object.toString()); return null; } } if (script instanceof StartScript) { if(!object.getLookData().isEmpty()) { script.addBrick(new SetLookBrick(object.getName(), object.getLookData().get(0).getName()),0); //show sprite when not explicitly hidden } startScriptCounter++; } } object.addScript(script); } //////// //if Sprite has no StartScript and has a Look, add StartScript to show sprite by default when not explicitly hidden if(startScriptCounter == 0 && !(looks.isEmpty())) { StartScript script_start = new StartScript(object, object.getName()); if(object.getLookData().get(0).getName() != null) { script_start.addBrick(new SetLookBrick(object.getName(), object.getLookData().get(0).getName())); } object.addScript(script_start); } return object; } private Brick checkBrick(Element brickNode, Sprite object, Script script) throws Exception { Element objectReference = getChildElementByTagName(brickNode, "object"); String reference = objectReference != null ? objectReference.getAttribute("reference") : null; Element referencedObject = (objectReference != null && reference != null) ? xpathEvaluateFirst( objectReference, reference, Element.class) : null; String objName = object.getName(); if (referencedObject != null && referencedObject.getNodeName().equals("object")) { String referenceName = getText(getChildElementByTagName(referencedObject, "name")); if (referenceName == null || referenceName.trim().length() == 0) { Stage.getInstance().log( "Invalid object reference: " + referencedObject.getNodeName() + " for " + reference); } else if (!objName.equals(referenceName)) { objName = referenceName; } } else { CatrobatDebug.debug("INVALID - checkBrick - objectElement: " + referencedObject); } if (brickNode.getNodeName().equals("setLookBrick")) { Element lookReferenceElement = getChildElementByTagName(brickNode, "look"); String lookReference = lookReferenceElement != null ? checkReference( lookReferenceElement.getAttribute("reference"), "look") : null; Element lookElement = lookReferenceElement != null && lookReference != null ? xpathEvaluateFirst( lookReferenceElement, lookReference, Element.class) : null; String lookName = null; if (lookElement != null) { lookName = getText(getChildElementByTagName(lookElement, "name")); } else { System.out.println("Look is null"); } return new SetLookBrick(objName, lookName); } else if (brickNode.getNodeName().equals("waitBrick")) { Formula waitTime = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "timeToWaitInSeconds")); return new WaitBrick(objName, waitTime, script); } else if (brickNode.getNodeName().equals("playSoundBrick")) { CatrobatDebug.debug("PlaySoundBrick:"); Element soundInfoElement = getChildElementByTagName(brickNode, "sound"); SoundInfo soundInfo = new SoundInfo(); String soundId = null; String fileName = null; CatrobatDebug.debug("soundInfo: " + soundInfoElement); if (soundInfoElement != null) { if (soundInfoElement.hasAttribute("reference")) { String soundInfoReference = checkReference(soundInfoElement.getAttribute("reference"), "PlaySoundBrick"); Element referencedSoundInfoElement = xpathEvaluateFirst(soundInfoElement, soundInfoReference, Element.class); CatrobatDebug.debug("PlaySoundBrick has a reference-attribute: " + soundInfoReference); CatrobatDebug.debug("referenced soundInfo: " + referencedSoundInfoElement); if (referencedSoundInfoElement != null) { soundInfoElement = referencedSoundInfoElement; CatrobatDebug.debug("soundInfoElement got set to the referenced soundInfo"); } else { CatrobatDebug.warn("referenced soundInfo is null"); return null; } } fileName = getText(getChildElementByTagName(soundInfoElement, "fileName")); CatrobatDebug.debug("Filename: " + fileName); soundInfo.setFileName(fileName); soundInfo.setTitle(getText(getChildElementByTagName(soundInfoElement, "name"))); CatrobatDebug.debug("Title: "+ getText(getChildElementByTagName(soundInfoElement, "name"))); soundId = fileName.split("_")[0]; CatrobatDebug.debug("Sound ID: " + soundId); soundInfo.setId(soundId); } if (soundId == null || soundId.trim().length() == 0) { System.out.println("sound is null"); } else { object.addSound(soundInfo); } return new PlaySoundBrick(objName, soundId); } else if (brickNode.getNodeName().equals("speakBrick")) { String text = getChildElementByTagName(brickNode, "text").getFirstChild().getNodeValue(); return new SpeakBrick(objName, text); } else if (brickNode.getNodeName().equals("changeVolumeByNBrick")) { Formula volume = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "volume")); return new ChangeVolumeByBrick(objName, volume); } else if (brickNode.getNodeName().equals("setVolumeToBrick")) { Formula volume = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "volume")); return new SetVolumeToBrick(objName, volume); } else if (brickNode.getNodeName().equals("placeAtBrick")) { Formula xPosition = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "xPosition")); Formula yPosition = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "yPosition")); return new PlaceAtBrick(objName, xPosition, yPosition); } else if (brickNode.getNodeName().equals("changeSizeByNBrick")) { Formula size = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "size")); return new ChangeSizeByNBrick(objName, size); } else if (brickNode.getNodeName().equals("setYBrick")) { Formula yPosition = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "yPosition")); return new SetYBrick(objName, yPosition); } else if (brickNode.getNodeName().equals("setXBrick")) { Formula xPosition = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "xPosition")); return new SetXBrick(objName, xPosition); } else if (brickNode.getNodeName().equals("changeXByNBrick")) { Formula deltaX = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "xMovement")); return new ChangeXByBrick(objName, deltaX); } else if (brickNode.getNodeName().equals("changeYByNBrick")) { Formula deltaY = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "yMovement")); return new ChangeYByBrick(objName, deltaY); } else if (brickNode.getNodeName().equals("hideBrick")) { return new HideBrick(objName); } else if (brickNode.getNodeName().equals("showBrick")) { return new ShowBrick(objName); } else if (brickNode.getNodeName().equals("stopAllSoundsBrick")) { return new StopAllSoundsBrick(objName); } else if (brickNode.getNodeName().equals("turnLeftBrick")) { Formula degrees = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "degrees")); return new TurnLeftBrick(objName, degrees); } else if (brickNode.getNodeName().equals("turnRightBrick")) { Formula degrees = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "degrees")); return new TurnRightBrick(objName, degrees); } else if (brickNode.getNodeName().equals("pointInDirectionBrick")) { Formula degrees = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "degrees")); return new PointInDirectionBrick(objName, degrees); } else if (brickNode.getNodeName().equals("goNStepsBackBrick")) { Formula steps = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "steps")); return new GoNStepsBackBrick(objName, steps); } else if (brickNode.getNodeName().equals("comeToFrontBrick")) { return new ComeToFrontBrick(objName); } else if (brickNode.getNodeName().equals("glideToBrick")) { Formula duration = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "durationInSeconds")); Formula xDestination = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "xDestination")); Formula yDestination = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "yDestination")); return new GlideToBrick(objName, duration, xDestination, yDestination, script); } else if (brickNode.getNodeName().equals("setSizeToBrick")) { Formula size = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "size")); return new SetSizeToBrick(objName, size); } else if (brickNode.getNodeName().equals("broadcastBrick")) { String message = getText(getChildElementByTagName(brickNode, "broadcastMessage")); return new BroadcastBrick(objName, message); } else if (brickNode.getNodeName().equals("broadcastWaitBrick")) { String message = getText(getChildElementByTagName(brickNode, "broadcastMessage")); return new BroadcastWaitBrick(objName, message, script); } else if (brickNode.getNodeName().equals("moveNStepsBrick")) { Formula steps = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "steps")); return new MoveNStepsBrick(objName, steps); } else if (brickNode.getNodeName().equals("nextLookBrick")) { return new NextLookBrick(objName); } else if (brickNode.getNodeName().equals("repeatBrick")) { Formula timesToRepeat = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "timesToRepeat")); return new RepeatBrick(objName, timesToRepeat); } else if (brickNode.getNodeName().equals("loopEndBrick")){ RepeatBrick repeatBrick = script.getLastRepeatBrickWithoutLoopEndBrick(); if (repeatBrick == null) { System.out.println("repeatBrick is null"); return null; } LoopEndBrick loopEndBrick = new LoopEndBrick(objName, repeatBrick); repeatBrick.setLoopEndBrick(loopEndBrick); return loopEndBrick; } else if (brickNode.getNodeName().equals("foreverBrick")) { return new ForeverBrick(objName); } else if (brickNode.getNodeName().equals("loopEndlessBrick")) { ForeverBrick foreverBrick = script.getLastForeverBrickWithoutLoopEndlessBrick(); if (foreverBrick == null) { System.out.println("foreverBrick is null"); return null; } LoopEndlessBrick loopEndlessBrick = new LoopEndlessBrick(objName, foreverBrick); foreverBrick.setLoopEndlessBrick(loopEndlessBrick); return loopEndlessBrick; } else if (brickNode.getNodeName().equals("noteBrick")) { Element noteNode = getChildElementByTagName(brickNode, "note"); String note = getText(noteNode); if (note == null){ return new NoteBrick(objName); } else{ return new NoteBrick(objName, note); } } else if (brickNode.getNodeName().equals("setGhostEffectBrick")) { Formula ghostEffectValue = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "transparency")); return new SetGhostEffectBrick(objName, ghostEffectValue); } else if (brickNode.getNodeName().equals("changeGhostEffectByNBrick")) { Formula changeGhostEffect = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "changeGhostEffect")); return new ChangeGhostEffectByBrick(objName, changeGhostEffect); } else if (brickNode.getNodeName().equals("ifOnEdgeBounceBrick")) { return new IfOnEdgeBounceBrick(objName); } else if (brickNode.getNodeName().equals("pointToBrick")) { Element pointedSpriteNode = getChildElementByTagName(brickNode, "pointedObject"); Element pointedSpriteNameNode = null; String pointedSpriteName = null; if (pointedSpriteNode.hasAttribute("reference")) { String pointedSpriteReference = pointedSpriteNode.getAttribute("reference"); Element referencedSpriteNode = xpathEvaluateFirst(pointedSpriteNode, pointedSpriteReference, Element.class); pointedSpriteNameNode = getChildElementByTagName(referencedSpriteNode, "name"); } else { pointedSpriteNameNode = getChildElementByTagName(pointedSpriteNode, "name"); } if (pointedSpriteNameNode != null) { pointedSpriteName = getText(pointedSpriteNameNode); } CatrobatDebug.debug("Sprite " + objName + " has PointToBrick which points to Sprite " + pointedSpriteName); return new PointToBrick(objName, pointedSpriteName); } else if (brickNode.getNodeName().equals("clearGraphicEffectBrick")) { return new ClearGraphicEffectBrick(objName); } else if (brickNode.getNodeName().equals("setBrightnessBrick")) { Formula brightness = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "brightness")); return new SetBrightnessBrick(objName, brightness); } else if (brickNode.getNodeName().equals("changeBrightnessByNBrick")) { Formula changeBrightness = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "changeBrightness")); return new ChangeBrightnessBrick(objName, changeBrightness); } else if(brickNode.getNodeName().equals("setVariableBrick")){ UserVariable userVar = parseUserVariable(brickNode); Formula formula = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "variableFormula")); return new SetVariableBrick(objName,formula, userVar); } else if(brickNode.getNodeName().equals("changeVariableBrick")){ UserVariable userVar = parseUserVariable(brickNode); Formula formula = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "variableFormula")); return new ChangeVariableBrick(objName,formula, userVar); } else if(brickNode.getNodeName().equals("ifLogicBeginBrick")){ Formula formula; if(brickNode.hasAttribute("reference")){ String r = checkReference(brickNode.getAttribute("reference"), "ifLogicBeginBrick"); Element n = xpathEvaluateFirst(brickNode, r, Element.class); //System.out.println(n); //return new SequenceBrick(objName); formula = FormulaParser.parseFormula(getChildElementByTagName(n, "ifCondition")); } else{ formula = FormulaParser.parseFormula(getChildElementByTagName(brickNode, "ifCondition")); } return new IfLogicBrick(objName, formula); } else if(brickNode.getNodeName().equals("ifLogicElseBrick")){ return new IfLogicElseBrick(objName); } else if(brickNode.getNodeName().equals("ifLogicEndBrick")){ return new IfLogicEndBrick(objName); } else { if(ignoreUnimplementedBricks){ return new SequenceBrick(objName); } CatrobatDebug.warn("Brick: " + brickNode.getNodeName() + " not implemented"); Stage.getInstance().log("Brick not implemented:" + brickNode.getNodeName()); } return null; } private Script checkScript(Element scriptElement, Sprite object) { Element objectElement = getChildElementByTagName(scriptElement, "object"); String objectReference = objectElement != null ? objectElement.getAttribute("reference") : null; Element referencedObject = (objectElement != null && objectReference != null) ? xpathEvaluateFirst( objectElement, objectReference, Element.class) : null; Sprite scriptObject = object; if (referencedObject != null && referencedObject.getNodeName().equals("object")) { String name = getText(getChildElementByTagName(referencedObject, "name")); if (name == null || name.trim().length() == 0) { Stage.getInstance().log( "Invalid sprite reference: " + referencedObject.getNodeName() + " for " + objectReference); } else if (!object.getName().equals(name)) { scriptObject = manager.getSprite(name, true); } } else { //TODO: check what to do when object reference is null! } if (scriptElement.getNodeName().equals("startScript")) { return new StartScript(scriptObject, "startScript"); } else if (scriptElement.getNodeName().equals("whenScript")) { return new WhenScript(scriptObject, "whenScript"); } else if (scriptElement.getNodeName().equals("broadcastScript")) { String message = getText(getChildElementByTagName(scriptElement, "receivedMessage")); return new BroadcastScript(scriptObject, "broadcastScript", message); } else { Stage.getInstance().log("Script not implemented:" + scriptElement.getNodeName()); return null; } } private void setRootCanvasSize(int width, int height) { Scene.get().setSceneMeasures(width, height); } public UserVariable parseUserVariable(Node tree){ Element userVariable = getChildElementByTagName(tree,"userVariable"); if(userVariable == null){ return null; } Element object = getChildElementByTagName(tree,"object"); String objectRef = object.getAttribute("reference"); object = xpathEvaluateFirst(object, objectRef, Element.class); String object_name = getChildElementByTagName(object,"name").getFirstChild().toString(); //first occurance of variable, name used Element nameEl = getChildElementByTagName(userVariable,"name"); if(nameEl != null){ String name = nameEl.getFirstChild().toString(); return Stage.getInstance().getUserVariables().getUserVariable(name, object_name); } //variable already exists, reference needed if (userVariable.hasAttribute("reference")) { String objectReference = checkReference(userVariable.getAttribute("reference"), "userVariable"); userVariable = xpathEvaluateFirst(userVariable, objectReference, Element.class); if(userVariable == null){ return null; } nameEl = getChildElementByTagName(userVariable,"name"); if(nameEl != null) { String name = nameEl.getFirstChild().toString(); return Stage.getInstance().getUserVariables().getUserVariable(name, object_name); } } return null; } public boolean isParsingComplete() { return parsingComplete; } private void parserFinished() { parsingComplete = true; } }