Package at.bestsolution.efxclipse.tooling.fxgraph.converter

Source Code of at.bestsolution.efxclipse.tooling.fxgraph.converter.FXMLLoader$FXMLHandler

/*******************************************************************************
* Copyright (c) 2012 BestSolution.at and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Martin Bluehweis<martin.bluehweis@bestsolution.at> - initial API and implementation
*******************************************************************************/
package at.bestsolution.efxclipse.tooling.fxgraph.converter;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.xtext.common.types.JvmParameterizedTypeReference;
import org.eclipse.xtext.common.types.JvmPrimitiveType;
import org.eclipse.xtext.common.types.TypesFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.BindValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ComponentDefinition;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ConstValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ControllerHandledValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.Define;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.Element;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.FXGraphFactory;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.Import;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.IncludeValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ListValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.LocationValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.MapValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.Model;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.PackageDeclaration;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.Property;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ReferenceValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ResourceValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.Script;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ScriptValueReference;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.SimpleValueProperty;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.StringValue;
import at.bestsolution.efxclipse.tooling.fxgraph.fXGraph.ValueProperty;

public class FXMLLoader {

  public Model loadModel(IFile file) {
    try {
      SAXParserFactory factory = SAXParserFactory.newInstance();
      factory.setNamespaceAware(true);
      SAXParser parser = factory.newSAXParser();
      FXMLHandler handler = new FXMLHandler(file);
      parser.parse(file.getContents(), handler);
      return handler.model;
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }

  static class FXMLHandler extends DefaultHandler {
    private final IFile fxmlFile;
    private Model model;

    private Map<String, Element> elements = new HashMap<String, Element>();

    private Stack<String> structureStack = new Stack<String>();

    private Stack<Element> elementStack = new Stack<Element>();
    private StringBuilder richtTextContent = new StringBuilder();
    private String scriptLanguage = null;

    private String thePropertyIDontWantToForget = null;
    private boolean constant = false;

    public FXMLHandler(IFile fxmlFile) {
      this.fxmlFile = fxmlFile;
    }

    @Override
    public void startDocument() {
      model = FXGraphFactory.eINSTANCE.createModel();

      String packName = null;
      IJavaElement j = JavaCore.create(fxmlFile.getParent());
      if (j instanceof IPackageFragment) {
        IPackageFragment p = (IPackageFragment) j;
        packName = p.getElementName();
      }

      if (packName != null) {
        PackageDeclaration pack = FXGraphFactory.eINSTANCE
            .createPackageDeclaration();
        pack.setName(packName);
        model.setPackage(pack);
      }

      ComponentDefinition compDef = FXGraphFactory.eINSTANCE
          .createComponentDefinition();

      String name = fxmlFile.getName();
      if (name.toLowerCase().endsWith(".fxml")) {
        name = name.substring(0, name.length() - 5);
      }
      compDef.setName(name);

      model.setComponentDef(compDef);
    }

    @Override
    public void processingInstruction(String target, String data)
        throws SAXException {
      if ("import".equals(target)) {
        Import i = FXGraphFactory.eINSTANCE.createImport();
        i.setImportedNamespace(data);
        model.getImports().add(i);
      } else if ("scenebuilder-stylesheet".equals(target)) {
        model.getComponentDef().getPreviewCssFiles().add(data);
      } else if ("scenebuilder-preview-i18n-resource".equals(target)) {
        model.getComponentDef().setPreviewResourceBundle(data);
      } else if ("language".equals(target)) {
        scriptLanguage = data;
      }
    }

    @Override
    public void startElement(String uri, String localName, String qName,
        Attributes attributes) throws SAXException {
      structureStack.push(qName);
      if ("fx:define".equals(qName)) {
        // nothing here
      } else if ("fx:include".equals(qName)) {
        IncludeValueProperty p = FXGraphFactory.eINSTANCE
            .createIncludeValueProperty();
        for (int i = 0; i < attributes.getLength(); i++) {
          String propertyQName = attributes.getQName(i);
          String value = attributes.getValue(i);
          if ("fx:id".equals(propertyQName)) {
            p.setName(value);
          } else if ("source".equals(propertyQName)) {
            ComponentDefinition cd = FXGraphFactory.eINSTANCE
                .createComponentDefinition();
            cd.setName(value);
            p.setSource(cd);
          }
        }
      } else if ("fx:script".equals(qName)) {
        for (int i = 0; i < attributes.getLength(); i++) {
          String propertyQName = attributes.getQName(i);
          String value = attributes.getValue(i);
          if ("source".equals(propertyQName)) {
            Script s = createScript(value, null);
            model.getComponentDef().getScripts().add(s);
          }
        }
      } else if ("fx:reference".equals(qName)) {
        for (int i = 0; i < attributes.getLength(); i++) {
          String propertyQName = attributes.getQName(i);
          String value = attributes.getValue(i);
          if ("source".equals(propertyQName)) {
            Element e = createElementWithJVMType("idref " + value); // TODO
                                        // this
                                        // is
                                        // really
                                        // dirty
            elementStack.peek().getDefaultChildren().add(e);
          }
        }
      } else if (!"children".equals(localName)) {
        if (Character.isLowerCase(localName.charAt(0))) {
          if (isSpecial(localName)) {
            boolean alreadyCreated = false;
            for (Property p : elementStack.peek().getProperties()) {
              if (localName.equals(p.getName())) {
                alreadyCreated = true;
                break;
              }
            }
            if (!alreadyCreated) {
              Property p = createProperty(localName,
                  FXGraphFactory.eINSTANCE
                      .createMapValueProperty());
              elementStack.peek().getProperties().add(p);
            }
          } else {
            if (!isContainer(localName)) {
              thePropertyIDontWantToForget = localName;
            }
          }
        } else {
          if (!localName.contains(".")) {
            if (checkConstant(localName, attributes)) {
              ConstValueProperty c = createConstValueProperty(
                  localName, attributes);
              boolean found = false;
              for (Property p : elementStack.peek()
                  .getProperties()) {
                if (p.getName().equals(getStructuralParent())) {
                  found = true;
                  p.setValue(c);
                }
              }
              if (!found) {
                Property p = createProperty(
                    getStructuralParent(), c);
                elementStack.peek().getProperties().add(p);
                if (getStructuralParent().equals(
                    thePropertyIDontWantToForget)) {
                  thePropertyIDontWantToForget = null;
                }
              }
            } else {
              Element e = createElement(localName, attributes);
              // root element
              if (model.getComponentDef().getRootNode() == null) {
                model.getComponentDef().setRootNode(e);
              } else {
                // Factory values
                if (elementStack.peek().getFactory() != null) {
                  // is it a constant or an element
                  if (attributes.getLength() == 1
                      && "fx:value".equals(attributes
                          .getQName(0))) {
                    SimpleValueProperty sp = FXGraphFactory.eINSTANCE
                        .createSimpleValueProperty();
                    sp.setStringValue(attributes
                        .getValue(0));
                    elementStack.peek().getValues().add(sp);
                  } else {
                    elementStack.peek().getValues().add(e);
                  }
                }
                // child elements
                else if ("children"
                    .equals(getStructuralParent())) {
                  elementStack.peek().getDefaultChildren()
                      .add(e);
                } else if (isContainer(getStructuralParent())) {
                  Element parent = elementStack.peek();
                  Property p = null;
                  for (Property existingP : parent
                      .getProperties()) {
                    if (getStructuralParent().equals(
                        existingP.getName())) {
                      p = existingP;
                      break;
                    }
                  }
                  if (p == null) {
                    p = createProperty(
                        getStructuralParent(),
                        FXGraphFactory.eINSTANCE
                            .createListValueProperty());
                  }
                  if (p.getValue() instanceof ListValueProperty) {
                    ListValueProperty list = (ListValueProperty) p
                        .getValue();
                    list.getValue().add(e);
                  } else if ((p.getValue() instanceof ListValueProperty)) {
                    System.err.println("TODO");
                  }
                  parent.getProperties().add(p);
                } else if ("fx:define"
                    .equals(getStructuralParent())) {
                  Define d = FXGraphFactory.eINSTANCE
                      .createDefine();
                  d.setElement(e);
                  model.getComponentDef().getDefines().add(d);
                } else {
                  if (!isSpecial(getStructuralParent())) {
                    Property p = createProperty(
                        getStructuralParent(), e);
                    elementStack.peek().getProperties()
                        .add(p);
                    if (getStructuralParent().equals(
                        thePropertyIDontWantToForget)) {
                      thePropertyIDontWantToForget = null;
                    }
                  }
                }
              }
              elementStack.push(e);
            }
          }
        }
      }
    }

    /**
     * @param localName
     * @param attributes
     * @return
     */
    private ConstValueProperty createConstValueProperty(String localName,
        Attributes attributes) {
      ConstValueProperty c = FXGraphFactory.eINSTANCE
          .createConstValueProperty();
      c.setField(attributes.getValue("fx:constant"));
      JvmParameterizedTypeReference constType = createJvmParameterizedTypeReference(localName);
      c.setType(constType);
      return c;
    }

    /**
     * @return
     */
    private boolean isContainer(String name) {
      return "items".equals(name) || "menus".equals(name)
          || "tabs".equals(name) || "transforms".equals(name)
          || "points".equals(name);
    }

    private String getStructuralParent() {
      if (structureStack.size() < 2) {
        return null;
      } else {
        String tmp = structureStack.pop();
        try {
          return structureStack.peek();
        } finally {
          structureStack.push(tmp);
        }
      }
    }

    private boolean checkConstant(String localName, Attributes attributes) {
      for (int i = 0; i < attributes.getLength(); i++) {
        String qName = attributes.getQName(i);
        if ("fx:constant".equals(qName)) {
          constant = true;
          return true;
        }
      }
      return false;
    }

    /**
     * @param localName
     * @param attributes
     * @return
     */
    private Element createElement(String localName, Attributes attributes) {
      Element element = createElementWithJVMType(localName);
      // attributes
      for (int i = 0; i < attributes.getLength(); i++) {
        String qName = attributes.getQName(i);
        String name = attributes.getLocalName(i);
        String value = attributes.getValue(i);
        if ("fx:value".equals(qName)) {
          if (isSpecial(getStructuralParent())) {
            boolean attached = false;
            for (Property p : elementStack.peek().getProperties()) {
              if (getStructuralParent().equals(p.getName())) {
                MapValueProperty prop = (MapValueProperty) p
                    .getValue();
                SimpleValueProperty e = FXGraphFactory.eINSTANCE
                    .createSimpleValueProperty();
                e.setStringValue(value);
                Property mapval = createProperty(localName, e);
                prop.getProperties().add(mapval);
                attached = true;
                break;
              }
            }
            if (!attached) {
              System.err.println("TODO could not attach value");
            }
          } else {
            if (elementStack.peek().getFactory() == null) {
              System.err
                  .println("TODO value found, structural parent is "
                      + getStructuralParent());
            }
          }
        } else if ("fx:factory".equals(qName)) {
          element.setFactory(value);
        } else if ("fx:controller".equals(qName)) {
          JvmParameterizedTypeReference c = createJvmParameterizedTypeReference(value);
          model.getComponentDef().setController(c);
        } else if ("fx:id".equals(qName)) {
          element.setName(value);
          elements.put(value, element);
        } else {
          Property p = createProperty(name);
          p.setValue(createValueProperty(p, qName, value));
          element.getProperties().add(p);
        }
      }
      return element;
    }

    /**
     * @return
     */
    private boolean isSpecial(String s) {
      return "styleClass".equals(s) || "points".equals(s);
    }

    @Override
    public void characters(char[] ch, int start, int length)
        throws SAXException {
      // if (isProperty) {
      richtTextContent = new StringBuilder().append(new String(ch, start,
          length));
      richtTextContent.trimToSize();
      // }
    }

    @Override
    public void endElement(String uri, String localName, String qName)
        throws SAXException {
      boolean doPop = false;
      try {
        if ("fx:script".equals(qName)) {
          String code = richtTextContent.toString()
              .replaceAll("\n", "").replaceAll("\t", "").trim();
          if (code.length() > 0) {
            Script s = createScript(null, code);
            model.getComponentDef().getScripts().add(s);
          }
        } else if (!"children".equals(localName)) {
          if (Character.isUpperCase(localName.charAt(0))) {
            if (localName.contains(".")) {
              Property p = FXGraphFactory.eINSTANCE
                  .createProperty();
              p.setValue(createStaticCallProperty(p, localName,
                  richtTextContent.toString()));
              elementStack.peek().getProperties().add(p);
            } else if (constant) {
              // nothing here
            } else {
              doPop = true;
            }
          } else {
            if (richtTextContent != null
                && richtTextContent.toString().trim().length() > 0) {
              SimpleValueProperty sp = FXGraphFactory.eINSTANCE
                  .createSimpleValueProperty();
              sp.setStringValue(richtTextContent.toString());
              elementStack.peek().getProperties()
                  .add(createProperty(localName, sp));
              if (localName.equals(thePropertyIDontWantToForget)) {
                thePropertyIDontWantToForget = null;
              }
            }
          }
        }
      } finally {
        if (doPop) {
          elementStack.pop();
        }
        structureStack.pop();
        if (thePropertyIDontWantToForget != null) {
          System.err.println("forgotten property: "
              + thePropertyIDontWantToForget);
          thePropertyIDontWantToForget = null;
        }
        constant = false;
      }
    }

    @Override
    public void endDocument() throws SAXException {
      elements.clear();
      // just for testing
      if (elementStack.size() > 0) {
        throw new SAXException("elementStack.size() =  "
            + elementStack.size());
      }
    }

    /**
     * @param value
     * @return
     */
    private Script createScript(String source, String sourceCode) {
      if (scriptLanguage == null) {
        throw new IllegalArgumentException(
            "scriptLanguage was not defined");
      }
      Script s = FXGraphFactory.eINSTANCE.createScript();
      s.setLanguage(scriptLanguage);
      s.setSource(source);
      s.setSourcecode(sourceCode);
      return s;
    }

    private ValueProperty createValueProperty(Property p, String qName,
        String value) {
      // actions
      if (qName.startsWith("on")) {
        ControllerHandledValueProperty cp = FXGraphFactory.eINSTANCE
            .createControllerHandledValueProperty();
        String methodName = null;
        if (value != null && value.startsWith("#")) {
          methodName = value.replaceFirst("#", "");
        }
        cp.setMethodname(methodName);
        return cp;
      }
      // static call
      else if (value != null && value.startsWith("${")
          && value.endsWith("}")) {
        BindValueProperty s = FXGraphFactory.eINSTANCE
            .createBindValueProperty();
        // format is ${field.text}
        String[] split = value.replaceFirst("[$]", "")
            .replaceFirst("[{]", "").split("[.]");
        if (split.length != 2) {
          throw new IllegalArgumentException(
              "could not resolve binding \"" + value + "\"");
        }
        s.setElementReference(elements.get(split[0]));
        s.setAttribute(split[1].replaceFirst("[}]", ""));
        return s;
      } else if (value != null && value.startsWith("$")) {
        String valueName = value.replaceFirst("[$]", "");
        if (elements.containsKey(valueName)) {
          return createReferenceValueProperty(valueName);
        } else {
          ScriptValueReference s = FXGraphFactory.eINSTANCE
              .createScriptValueReference();
          s.setReference(valueName);
          return s;
        }
      } else if (value != null && value.startsWith("@")) {
        LocationValueProperty l = FXGraphFactory.eINSTANCE
            .createLocationValueProperty();
        l.setValue(value.replaceFirst("@", ""));
        return l;
      } else if (value != null && value.startsWith("%")) {
        ResourceValueProperty l = FXGraphFactory.eINSTANCE
            .createResourceValueProperty();
        StringValue sv = FXGraphFactory.eINSTANCE.createStringValue();
        sv.setValue(value.replaceFirst("%", ""));
        l.setValue(sv);
        return l;
      } else {
        // static call
        SimpleValueProperty vp = createStaticCallProperty(p, qName,
            value);
        return vp;
      }
    }

    /**
     * @param refName
     * @return
     */
    private ReferenceValueProperty createReferenceValueProperty(
        String refName) {
      ReferenceValueProperty r = FXGraphFactory.eINSTANCE
          .createReferenceValueProperty();
      Element refElement = createElementWithJVMType(refName);
      r.setReference(refElement);
      return r;
    }

    /**
     * @param simpleName
     * @return
     */
    private Element createElementWithJVMType(String simpleName) {
      Element refElement = FXGraphFactory.eINSTANCE.createElement();
      JvmParameterizedTypeReference type = createJvmParameterizedTypeReference(simpleName);
      refElement.setType(type);
      return refElement;
    }

    /**
     * @param simpleName
     * @return
     */
    private JvmParameterizedTypeReference createJvmParameterizedTypeReference(
        String simpleName) {
      JvmParameterizedTypeReference type = TypesFactory.eINSTANCE
          .createJvmParameterizedTypeReference();
      JvmPrimitiveType jvmType = TypesFactory.eINSTANCE
          .createJvmPrimitiveType();
      jvmType.setSimpleName(simpleName);
      type.setType(jvmType);
      return type;
    }

    /**
     * @param p
     * @param qName
     * @param value
     * @return
     */
    private SimpleValueProperty createStaticCallProperty(Property p,
        String qName, String value) {
      if (qName.contains(".")) {
        p.setName("call " + qName.replace(".", "#"));
      }
      // ordinary property
      SimpleValueProperty vp = FXGraphFactory.eINSTANCE
          .createSimpleValueProperty();
      if ("true".equals(value) || "false".equals(value)) {
        vp.setBooleanValue(value);
      } else {
        try {
          Integer i = Integer.parseInt(value);
          vp.setIntValue(i);
          vp.setNegative(i < 0);
        } catch (NumberFormatException e) {
          try {
            Double i = Double.parseDouble(value);
            vp.setRealValue(i);
            vp.setNegative(i < 0);
          } catch (NumberFormatException ex) {
            vp.setStringValue(value);
          }
        }
      }
      return vp;
    }

    private Property createProperty(String name) {
      Property p = FXGraphFactory.eINSTANCE.createProperty();
      p.setName(name);
      return p;
    }

    private Property createProperty(String name, ValueProperty value) {
      Property p = createProperty(name);
      p.setValue(value);
      return p;
    }
  }
}
TOP

Related Classes of at.bestsolution.efxclipse.tooling.fxgraph.converter.FXMLLoader$FXMLHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.