r1671 - in branches/jaxx-2.X: jaxx-compiler/src/main/java/jaxx/compiler jaxx-compiler/src/main/java/jaxx/compiler/binding jaxx-compiler/src/main/java/jaxx/compiler/css jaxx-compiler/src/main/java/jaxx/compiler/decorators jaxx-compiler/src/main/java/jaxx/compiler/finalizers jaxx-compiler/src/main/java/jaxx/compiler/tags jaxx-compiler/src/main/java/jaxx/compiler/tags/swing jaxx-compiler/src/main/java/jaxx/compiler/tags/validator maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin
Author: tchemit Date: 2009-12-02 13:56:47 +0100 (Wed, 02 Dec 2009) New Revision: 1671 Added: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/PseudoClassDataBinding.java Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/css/StylesheetHelper.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/DefaultObjectHandler.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/ItemHandler.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/JAXXComboBoxHandler.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/TabHandler.java branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/DataBindingTest.java Log: - extract from JAXXCompiler all the binding logic into DataBindingHelper (one per JAXXCompiler) - extract fro StyleShettHelper all the binding logic into PseudoClassDataBinding - createCompleteSetupMethod method of CompiledObjectDecorator has nothing to do with bindings :) - refactor of bindings (still in progress...) - improve generated code Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/CompiledObjectDecorator.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -45,10 +45,11 @@ * @param compiler * @param object * @param javaFile - * @param initDataBindings +// * @param initDataBindings * @return */ - String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings); + String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile); +// String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings); /** * Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXCompiler.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -20,7 +20,7 @@ */ package jaxx.compiler; -import jaxx.compiler.binding.DataBinding; +import jaxx.compiler.binding.DataBindingHelper; import jaxx.compiler.css.StylesheetHelper; import jaxx.compiler.java.JavaField; import jaxx.compiler.java.JavaFile; @@ -35,7 +35,6 @@ import jaxx.compiler.tags.DefaultObjectHandler; import jaxx.compiler.tags.TagHandler; import jaxx.compiler.tags.TagManager; -import jaxx.compiler.types.TypeManager; import jaxx.runtime.ComponentDescriptor; import jaxx.runtime.JAXXObjectDescriptor; import jaxx.runtime.css.Rule; @@ -60,8 +59,6 @@ import java.net.URL; import java.net.URLDecoder; import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Compiles JAXX files into Java classes. @@ -126,13 +123,13 @@ */ protected Stack<CompiledObject> openComponents = new Stack<CompiledObject>(); /** - * Sequence number used to create automatic variable names. + * to generate ids */ - protected int autogenID = 0; + protected final IDHelper idHelper; /** - * data bindings detected + * Binding Util */ - protected List<DataBinding> dataBindings = new ArrayList<DataBinding>(); + protected final DataBindingHelper bindingHelper; /** * table of symbols for this compiler */ @@ -173,10 +170,6 @@ */ protected Map<String, Map<ClassDescriptor, List<EventHandler>>> eventHandlers = new HashMap<String, Map<ClassDescriptor, List<EventHandler>>>(); /** - * Maps of uniqued id for objects used in compiler - */ - protected Map<Object, String> uniqueIds = new HashMap<Object, String>(); - /** * Map of event handler method names used in compiler */ protected Map<EventHandler, String> eventHandlerMethodNames = new HashMap<EventHandler, String>(); @@ -191,14 +184,6 @@ */ protected List<Runnable> initializers = new ArrayList<Runnable>(); /** - * left brace matcher - */ - protected Matcher leftBraceMatcher = Pattern.compile("^(\\{)|[^\\\\](\\{)").matcher(""); - /** - * right brace matcher - */ - protected Matcher rightBraceMatcher = Pattern.compile("^(\\})|[^\\\\](\\})").matcher(""); - /** * extra interfaces which can by passed to root object via the 'implements' attribute */ private String[] extraInterfaces; @@ -227,22 +212,6 @@ */ protected StringBuffer bodyCode = new StringBuffer(); /** - * Code to initialize data bindings. - */ - protected StringBuffer initDataBindings = new StringBuffer(); - /** - * Body of the applyDataBinding method. - */ - protected StringBuffer applyDataBinding = new StringBuffer(); - /** - * Body of the removeDataBinding method. - */ - protected StringBuffer removeDataBinding = new StringBuffer(); - /** - * Body of the processDataBinding method. - */ - protected StringBuffer processDataBinding = new StringBuffer(); - /** * true if a main() method has been declared in a script */ protected boolean mainDeclared; @@ -317,7 +286,11 @@ log.error("could not find default decorator : " + configuration.getDefaultDecoratorClass()); throw new IllegalArgumentException("could not find default decorator : " + configuration.getDefaultDecoratorClass()); } + idHelper = new IDHelper(configuration.isOptimize()); + } else { + idHelper = new IDHelper(false); } + bindingHelper = new DataBindingHelper(this); } /*------------------------------------------------------------------------*/ @@ -447,7 +420,6 @@ TagHandler handler = TagManager.getTagHandler(tag.getNamespaceURI(), tag.getLocalName(), tag.getPrefix() != null, this); if (handler == null) { reportError("Could not find a Java class corresponding to: <" + tag.getTagName() + ">"); -// assert false : "can't-happen error: error should have been reported during the fast pass and caused an abort"; failed = true; } else { handler.compileSecondPass(tag, this); @@ -568,101 +540,14 @@ } } - public String getJavaCode(Object object) { - String result = TypeManager.getJavaCode(object); - return result; - } - - public Object convertFromString(String string, Class<?> type) { - Object result = TypeManager.convertFromString(string, type); - return result; - } - /*------------------------------------------------------------------------*/ /*-- DataBinding methods -------------------------------------------------*/ /*------------------------------------------------------------------------*/ - public List<DataBinding> getDataBindings() { - return dataBindings; - } - /** - * Examine an attribute value for data binding expressions. Returns a 'cooked' expression which - * can be used to determine the resulting value. It is expected that this expression will be used - * as the source expression in a call to {@link #registerDataBinding}. - * If the attribute value does not invoke data binding, this method returns <code>null</code> - * - * @param stringValue the string value of the property from the XML - * @return a processed version of the expression - * @throws CompilerException ? - */ - public String processDataBindings(String stringValue) throws CompilerException { - int pos = getNextLeftBrace(stringValue, 0); - if (pos != -1) { - StringBuffer expression = new StringBuffer(); - int lastPos = 0; - while (pos != -1 && pos < stringValue.length()) { - if (pos > lastPos) { - if (expression.length() > 0) { - expression.append(" + "); - } - expression.append('"'); - expression.append(escapeJavaString(stringValue.substring(lastPos, pos))); - expression.append('"'); - } - boolean multi = expression.length() > 0; - if (multi) { - expression.append(" + "); - expression.append('('); - } - int pos2 = getNextRightBrace(stringValue, pos + 1); - if (pos2 == -1) { - reportError("unmatched '{' in expression: " + stringValue); - return ""; - } - expression.append(stringValue.substring(pos + 1, pos2)); - if (multi) { - expression.append(')'); - } - pos2++; - if (pos2 < stringValue.length()) { - pos = getNextLeftBrace(stringValue, pos2); - lastPos = pos2; - } else { - pos = stringValue.length(); - lastPos = pos; - } - } - if (lastPos < stringValue.length()) { - if (expression.length() > 0) { - expression.append(" + "); - } - expression.append('"'); - expression.append(escapeJavaString(stringValue.substring(lastPos))); - expression.append('"'); - } - //TC-20091027 : developper must write extact databinding - // the fact of adding the String boxed for String type binding is not - // a good thing, since it add one more call to process in binding - // and add nothing special more ? -// return type == ClassDescriptorLoader.getClassDescriptor(String.class) ? "String.valueOf(" + expression + ")" : expression.toString(); - return expression.toString(); - } - return null; + public DataBindingHelper getBindingHelper() { + return bindingHelper; } - public void registerDataBinding(String src, String dest, String assignment) { - try { - src = checkJavaCode(src); -// if (log.isDebugEnabled()) { -// log.info(getRootObject().getId() + " src=" + src + ", dst=" + dest.trim()); -// } - dataBindings.add(new DataBinding(src, dest, assignment)); -// dataBindings.add(new DataBinding(src, dest, assignment, this)); - } catch (CompilerException e) { - reportError("While parsing data binding for '" + dest.substring(dest.lastIndexOf(".") + 1) + "': " + e.getMessage()); - } - } - public void registerEventHandler(EventHandler handler) { String objectCode = handler.getObjectCode(); Map<ClassDescriptor, List<EventHandler>> listeners = eventHandlers.get(objectCode); @@ -941,6 +826,15 @@ return scriptFields.toArray(new FieldDescriptor[scriptFields.size()]); } + public FieldDescriptor getScriptField(String fieldName) { + for (FieldDescriptor f : symbolTable.getScriptFields()) { + if (fieldName.equals(f.getName())) { + return f; + } + } + return null; + } + public MethodDescriptor[] getScriptMethods() { List<MethodDescriptor> scriptMethods = symbolTable.getScriptMethods(); return scriptMethods.toArray(new MethodDescriptor[scriptMethods.size()]); @@ -959,6 +853,10 @@ return failed; } + public IDHelper getIdHelper() { + return idHelper; + } + /** * Returns a <code>ClassLoader</code> which searches the user-specified class path in addition * to the normal system class path. @@ -1025,13 +923,6 @@ return new JAXXObjectDescriptor(descriptors, css); } -// /*------------------------------------------------------------------------*/ -// /*-- Setter methods ------------------------------------------------------*/ -// /*------------------------------------------------------------------------*/ -// public void setFailed(boolean failed) { -// this.failed = failed; -// } - /*------------------------------------------------------------------------*/ /*-- Buffer --------------------------------------------------------------*/ /*------------------------------------------------------------------------*/ @@ -1047,22 +938,7 @@ return bodyCode; } - public StringBuffer getInitDataBindings() { - return initDataBindings; - } - public StringBuffer getApplyDataBinding() { - return applyDataBinding; - } - - public StringBuffer getRemoveDataBinding() { - return removeDataBinding; - } - - public StringBuffer getProcessDataBinding() { - return processDataBinding; - } - public boolean isMainDeclared() { return mainDeclared; } @@ -1079,38 +955,10 @@ bodyCode.append(code); } - public void appendInitDataBindings(String code) { - initDataBindings.append(code); - } - - public void appendProcessDataBinding(String code) { - processDataBinding.append(code); - } - - public void appendApplyDataBinding(String code) { - applyDataBinding.append(code); - } - - public void appendRemoveDataBinding(String code) { - removeDataBinding.append(code); - } - public void appendLateInitializer(String code) { lateInitializer.append(code); } - public boolean hasProcessDataBinding() { - return processDataBinding.length() > 0; - } - - public boolean hasApplyDataBinding() { - return applyDataBinding.length() > 0; - } - - public boolean hasRemoveDataBinding() { - return removeDataBinding.length() > 0; - } - public boolean hasMethod(String methodName) { for (JavaMethod method : getJavaFile().getMethods()) { if (methodName.equals(method.getName())) { @@ -1212,124 +1060,41 @@ return true; } - protected int getNextLeftBrace(String string, int pos) { - leftBraceMatcher.reset(string); - return leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; - } - - protected int getNextRightBrace(String string, int pos) { - leftBraceMatcher.reset(string); - rightBraceMatcher.reset(string); - int openCount = 1; - int rightPos; - while (openCount > 0) { - pos++; - int leftPos = leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; - rightPos = rightBraceMatcher.find(pos) ? Math.max(rightBraceMatcher.start(1), rightBraceMatcher.start(2)) : -1; - assert leftPos == -1 || leftPos >= pos; - assert rightPos == -1 || rightPos >= pos; - if (leftPos != -1 && leftPos < rightPos) { - pos = leftPos; - openCount++; - } else if (rightPos != -1) { - pos = rightPos; - openCount--; - } else { - openCount = 0; - } - } - return pos; - } - -// public String[] parseParameterList(String parameters) throws CompilerException { -// List<String> result = new ArrayList<String>(); -// StringBuffer current = new StringBuffer(); -// int state = 0; // normal -// for (int i = 0; i < parameters.length(); i++) { -// char c = parameters.charAt(i); -// switch (state) { -// case 0: // normal -// switch (c) { -// case '"': -// current.append(c); -// state = 1; -// break; // in quoted string -// case '\\': -// current.append(c); -// state = 2; -// break; // immediately after backslash -// case ',': -// if (current.length() > 0) { -// result.add(current.toString()); -// current.setLength(0); -// break; -// } else { -// reportError("error parsing parameter list: " + parameters); -// break; -// } -// default: -// current.append(c); -// } -// break; -// case 1: // in quoted string -// switch (c) { -// case '"': -// current.append(c); -// state = 0; -// break; // normal -// case '\\': -// current.append(c); -// state = 3; -// break; // immediate after backslash in quoted string -// default: -// current.append(c); -// } -// break; -// case 2: // immediately after backslash -// current.append(c); -// state = 0; // normal -// break; -// case 3: // immediately after backslash in quoted string -// current.append(c); -// state = 1; // in quoted string -// break; -// } -// } -// if (current.length() > 0) { -// result.add(current.toString()); -// } -// return result.toArray(new String[result.size()]); +// public String getAutoId(ClassDescriptor objectClass) { +// String name = objectClass.getName(); +// name = name.substring(name.lastIndexOf(".") + 1); +// return getAutoId(name); +//// if (configuration.getOptimize()) { +//// return "$" + Integer.toString(autogenID++, 36); +//// } else { +//// String name = objectClass.getName(); +//// name = name.substring(name.lastIndexOf(".") + 1); +//// return "$" + name + autogenID++; +//// } // } - public String getAutoId(ClassDescriptor objectClass) { - String name = objectClass.getName(); - name = name.substring(name.lastIndexOf(".") + 1); - return getAutoId(name); + public String getAutoId(String name) { + return idHelper.nextId(name); // if (configuration.getOptimize()) { // return "$" + Integer.toString(autogenID++, 36); // } else { -// String name = objectClass.getName(); // name = name.substring(name.lastIndexOf(".") + 1); // return "$" + name + autogenID++; // } } - public String getAutoId(String name) { - if (configuration.getOptimize()) { - return "$" + Integer.toString(autogenID++, 36); - } else { - name = name.substring(name.lastIndexOf(".") + 1); - return "$" + name + autogenID++; - } + public String getUniqueId(Object object) { + return idHelper.getUniqueId(object); +// String result = uniqueIds.get(object); +// if (result == null) { +// result = "$u" + uniqueIds.size(); +// uniqueIds.put(object, result); +// } +// return result; } - public String getUniqueId(Object object) { - String result = uniqueIds.get(object); - if (result == null) { - result = "$u" + uniqueIds.size(); - uniqueIds.put(object, result); - } - return result; + public void revertId(String name) { + idHelper.revertId(name); } public void setExtraInterfaces(String[] extraInterfaces) { @@ -1602,32 +1367,293 @@ return engine; } - /** - * Convertit un nom de variable en nom de constante. - * - * @param variableName le nom de variable a convertir - * @return le nom de la constante à partir du nom de la variable - */ - public static String convertVariableNameToConstantName(String variableName) { - //TODO Faire des tests pour savoir si variableName est non null et valide - //TODO Ameliorer l'algo pour tenir compte des caractères non alpha - //TODO pour le moment cela convient, donc... - StringBuilder buffer = new StringBuilder(); - boolean lastCarIsUp = false; - for (int i = 0, j = variableName.length(); i < j; i++) { - char c = variableName.charAt(i); - boolean carIsUp = Character.isUpperCase(c); - if (i > 0 && !lastCarIsUp && carIsUp) { - // ajout d'un _ - buffer.append('_'); - } - if (carIsUp) { - buffer.append(c); - } else { - buffer.append(Character.toUpperCase(c)); - } - lastCarIsUp = carIsUp; - } - return buffer.toString(); + public void clear() { + idHelper.clear(); + bindingHelper.clear(); + objects.clear(); + ids.clear(); } + +// /*------------------------------------------------------------------------*/ +// /*-- REMOVE CODE (Goto to idHelper and DataBindingHelper) ----------------*/ +// /*------------------------------------------------------------------------*/ +// /** +// * Sequence number used to create automatic variable names. +// */ +// protected int autogenID = 0; +// /** +// * data bindings detected +// */ +// protected List<DataBinding> dataBindings = new ArrayList<DataBinding>(); +// /** +// * Maps of uniqued id for objects used in compiler +// */ +// protected Map<Object, String> uniqueIds = new HashMap<Object, String>(); +// /** +// * left brace matcher +// */ +// protected Matcher leftBraceMatcher = Pattern.compile("^(\\{)|[^\\\\](\\{)").matcher(""); +// /** +// * right brace matcher +// */ +// protected Matcher rightBraceMatcher = Pattern.compile("^(\\})|[^\\\\](\\})").matcher(""); +// /** +// * Code to initialize data bindings. +// */ +// protected StringBuffer initDataBindings = new StringBuffer(); +// /** +// * Body of the applyDataBinding method. +// */ +// protected StringBuffer applyDataBinding = new StringBuffer(); +// /** +// * Body of the removeDataBinding method. +// */ +// protected StringBuffer removeDataBinding = new StringBuffer(); +// /** +// * Body of the processDataBinding method. +// */ +// protected StringBuffer processDataBinding = new StringBuffer(); +// public String getJavaCode(Object object) { +// String result = TypeManager.getJavaCode(object); +// return result; +// } +// public Object convertFromString(String string, Class<?> type) { +// Object result = TypeManager.convertFromString(string, type); +// return result; +// } +// public List<DataBinding> getDataBindings() { +// return dataBindings; +// } +// /** +// * Examine an attribute value for data binding expressions. Returns a 'cooked' expression which +// * can be used to determine the resulting value. It is expected that this expression will be used +// * as the source expression in a call to {@link #registerDataBinding}. +// * If the attribute value does not invoke data binding, this method returns <code>null</code> +// * +// * @param stringValue the string value of the property from the XML +// * @return a processed version of the expression +// * @throws CompilerException ? +// */ +// public String processDataBindings(String stringValue) throws CompilerException { +// int pos = getNextLeftBrace(stringValue, 0); +// if (pos != -1) { +// StringBuffer expression = new StringBuffer(); +// int lastPos = 0; +// while (pos != -1 && pos < stringValue.length()) { +// if (pos > lastPos) { +// if (expression.length() > 0) { +// expression.append(" + "); +// } +// expression.append('"'); +// expression.append(escapeJavaString(stringValue.substring(lastPos, pos))); +// expression.append('"'); +// } +// boolean multi = expression.length() > 0; +// if (multi) { +// expression.append(" + "); +// expression.append('('); +// } +// int pos2 = getNextRightBrace(stringValue, pos + 1); +// if (pos2 == -1) { +// reportError("unmatched '{' in expression: " + stringValue); +// return ""; +// } +// expression.append(stringValue.substring(pos + 1, pos2)); +// if (multi) { +// expression.append(')'); +// } +// pos2++; +// if (pos2 < stringValue.length()) { +// pos = getNextLeftBrace(stringValue, pos2); +// lastPos = pos2; +// } else { +// pos = stringValue.length(); +// lastPos = pos; +// } +// } +// if (lastPos < stringValue.length()) { +// if (expression.length() > 0) { +// expression.append(" + "); +// } +// expression.append('"'); +// expression.append(escapeJavaString(stringValue.substring(lastPos))); +// expression.append('"'); +// } +// //TC-20091027 : developper must write extact databinding +// // the fact of adding the String boxed for String type binding is not +// // a good thing, since it add one more call to process in binding +// // and add nothing special more ? +//// return type == ClassDescriptorLoader.getClassDescriptor(String.class) ? "String.valueOf(" + expression + ")" : expression.toString(); +// return expression.toString(); +// } +// return null; +// } +// public void registerDataBinding(String src, String dest, String assignment) { +// try { +// src = checkJavaCode(src); +//// if (log.isDebugEnabled()) { +//// log.info(getRootObject().getId() + " src=" + src + ", dst=" + dest.trim()); +//// } +// dataBindings.add(new DataBinding(src, dest, assignment)); +//// dataBindings.add(new DataBinding(src, dest, assignment, this)); +// } catch (CompilerException e) { +// reportError("While parsing data binding for '" + dest.substring(dest.lastIndexOf(".") + 1) + "': " + e.getMessage()); +// } +// } +// public void setFailed(boolean failed) { +// this.failed = failed; +// } +// public StringBuffer getInitDataBindings() { +// return initDataBindings; +// } +// public StringBuffer getApplyDataBinding() { +// return applyDataBinding; +// } +// public StringBuffer getRemoveDataBinding() { +// return removeDataBinding; +// } +// public StringBuffer getProcessDataBinding() { +// return processDataBinding; +// } +// public void appendInitDataBindings(String code) { +// initDataBindings.append(code); +// } + +// public void appendProcessDataBinding(String code) { +// processDataBinding.append(code); +// } + +// public void appendApplyDataBinding(String code) { +// applyDataBinding.append(code); +// } + +// public void appendRemoveDataBinding(String code) { +// removeDataBinding.append(code); +// } + +// public boolean hasProcessDataBinding() { +// return processDataBinding.length() > 0; +// } + +// public boolean hasApplyDataBinding() { +// return applyDataBinding.length() > 0; +// } + + // public boolean hasRemoveDataBinding() { +// return removeDataBinding.length() > 0; +// } +// public int getNextLeftBrace(String string, int pos) { +// leftBraceMatcher.reset(string); +// return leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; +// } +// +// public int getNextRightBrace(String string, int pos) { +// leftBraceMatcher.reset(string); +// rightBraceMatcher.reset(string); +// int openCount = 1; +// int rightPos; +// while (openCount > 0) { +// pos++; +// int leftPos = leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; +// rightPos = rightBraceMatcher.find(pos) ? Math.max(rightBraceMatcher.start(1), rightBraceMatcher.start(2)) : -1; +// assert leftPos == -1 || leftPos >= pos; +// assert rightPos == -1 || rightPos >= pos; +// if (leftPos != -1 && leftPos < rightPos) { +// pos = leftPos; +// openCount++; +// } else if (rightPos != -1) { +// pos = rightPos; +// openCount--; +// } else { +// openCount = 0; +// } +// } +// return pos; +// } +// +// public String[] parseParameterList(String parameters) throws CompilerException { +// List<String> result = new ArrayList<String>(); +// StringBuffer current = new StringBuffer(); +// int state = 0; // normal +// for (int i = 0; i < parameters.length(); i++) { +// char c = parameters.charAt(i); +// switch (state) { +// case 0: // normal +// switch (c) { +// case '"': +// current.append(c); +// state = 1; +// break; // in quoted string +// case '\\': +// current.append(c); +// state = 2; +// break; // immediately after backslash +// case ',': +// if (current.length() > 0) { +// result.add(current.toString()); +// current.setLength(0); +// break; +// } else { +// reportError("error parsing parameter list: " + parameters); +// break; +// } +// default: +// current.append(c); +// } +// break; +// case 1: // in quoted string +// switch (c) { +// case '"': +// current.append(c); +// state = 0; +// break; // normal +// case '\\': +// current.append(c); +// state = 3; +// break; // immediate after backslash in quoted string +// default: +// current.append(c); +// } +// break; +// case 2: // immediately after backslash +// current.append(c); +// state = 0; // normal +// break; +// case 3: // immediately after backslash in quoted string +// current.append(c); +// state = 1; // in quoted string +// break; +// } +// } +// if (current.length() > 0) { +// result.add(current.toString()); +// } +// return result.toArray(new String[result.size()]); +// } +// /** +// * Convertit un nom de variable en nom de constante. +// * +// * @param variableName le nom de variable a convertir +// * @return le nom de la constante à partir du nom de la variable +// */ +// public static String convertVariableNameToConstantName(String variableName) { +// StringBuilder buffer = new StringBuilder(); +// boolean lastCarIsUp = false; +// for (int i = 0, j = variableName.length(); i < j; i++) { +// char c = variableName.charAt(i); +// boolean carIsUp = Character.isUpperCase(c); +// if (i > 0 && !lastCarIsUp && carIsUp) { +// // ajout d'un _ +// buffer.append('_'); +// } +// if (carIsUp) { +// buffer.append(c); +// } else { +// buffer.append(Character.toUpperCase(c)); +// } +// lastCarIsUp = carIsUp; +// } +// return buffer.toString(); +// } + } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/JAXXEngine.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -449,6 +449,9 @@ jaxxFiles.clear(); jaxxFileClassNames.clear(); symbolTables.clear(); + for (JAXXCompiler jaxxCompiler : compilers.values()) { + jaxxCompiler.clear(); + } compilers.clear(); if (profiler != null) { profiler.clear(); @@ -594,11 +597,13 @@ //FIXME : deal better the exception treatment... } catch (CompilerException e) { - System.err.println(e.getMessage()); - e.printStackTrace(); + log.error(e.getMessage()); +// System.err.println(e.getMessage()); +// e.printStackTrace(); return -1; } catch (Throwable e) { - e.printStackTrace(); + log.error(e.getMessage()); +// e.printStackTrace(); return -1; } finally { //TC - 20081018 only reset when no error was detected @@ -641,7 +646,7 @@ return cons.newInstance(this, parentFile, file, className, configuration, Arrays.asList("java.awt.*", "java.awt.event.*", - "java.beans.*", +// "java.beans.*", "java.io.*", "java.lang.*", "java.util.*", @@ -655,7 +660,7 @@ "jaxx.runtime.Util", "jaxx.runtime.SwingUtil", "static org.nuiton.i18n.I18n._", - "static jaxx.runtime.Util.createImageIcon") + "static jaxx.runtime.SwingUtil.createImageIcon") ); } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBinding.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -1,5 +1,5 @@ /* - * *##% + * *##% * JAXX Compiler * Copyright (C) 2008 - 2009 CodeLutin * @@ -22,11 +22,19 @@ import jaxx.compiler.CompilerException; import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.java.JavaFileGenerator; +import jaxx.compiler.java.JavaMethod; +import jaxx.compiler.types.TypeManager; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import java.util.ArrayList; +import java.util.List; + /** - * Represents a data binding in a JAXX file. <code>DataBinding</code> uses + * Represents a data binding in a JAXX file. <code>DataBinding</code> uses * {@link DataSource} to track changes to a source expression and update * the destination. */ @@ -41,6 +49,14 @@ */ private String id; /** + * Real Id of the data binding (can be suffix by a number for css binding to avoid collisions) + */ + private String realId; + /** + * Constant id build from the {@link #realId} and used instead of {@link #realId} in generated code + */ + protected String constantId; + /** * source of the data binding */ private String source; @@ -49,81 +65,214 @@ * the binding. */ private String assignment; + /** + * A internal flag to + */ + private boolean quickNoDependencies; /** + * Compiled data source + */ + protected DataSource dataSource; + + /** + * code to add to processDataBinding (null if no binding) + */ + protected String processDataBinding; + /** + * code to register the databinding (null if no binding) + */ + protected String initDataBinding; + /** + * code to put in applyDataBinding method on generated java file + */ + private StringBuffer addListenerCode = new StringBuffer(); + /** + * code to put in removeDataBinding method on generated java file + */ + private StringBuffer removeListenerCode = new StringBuffer(); + /** + * Extra method to add to the binding + */ + protected final List<JavaMethod> methods = new ArrayList<JavaMethod>(); + /** + * internal state passed to {@code true} when {@link #compile(jaxx.compiler.JAXXCompiler)} method is invoked + */ + private boolean compiled; + + /** * Creates a new data binding. * - * @param source the Java source code for the data binding expression - * @param id the data binding destination in the form <code>id.propertyName</code> - * @param assignment Java snippet which will cause the destination property to be updated with the current value of the binding + * @param id the data binding destination in the form <code>id.propertyName</code> + * @param source the Java source code for the data binding expression + * @param assignment Java snippet which will cause the destination property to be updated with the current value of the binding + * @param quickNoDependencies internal flag to not treate process databinding in not a real binding */ - public DataBinding(String source, String id, String assignment) { + public DataBinding(String id, String source, String assignment, boolean quickNoDependencies) { +// public DataBinding(String source, String id, String assignment, boolean quickNoDependencies) { this.id = id; this.source = source; this.assignment = assignment; + this.quickNoDependencies = quickNoDependencies; if (log.isDebugEnabled()) { - log.debug("id=" + id + " assignement=" + assignment + " source=" + source); + log.debug("id=" + id + " assignement=" + assignment + " source=" + source + " quickNoDependencies=" + quickNoDependencies); } } - public String getId() { - return id; +// public String getId() { +// return id; +// } + +// public DataSource getDataSource() { +// return dataSource; +// } + + public String getAssignment() { + return assignment; } + public String getSource() { + return source; + } + + public boolean isQuickNoDependencies() { + return quickNoDependencies; + } + + public String getProcessDataBinding() { + return processDataBinding; + } + + public String getInitDataBinding() { + return initDataBinding; + } + + public String getAddListenerCode() { + return addListenerCode.toString(); + } + + public String getRemoveListenerCode() { + return removeListenerCode.toString(); + } + + public String getRealId() { + return realId; + } + + public String getConstantId() { + return constantId; + } + + public List<JavaMethod> getMethods() { + return methods; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); + b.append("id", id); + b.append("source", source); + b.append("assignement", assignment); + b.append("quickNoDependencies", quickNoDependencies); + if (compiled) { + b.append("realdId", realId); + b.append("constantId", getConstantId()); + if (!addListenerCode.toString().trim().isEmpty()) { + b.append("addListenerCode", addListenerCode.toString().trim()); + } + if (!removeListenerCode.toString().trim().isEmpty()) { + b.append("removeListenerCode", removeListenerCode.toString().trim()); + } + b.append("dataSource", dataSource); + } + return b.toString(); + } + /** - * Compiles the data binding expression. This method calls methods in + * Compiles the data binding expression. This method calls methods in * <code>JAXXCompiler</code> to add the Java code that performs the data * binding setup. * * @param compiler compiler which includes the data binding - * @param quickNoDependencies true to optimize bindings with no dependencies by simply running them at startup time + * // * @param quickNoDependencies true to optimize bindings with no dependencies by simply running them at startup time * @return {@code true} if the expression has dependencies, {@code false} otherwise - * @throws CompilerException if a compilation error occurs + * @throws jaxx.compiler.CompilerException + * if a compilation error occurs */ - public boolean compile(JAXXCompiler compiler, boolean quickNoDependencies) throws CompilerException { + public boolean compile(JAXXCompiler compiler) throws CompilerException { +// public boolean compile(JAXXCompiler compiler, boolean quickNoDependencies) throws CompilerException { - DataSource dataSource = new DataSource(id, source, compiler); + if (compiled) { + throw new IllegalStateException(this + " has already been compiled"); + } + DataBindingHelper bindingHelper = compiler.getBindingHelper(); + + realId = bindingHelper.getSafeId(id.trim()); + constantId = TypeManager.convertVariableNameToConstantName("binding_" + realId); + + dataSource = new DataSource(realId, constantId, getSource(), compiler, addListenerCode, removeListenerCode, methods); + // handles all of the listener additions - //TC-20091026 use 'this' instead of root object javaCode -// boolean result = dataSource.compile("new jaxx.runtime.DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + compiler.getJavaCode(id) + ")"); - boolean result = dataSource.compile("new DataBindingListener(this, " + compiler.getJavaCode(id) + ")"); - if (log.isDebugEnabled()) { - log.debug(id + " isBinding ? " + result); + + boolean isBinding = dataSource.compile(); + + if (!isBinding) { + + bindingHelper.revertSafeId(id.trim()); } + + // was compiled + compiled = true; + + if (isBinding && (DataBindingHelper.SHOW_LOG || log.isDebugEnabled())) { + log.info("detect a databinding\n" + this); + } + + // update initDataBinding code + + initDataBinding = getInitDataBindingCode(compiler, dataSource, isBinding); + + // update processDataBinding code + + processDataBinding = getProcessDataBindingCode(compiler, dataSource, isBinding); + + return isBinding; + } + + protected String getInitDataBindingCode(JAXXCompiler compiler, DataSource dataSource, boolean isBinding) { String eol = JAXXCompiler.getLineSeparator(); - if (!result && quickNoDependencies) { + if (isBinding) { + return null; + } + if (isQuickNoDependencies()) { // layout is specially handled early in the chain if (!id.endsWith(".layout")) { - compiler.appendInitDataBindings(assignment + eol); + return getAssignment() + eol; } - return false; // no dependencies, just a static expression } + return null; + } + protected String getProcessDataBindingCode(JAXXCompiler compiler, DataSource dataSource, boolean isBinding) { + if (!isBinding) { + // no binding = no process code + return null; + } + String eol = JAXXCompiler.getLineSeparator(); StringBuilder buffer = new StringBuilder(); - if (compiler.hasProcessDataBinding()) { - buffer.append(" else "); - } else { - buffer.append(" "); - } - buffer.append("if (").append(compiler.getJavaCode(id)).append(".equals($dest)) {").append(eol); + String objectCode = dataSource.getObjectCode(); - if (log.isDebugEnabled()) { - log.debug(id + " objectCode= " + objectCode); - } - //TC-20091026 no need to test objectCode not null if on root object -// boolean needTest = objectCode != null; + + // no need to test objectCode not null if on root object boolean needTest = objectCode != null && !compiler.getRootObject().getId().equals(objectCode); if (needTest) { - buffer.append(" if (").append(objectCode).append(" != null) {").append(eol); - buffer.append(" "); + buffer.append("if (").append(objectCode).append(" != null) {").append(eol); } - buffer.append(" ").append(assignment.trim()); + buffer.append(JavaFileGenerator.indent(getAssignment(), needTest ? 4 : 0, false, eol)); if (needTest) { - buffer.append(eol).append(" }"); + buffer.append(eol).append("}"); } - buffer.append(eol).append(" }"); - compiler.appendProcessDataBinding(buffer.toString()); - return true; + return buffer.toString(); } -} +} \ No newline at end of file Added: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java (rev 0) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -0,0 +1,243 @@ +package jaxx.compiler.binding; + +import jaxx.compiler.CompilerException; +import jaxx.compiler.JAXXCompiler; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Helper to be used by compiler to treate data bindings. + * <p/> + * Note : The code in this class was previously directly in JAXXCompiler, now prefer have a separate + * class to make {@link JAXXCompiler} more simple and clear. + * <p/> + * Created: 27 nov. 2009 + * + * @author Tony Chemit <chemit@codelutin.com> Copyright Code Lutin + * @version $Revision$ + * <p/> + * Mise a jour: $Date$ par : + * $Author: tchemit $ + * @since 2.0.0 + */ +public class DataBindingHelper { + + /** + * To debug binding without any log interference + */ + public static boolean SHOW_LOG = true; + /** + * left brace matcher + */ + protected static final Matcher leftBraceMatcher = Pattern.compile("^(\\{)|[^\\\\](\\{)").matcher(""); + /** + * right brace matcher + */ + protected static final Matcher rightBraceMatcher = Pattern.compile("^(\\})|[^\\\\](\\})").matcher(""); + /** + * Registred data binding for the compiler, then after the invocation of method {@link #finalizeBindings()} + * only the real data bindings, the simple bindings will be moved to {@link #simpleBindings}. + */ + protected final List<DataBinding> dataBindings = new ArrayList<DataBinding>(); + /** + * Simpel bindings for the compiler + */ + protected final List<DataBinding> simpleBindings = new ArrayList<DataBinding>(); + /** + * Associated compiler + */ + protected final JAXXCompiler compiler; + /** + * Counter by unsafe type + */ + protected final Map<String, Integer> autoUnsafeGenIds = new TreeMap<String, Integer>(); + + public DataBindingHelper(JAXXCompiler compiler) { + this.compiler = compiler; + } + + /** + * Examine an attribute value for data binding expressions. Returns a 'cooked' expression which + * can be used to determine the resulting value. It is expected that this expression will be used + * as the source expression in a call to {@link #registerDataBinding}. + * If the attribute value does not invoke data binding, this method returns <code>null</code> + * + * @param stringValue the string value of the property from the XML + * @return a processed version of the expression + * @throws jaxx.compiler.CompilerException + * ? + */ + public static String processDataBindings(String stringValue) throws CompilerException { + int pos = getNextLeftBrace(stringValue, 0); + if (pos != -1) { + StringBuffer expression = new StringBuffer(); + int lastPos = 0; + while (pos != -1 && pos < stringValue.length()) { + if (pos > lastPos) { + if (expression.length() > 0) { + expression.append(" + "); + } + expression.append('"'); + expression.append(JAXXCompiler.escapeJavaString(stringValue.substring(lastPos, pos))); + expression.append('"'); + } + boolean multi = expression.length() > 0; + if (multi) { + expression.append(" + "); + expression.append('('); + } + int pos2 = getNextRightBrace(stringValue, pos + 1); + if (pos2 == -1) { + throw new CompilerException("unmatched '{' in expression: " + stringValue); + } + expression.append(stringValue.substring(pos + 1, pos2)); + if (multi) { + expression.append(')'); + } + pos2++; + if (pos2 < stringValue.length()) { + pos = getNextLeftBrace(stringValue, pos2); + lastPos = pos2; + } else { + pos = stringValue.length(); + lastPos = pos; + } + } + if (lastPos < stringValue.length()) { + if (expression.length() > 0) { + expression.append(" + "); + } + expression.append('"'); + expression.append(JAXXCompiler.escapeJavaString(stringValue.substring(lastPos))); + expression.append('"'); + } + //TC-20091027 : developper must write extact databinding + // the fact of adding the String boxed for String type binding is not + // a good thing, since it add one more call to process in binding + // and add nothing special more ? +// return type == ClassDescriptorLoader.getClassDescriptor(String.class) ? "String.valueOf(" + expression + ")" : expression.toString(); + return expression.toString(); + } + return null; + } + + public DataBinding[] getDataBindings() { + return dataBindings.toArray(new DataBinding[dataBindings.size()]); + } + + public DataBinding[] getSimpleBindings() { + return simpleBindings.toArray(new DataBinding[simpleBindings.size()]); + } + + public void registerDataBinding(String id, String binding, String assignment) { + binding = compiler.checkJavaCode(binding); + registerDataBinding(new DataBinding(id, binding, assignment, true)); + } + + public void registerDataBinding(DataBinding binding) { + dataBindings.add(binding); + } + + public void clear() { + simpleBindings.clear(); + dataBindings.clear(); + autoUnsafeGenIds.clear(); + } + + /** + * Obtain the next safe id for the given binding id. + * <p/> + * With css, we can obtain the same binding id, so we must + * check for unicity each time we want a new binding id. + * <p/> + * If an id is already taken, we suffix by {@code _XXX} until + * found a free id. + * + * @param id the id of the binding + * @return the safe id of the binding + */ + public String getSafeId(String id) { + + Integer integer = autoUnsafeGenIds.get(id); + String result = id; + if (integer == null) { + integer = 0; + } else { + result += "_" + integer; + } + autoUnsafeGenIds.put(id, ++integer); + return result; + } + + /** + * Revert a previous computed safe id. + * <p/> + * This is needed when a binding compiled is not an data binding, we want to free + * the safe id to avoid hole in numbers. + * + * @param id the original id to revert in counter. + */ + public void revertSafeId(String id) { + Integer integer = autoUnsafeGenIds.get(id); + if (integer != null) { + integer--; + if (integer > 0) { + autoUnsafeGenIds.put(id, integer); + } else { + autoUnsafeGenIds.remove(id); + } + } + } + + /** + * Finalize discovered bindings for the associated compiler. + * <p/> + * The method will compile all bindings. The one which are not data binding, are just + * process as property set (with the binding assigment) and remove from the binding list. + */ + public void finalizeBindings() { + + for (Iterator<DataBinding> itr = dataBindings.iterator(); itr.hasNext();) { + DataBinding binding = itr.next(); + boolean isBinding = binding.compile(compiler); + if (!isBinding) { + // ce n'est pas un binding, on enregistre le code d'init (si il existe) + simpleBindings.add(binding); + // on supprime le faux binding + itr.remove(); + } + } + } + + protected static int getNextLeftBrace(String string, int pos) { + leftBraceMatcher.reset(string); + return leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; + } + + protected static int getNextRightBrace(String string, int pos) { + leftBraceMatcher.reset(string); + rightBraceMatcher.reset(string); + int openCount = 1; + int rightPos; + while (openCount > 0) { + pos++; + int leftPos = leftBraceMatcher.find(pos) ? Math.max(leftBraceMatcher.start(1), leftBraceMatcher.start(2)) : -1; + rightPos = rightBraceMatcher.find(pos) ? Math.max(rightBraceMatcher.start(1), rightBraceMatcher.start(2)) : -1; + assert leftPos == -1 || leftPos >= pos; + assert rightPos == -1 || rightPos >= pos; + if (leftPos != -1 && leftPos < rightPos) { + pos = leftPos; + openCount++; + } else if (rightPos != -1) { + pos = rightPos; + openCount--; + } else { + openCount = 0; + } + } + return pos; + } + +} Property changes on: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataBindingHelper.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/DataSource.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -1,5 +1,5 @@ /* - * *##% + * *##% * JAXX Compiler * Copyright (C) 2008 - 2009 CodeLutin * @@ -24,8 +24,9 @@ import jaxx.compiler.CompilerException; import jaxx.compiler.JAXXCompiler; import jaxx.compiler.UnsupportedAttributeException; -import jaxx.compiler.java.JavaField; +import jaxx.compiler.java.JavaArgument; import jaxx.compiler.java.JavaFileGenerator; +import jaxx.compiler.java.JavaMethod; import jaxx.compiler.java.parser.JavaParser; import jaxx.compiler.java.parser.JavaParserConstants; import jaxx.compiler.java.parser.JavaParserTreeConstants; @@ -37,6 +38,10 @@ import jaxx.compiler.tags.DefaultObjectHandler; import jaxx.compiler.tags.TagManager; import jaxx.compiler.types.TypeManager; +import jaxx.runtime.Util; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -45,6 +50,7 @@ import java.io.StringReader; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -69,71 +75,77 @@ /** * id of data source */ - private String id; + private final String id; /** + * Constant id + */ + protected final String constantId; + /** * The Java source code for the expression. */ - private String source; + private final String source; /** * The current <code>JAXXCompiler</code>. */ - private JAXXCompiler compiler; + private final JAXXCompiler compiler; /** * List of symbols which this data source expression depends on. */ - private List<String> dependencySymbols = new ArrayList<String>(); + private final List<String> dependencySymbols = new ArrayList<String>(); /** - * + * code to put in applyDataBinding method on generated java file */ - private StringBuffer addListenerCode = new StringBuffer(); + private final StringBuffer addListenerCode; /** - * + * code to put in removeDataBinding method on generated java file */ - private StringBuffer removeListenerCode = new StringBuffer(); + private final StringBuffer removeListenerCode; /** - * - */ - private boolean compiled; - /** * the delegate of property to be required */ private String objectCode; - /** - * the data source id - */ - private String listenerId; + protected final List<JavaMethod> methods; + /** - * Creates a new data source. After creating a <code>DataSource</code>, use {@link #compile} + * Creates a new data source. After creating a <code>DataSource</code>, use {@link #compile()} * to cause it to function at runtime. * - * @param id the DataSource's id - * @param source the Java source code for the data source expression - * @param compiler the current <code>JAXXCompiler</code> + * @param id the DataSource's id + * @param constantId the DataSource constant id + * @param source the Java source code for the data source expression + * @param compiler the current <code>JAXXCompiler</code> + * @param addListenerCode where to push add code + * @param removeListenerCode where to push remove code + * @param methods where to store extra method to add to binding */ - public DataSource(String id, String source, JAXXCompiler compiler) { + public DataSource(String id, String constantId, String source, JAXXCompiler compiler, StringBuffer addListenerCode, StringBuffer removeListenerCode, List<JavaMethod> methods) { this.id = id; + this.constantId = constantId; this.source = source; this.compiler = compiler; - if (log.isDebugEnabled()) { - log.debug("id=" + id + " source=" + source); - } + this.addListenerCode = addListenerCode; + this.removeListenerCode = removeListenerCode; + this.methods = methods; } - public String getId() { - return id; - } - - public String getSource() { - return source; - } - public String getObjectCode() { return objectCode; } - public String getListenerId() { - return listenerId; + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); + b.append("source:id", id); + b.append("source:source", source); + b.append("source:objectCode", objectCode); + if (dependencySymbols != null && !dependencySymbols.isEmpty()) { + b.append("source:dependencySymbols", dependencySymbols.size()); + for (String d : dependencySymbols) { + b.append("source:depencendy ", d); + } + } + return b.toString(); } /** @@ -143,19 +155,16 @@ * time. You must pass in a Java expression which evaluates to a <code>PropertyChangeListener</code>; this * expression will be compiled and evaluated at runtime to yield the <code>DataSource's</code> listener. * - * @param propertyChangeListenerCode Java code snippet which evaluates to a <code>PropertyChangeListener</code> * @return <code>true</code> if the expression has dependencies, <code>false</code> otherwise - * @throws CompilerException if a compilation error occurs + * @throws jaxx.compiler.CompilerException + * if a compilation error occurs * @throws IllegalStateException if data source was already compiled */ - public boolean compile(String propertyChangeListenerCode) throws CompilerException, IllegalStateException { - if (compiled) { - throw new IllegalStateException(this + " has already been compiled"); + protected boolean compile() throws CompilerException, IllegalStateException { + + if (DataBindingHelper.SHOW_LOG || log.isDebugEnabled()) { + log.debug("try to compile dataSource\n" + this); } - listenerId = compiler.getAutoId(getClass().getSimpleName()); - if (log.isDebugEnabled()) { - log.debug("listenerId=" + listenerId); - } JavaParser p = new JavaParser(new StringReader(source)); while (!p.Line()) { SimpleNode node = p.popNode(); @@ -167,52 +176,18 @@ if (log.isDebugEnabled()) { log.debug("dependencySymbols=" + dependencySymbols); } - if (dependencySymbols.size() > 0) { - // a real binding was detected - // add a dataBinding field - //TC 20081108 prefer add a real JavaField instead of raw code - //compiler.appendBodyCode("private PropertyChangeListener " + id + " = " + propertyChangeListenerCode + ";\n"); - compiler.addSimpleField(new JavaField(Modifier.PRIVATE, PropertyChangeListener.class.getSimpleName(), listenerId, false, propertyChangeListenerCode)); + boolean isBinding = !dependencySymbols.isEmpty(); - // add listener codes in compiler - - String javaCodeId = TypeManager.getJavaCode(id); - String eol = JAXXCompiler.getLineSeparator(); - - if (compiler.hasApplyDataBinding()) { - compiler.appendApplyDataBinding(" else "); - } - compiler.appendApplyDataBinding("if (" + javaCodeId + ".equals($binding)) {"); - compiler.appendApplyDataBinding(" " + addListenerCode + eol); - compiler.appendApplyDataBinding("}"); - - if (compiler.hasRemoveDataBinding()) { - compiler.appendRemoveDataBinding(" else "); - } - compiler.appendRemoveDataBinding("if (" + javaCodeId + ".equals($binding)) {"); - compiler.appendRemoveDataBinding(" " + removeListenerCode + eol); - compiler.appendRemoveDataBinding("}"); - } - //TC-20091027 if no dependency symbols then no listeners -// compileListeners(); - compiled = true; - - return dependencySymbols.size() > 0; + return isBinding; } -// /** -// * @return a list of symbols on which this data source depends. -// */ -// public Collection<String> getDependencies() { -// return Collections.unmodifiableList(dependencySymbols); -// } - /** * Examines a node to identify any dependencies it contains. * * @param node node to scan - * @throws CompilerException ? + * @throws jaxx.compiler.CompilerException + * ? */ private void scanNode(SimpleNode node) throws CompilerException { if (node.getId() == JavaParserTreeConstants.JJTMETHODDECLARATION || @@ -237,6 +212,9 @@ break; case JavaParserTreeConstants.JJTPRIMARYEXPRESSION: type = determineExpressionType(node); + if (log.isDebugEnabled()) { + log.debug("result of determineExpressionType for " + node.getText() + " = " + type); + } break; case JavaParserTreeConstants.JJTLITERAL: type = determineLiteralType(node); @@ -246,20 +224,6 @@ break; } node.setJavaType(type); - -// switch (node.getId()) { -// case JavaParserTreeConstants.JJTMETHODDECLARATION: -// break; -// case JavaParserTreeConstants.JJTFIELDDECLARATION: -// break; -// -// default: -// int count = node.jjtGetNumChildren(); -// for (int i = 0; i < count; i++) { -// scanNode(node.getChild(i), listenerId); -// } -// determineNodeType(node); -// } } /** @@ -270,6 +234,9 @@ * @return the class descriptor of the return type or null */ private ClassDescriptor determineExpressionType(SimpleNode expression) { + if (log.isDebugEnabled()) { + log.debug("for expression " + expression.getText()); + } assert expression.getId() == JavaParserTreeConstants.JJTPRIMARYEXPRESSION; SimpleNode prefix = expression.getChild(0); if (prefix.jjtGetNumChildren() == 1) { @@ -278,7 +245,11 @@ prefix.setJavaType(prefix.getChild(0).getJavaType()); } else if (type == JavaParserTreeConstants.JJTNAME && expression.jjtGetNumChildren() == 1) { // name with no arguments after it - prefix.setJavaType(scanCompoundSymbol(prefix.getText().trim(), compiler.getRootObject().getObjectClass(), false)); + ClassDescriptor classDescriptor = scanCompoundSymbol(prefix.getText().trim(), compiler.getRootObject().getObjectClass(), false); + if (log.isDebugEnabled()) { + log.debug("scanCompoundSymbol result for node " + prefix.getText().trim() + " = " + classDescriptor); + } + prefix.setJavaType(classDescriptor); } } @@ -298,6 +269,9 @@ if (suffix.getChild(0).jjtGetNumChildren() == 0) { // at the moment only no-argument methods are trackable contextClass = scanCompoundSymbol(lastNode, contextClass, true); + if (log.isDebugEnabled()) { + log.debug("scanCompoundSymbol result for node " + lastNode + " = " + contextClass); + } if (contextClass == null) { return null; } @@ -310,9 +284,15 @@ code = compiler.getRootObject().getJavaCode(); } String methodName = lastNode.substring(dotPos + 1).trim(); + if (log.isDebugEnabled()) { + log.debug("try to find type for method " + methodName + ", code : " + code); + } try { MethodDescriptor method = contextClass.getMethodDescriptor(methodName); trackMemberIfPossible(code, contextClass, method.getName(), true); + if (log.isDebugEnabled()) { + log.debug("method found = " + method); + } return method.getReturnType(); } catch (NoSuchMethodException e) { // happens for methods defined in the current JAXX file via scripts @@ -331,8 +311,8 @@ // addListener(compiler.getRootObject().getId(), addListener(compiler.getRootObject().getId()+"."+propertyName, null, - "addPropertyChangeListener(\"" + propertyName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator(), - "removePropertyChangeListener(\"" + propertyName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator()); + "addPropertyChangeListener(\"" + propertyName + "\", this);" + JAXXCompiler.getLineSeparator(), + "removePropertyChangeListener(\"" + propertyName + "\", this);" + JAXXCompiler.getLineSeparator()); contextClass = newMethod.getReturnType(); } } @@ -390,13 +370,15 @@ * @return the type of the symbol (or null if it could not be determined). */ private ClassDescriptor scanCompoundSymbol(String symbol, ClassDescriptor contextClass, boolean isMethod) { + String[] tokens = symbol.split("\\s*\\.\\s*"); if (log.isDebugEnabled()) { - log.debug("for symbol " + symbol + " and contextClass " + contextClass + ", isMethod " + isMethod); + log.debug("for symbol " + symbol + ", contextClass " + contextClass + ", isMethod " + isMethod); + log.debug("tokens " + Arrays.toString(tokens)); } - String[] tokens = symbol.split("\\s*\\.\\s*"); StringBuffer currentSymbol = new StringBuffer(); StringBuffer tokensSeenSoFar = new StringBuffer(); - boolean accepted; // if this ends up false, it means we weren't able to figure out + // if this ends up false, it means we weren't able to figure out + boolean accepted; // which object the method is being invoked on boolean recognizeClassNames = true; for (int j = 0; j < tokens.length - (isMethod ? 1 : 0); j++) { @@ -410,11 +392,16 @@ currentSymbol.append('.'); } currentSymbol.append(tokens[j]); - + if (log.isDebugEnabled()) { + log.debug("try to find type for " + currentSymbol); + } if (currentSymbol.indexOf(".") == -1) { String memberName = currentSymbol.toString(); CompiledObject object = compiler.getCompiledObject(memberName); if (object != null) { + if (log.isDebugEnabled()) { + log.debug("detected an object " + object); + } contextClass = object.getObjectClass(); currentSymbol.setLength(0); accepted = true; @@ -434,37 +421,39 @@ accepted = true; recognizeClassNames = false; } catch (NoSuchFieldException e) { - if (j == 0 || j == 1 && tokens[0].equals(compiler.getRootObject().getId())) { // still in root context - FieldDescriptor[] newFields = compiler.getScriptFields(); - for (FieldDescriptor newField : newFields) { - if (newField.getName().equals(memberName)) { - try { - contextClass = newField.getType(); - } catch (Exception e2) { - // try to get a generic type - CompiledObject compiledObject = compiler.getCompiledObject(newField.getName()); - log.warn("could not find type for field " + newField + " membername " + memberName + ", compiledObject : " + compiledObject); - contextClass = null; - continue; - } - addListener(tokensSeenSoFar.toString(), - null, - "addPropertyChangeListener(\"" + memberName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator(), - "removePropertyChangeListener(\"" + memberName + "\", " + listenerId + ");" + JAXXCompiler.getLineSeparator()); + if (j == 0 || j == 1 && tokens[0].equals(compiler.getRootObject().getId())) { + // still in root context + FieldDescriptor newField = compiler.getScriptField(memberName); + if (newField != null) { + if (log.isDebugEnabled()) { + log.debug("Detect a field script to use in binding : " + newField); + } + contextClass = newField.getType(); - assert contextClass != null : "script field '" + memberName + "' is defined, but has type null"; - currentSymbol.setLength(0); - accepted = true; - recognizeClassNames = false; - break; + if (log.isDebugEnabled()) { + log.debug("Add listener for expression " + tokensSeenSoFar.toString()); + } + String eol = JAXXCompiler.getLineSeparator(); + addListener(tokensSeenSoFar.toString(), + null, + "addPropertyChangeListener(\"" + memberName + "\", this);" + eol, +// "addPropertyChangeListener(\"" + memberName + "\", " + listenerId + ");" + eol, + "removePropertyChangeListener(\"" + memberName + "\", this);" + eol); +// "removePropertyChangeListener(\"" + memberName + "\", " + listenerId + ");" + eol); - } + assert contextClass != null : "script field '" + memberName + "' is defined, but has type null"; + currentSymbol.setLength(0); + accepted = true; + recognizeClassNames = false; } } } } } if (currentSymbol.length() > 0 && recognizeClassNames) { + if (log.isDebugEnabled()) { + log.debug("Try to recognizeClassNames for symbol " + currentSymbol); + } contextClass = TagManager.resolveClass(currentSymbol.toString(), compiler); if (contextClass != null) { currentSymbol.setLength(0); @@ -475,6 +464,9 @@ } } if (!accepted) { + if (log.isDebugEnabled()) { + log.debug("symbol " + symbol + " was not accepted."); + } return null; } } @@ -483,19 +475,17 @@ } private void trackMemberIfPossible(String objectCode, ClassDescriptor objectClass, String memberName, boolean method) { -// if (objectClass.isInterface()) { -// // might be technically possible to track in some cases, but for now -// // we can't create a DefaultObjectHandler for interfaces -// return; -// } + if (log.isDebugEnabled()) { + log.debug("for [objectCode:" + objectCode + ", objectClass:" + objectClass + ", memberName:" + memberName + ", isMethod:" + method); + } DefaultObjectHandler handler = TagManager.getTagHandler(objectClass); try { if (handler.isMemberBound(memberName)) { addListener(objectCode + "." + memberName + (method ? "()" : ""), objectCode, - handler.getAddMemberListenerCode(objectCode, id, memberName, listenerId, compiler), - handler.getRemoveMemberListenerCode(objectCode, id, memberName, listenerId, compiler)); + getAddMemberListenerCode(handler, objectCode, memberName, "this", compiler), + getRemoveMemberListenerCode(handler, objectCode, memberName, "this", compiler)); } } catch (UnsupportedAttributeException e) { // ignore -- this is thrown for methods like toString(), for which there is no tracking and @@ -505,29 +495,225 @@ private void addListener(String dependencySymbol, String objectCode, String addCode, String removeCode) { this.objectCode = objectCode; - //TC-20091026 no need to test objectCode not null if on root object -// boolean needTest = objectCode != null; boolean needTest = objectCode != null && !compiler.getRootObject().getId().equals(objectCode); + if (log.isDebugEnabled()) { + log.debug("try to add listener [dependencySymbol:" + dependencySymbol + ", objectCode:" + objectCode + ", addCode:" + addCode + "]"); + } if (!dependencySymbols.contains(dependencySymbol)) { + if (log.isDebugEnabled()) { + log.debug("add [dependencySymbol:" + dependencySymbol + ", objectCode:" + objectCode + "]"); + } dependencySymbols.add(dependencySymbol); String eol = JAXXCompiler.getLineSeparator(); - addListenerCode.append(eol); + if (dependencySymbols.size() > 1) { + addListenerCode.append(eol); + } if (needTest) { - addListenerCode.append(" if (").append(objectCode).append(" != null) {").append(eol); + addListenerCode.append("if (").append(objectCode).append(" != null) {").append(eol); } - addListenerCode.append(JavaFileGenerator.indent(addCode, needTest ? 8 : 4, false, eol)); + addListenerCode.append(JavaFileGenerator.indent(addCode, needTest ? 4 : 0, false, eol)); if (needTest) { - addListenerCode.append(eol).append(" }"); + addListenerCode.append(eol).append("}"); } - removeListenerCode.append(eol); + if (dependencySymbols.size() > 1) { + removeListenerCode.append(eol); + } if (needTest) { - removeListenerCode.append(" if (").append(objectCode).append(" != null) {").append(eol); + removeListenerCode.append("if (").append(objectCode).append(" != null) {").append(eol); } - removeListenerCode.append(JavaFileGenerator.indent(removeCode, needTest ? 8 : 4, false, eol)); + removeListenerCode.append(JavaFileGenerator.indent(removeCode, needTest ? 4 : 0, false, eol)); if (needTest) { - removeListenerCode.append(eol).append(" }"); + removeListenerCode.append(eol).append("}"); } } } -} + + public boolean hasMethod(String methodName) { + for (JavaMethod method : methods) { + if (methodName.equals(method.getName())) { + return true; + } + } + return false; + } + + /** + * Returns a snippet of Java code which will cause a <code>PropertyChangeListener</code> to be notified + * when the member's value changes. The <code>PropertyChangeListener</code> is provided in the form + * of a Java code snippet that evaluates to a listener object. + * <p/> + * For ordinary bound JavaBeans properties, the Java code returned is a simple call to + * <code>addPropertyChangeListener</code>. Fields and methods which do not actually fire + * <code>PropertyChangeEvents</code> when they change necessitate more complex code. + * + * @param handler Object handler (containts known events + * @param objectCode Java code which evaluates to the object to which to add the listener + * *@param dataBinding the name of the data binding this listener is a part of + * @param memberName the name of the field or method to listen to + * @param propertyChangeListenerCode Java code which evaluates to a <code>PropertyChangeListener</code> + * @param compiler the current <code>JAXXCompiler</code> + * @return Java code snippet which causes the listener to be added to the object + */ + public String getAddMemberListenerCode(DefaultObjectHandler handler, String objectCode, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { + if ("getClass".equals(memberName)) { + return null; + } + + DefaultObjectHandler.ProxyEventInfo eventInfo = handler.getEventInfo(memberName); +// DefaultObjectHandler.ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; + if (eventInfo != null) { + // a "proxied" event is one that doesn't fire PropertyChangeEvent, so we need to convert its native event type into PropertyChangeEvents + StringBuffer result = new StringBuffer(); + String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode.equals("this") ? constantId : propertyChangeListenerCode); +// String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); + boolean methodExists = hasMethod(methodName); +// boolean methodExists = compiler.hasMethod(methodName); + ClassDescriptor eventClass = DefaultObjectHandler.getEventClass(eventInfo.getListenerClass()); +// ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); + if (!methodExists) { + methods.add(new JavaMethod(Modifier.PUBLIC, "void", methodName, + new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, + "propertyChange(null);", false)); +// compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, +// new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, +// propertyChangeListenerCode + ".propertyChange(null);", false)); + } + String code = objectCode + (eventInfo.getModelName() != null ? ".get" + StringUtils.capitalize(eventInfo.getModelName()) + "()" : ""); +// String code = objectCode + (eventInfo.modelName != null ? ".get" + StringUtils.capitalize(eventInfo.modelName) + "()" : ""); + result.append("$bindingSources.put(\"").append(code).append("\", ").append(code).append(");").append(JAXXCompiler.getLineSeparator()); + //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name + result.append(code).append('.').append(eventInfo.getAddMethod()).append("( Util.getEventListener(").append(eventInfo.getListenerClass().getSimpleName()).append(".class, ").append("this").append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); +// result.append(code).append('.').append(eventInfo.getAddMethod()).append("( Util.getEventListener(").append(eventInfo.getListenerClass().getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); +// result.append(code).append('.').append(eventInfo.addMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); + result.append(JAXXCompiler.getLineSeparator()); +// if (eventInfo.modelName != null) { + if (eventInfo.getModelName() != null) { +// result.append(getAddMemberListenerCode(objectCode, dataBinding, "get" + StringUtils.capitalize(eventInfo.modelName), + result.append(getAddMemberListenerCode(handler, objectCode, "get" + StringUtils.capitalize(eventInfo.getModelName()), + Util.class.getSimpleName() + ".getDataBindingUpdateListener(" + (compiler.getOutputClassName() + ".this") + ", " + constantId + ")", +// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , " + dataBinding + ")", +// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , \"" + dataBinding + "\")", + compiler)); + } + return result.toString(); + } else { + String propertyName = null; + if (memberName.startsWith("get")) { + propertyName = Introspector.decapitalize(memberName.substring("get".length())); + } else if (memberName.startsWith("is")) { + propertyName = Introspector.decapitalize(memberName.substring("is".length())); + } else { + try { + handler.getBeanClass().getFieldDescriptor(memberName); +// getBeanClass().getFieldDescriptor(memberName); + propertyName = memberName; + } catch (NoSuchFieldException e) { + // ignore ? + } + } + if (propertyName != null) { + //TC-20091026 when on root object, do not prefix with objectCode + String prefix = objectCode.trim() + "."; + if (objectCode.equals(compiler.getRootObject().getJavaCode())) { + prefix = ""; + } + try { + // check for property-specific addPropertyChangeListener method +// getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), + handler.getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), + ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); + return prefix + "addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; + } catch (NoSuchMethodException e) { + // no property-specific method, use general one + return prefix + "addPropertyChangeListener(" + propertyChangeListenerCode + ");\n"; + } + } + return null; + } + } + + public String getRemoveMemberListenerCode(DefaultObjectHandler handler, String objectCode, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { + if ("getClass".equals(memberName)) { + return null; + } + + DefaultObjectHandler.ProxyEventInfo eventInfo = handler.getEventInfo(memberName); +// ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; + if (eventInfo != null) { + // a "proxied" event is one that doesn't fire PropertyChangeEvent, + // so we need to convert its native event type into PropertyChangeEvents + StringBuffer result = new StringBuffer(); + String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode.equals("this") ? constantId : propertyChangeListenerCode); + boolean methodExists = hasMethod(methodName); +// boolean methodExists = compiler.hasMethod(methodName); + if (!methodExists) { + ClassDescriptor eventClass = DefaultObjectHandler.getEventClass(eventInfo.getListenerClass()); +// ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); + methods.add(new JavaMethod(Modifier.PUBLIC, "void", methodName, + new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, + "propertyChange(null);", false)); +// compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, +// new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, +// propertyChangeListenerCode + ".propertyChange(null);", false)); + } + try { + String modelMemberName = eventInfo.getModelName() != null ? "get" + StringUtils.capitalize(eventInfo.getModelName()) : null; + String modelClassName = modelMemberName != null ? handler.getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(handler.getBeanClass()); + String code = objectCode + (eventInfo.getModelName() != null ? "." + modelMemberName + "()" : ""); +// String modelMemberName = eventInfo.modelName != null ? "get" + StringUtils.capitalize(eventInfo.modelName) : null; +// String modelClassName = modelMemberName != null ? getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(getBeanClass()); +// String code = objectCode + (eventInfo.modelName != null ? "." + modelMemberName + "()" : ""); + String eol = JAXXCompiler.getLineSeparator(); + result.append(modelClassName).append(" $target = ((").append(modelClassName).append(") $bindingSources.remove(\"").append(code).append("\"));").append(eol); + //TC-20091105 test if $target is not null + result.append("if ($target != null) {").append(eol); + //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name + result.append(" $target.").append(eventInfo.getRemoveMethod()).append("( Util.getEventListener(").append(eventInfo.getListenerClass().getSimpleName()).append(".class, ").append("this").append(", ").append(TypeManager.getJavaCode(methodName)).append("));").append(eol); +// result.append(" $target.").append(eventInfo.removeMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));").append(eol); + result.append("}").append(eol); + if (eventInfo.getModelName() != null) { + result.append(getRemoveMemberListenerCode(handler, objectCode, "get" + StringUtils.capitalize(eventInfo.getModelName()), + Util.class.getSimpleName() + ".getDataBindingUpdateListener(" + compiler.getOutputClassName() + ".this, " + constantId + ")", +// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this, \"" + dataBinding + "\")", + compiler)); + } + return result.toString(); + } catch (NoSuchMethodException e) { + throw new CompilerException("Internal error: " + e); + } + } else { + String propertyName = null; + if (memberName.startsWith("get")) { + propertyName = Introspector.decapitalize(memberName.substring("get".length())); + } else if (memberName.startsWith("is")) { + propertyName = Introspector.decapitalize(memberName.substring("is".length())); + } else { + try { + handler.getBeanClass().getFieldDescriptor(memberName); +// getBeanClass().getFieldDescriptor(memberName); + propertyName = memberName; + } catch (NoSuchFieldException e) { + // ignore ? + } + } + if (propertyName != null) { + //TC-20091026 when on root object, do not prefix with objectCode + String prefix = objectCode.trim() + "."; + if (objectCode.equals(compiler.getRootObject().getJavaCode())) { + prefix = ""; + } + try { + // check for property-specific removePropertyChangeListener method + handler.getBeanClass().getMethodDescriptor("removePropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), + ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); + return prefix + "removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; + } catch (NoSuchMethodException e) { + // no property-specific method, use general one + return prefix + "removePropertyChangeListener(" + propertyChangeListenerCode + ");\n"; + } + } + return null; + } + } +} \ No newline at end of file Added: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/PseudoClassDataBinding.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/PseudoClassDataBinding.java (rev 0) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/PseudoClassDataBinding.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -0,0 +1,123 @@ +/* + * *##% + * JAXX Compiler + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * ##%* + */ +package jaxx.compiler.binding; + +import jaxx.compiler.CompiledObject; +import jaxx.compiler.CompilerException; +import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.java.JavaFileGenerator; +import jaxx.compiler.java.parser.JavaParser; +import jaxx.compiler.java.parser.JavaParserTreeConstants; +import jaxx.compiler.java.parser.SimpleNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.StringReader; + +/** + * Represents a data binding in a JAXX file. <code>DataBinding</code> uses + * {@link jaxx.compiler.binding.DataSource} to track changes to a source expression and update + * the destination. + */ +public class PseudoClassDataBinding extends DataBinding { + + /** + * Logger + */ + protected static final Log log = LogFactory.getLog(PseudoClassDataBinding.class); + + protected final boolean invert; + + public static PseudoClassDataBinding newPseudoClassDataBinding(String pseudoClass, CompiledObject object, String propertyCode, String methodName, boolean invertTest) { + PseudoClassDataBinding binding = null; + if (pseudoClass.startsWith("{")) { + pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); + pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); + String id = object.getId() + ".style." + pseudoClass + "." + methodName; + binding = new PseudoClassDataBinding(id, pseudoClass, propertyCode, invertTest); + } + return binding; + } + + protected PseudoClassDataBinding(String id, String source, String assignment, boolean invert) { + super(id, source, assignment, false); + this.invert = invert; + } + + /** + * Replaces all references to the variable "object" with the actual object ID. + * + * @param code ? + * @param id ? + * @return ? + * @throws jaxx.compiler.CompilerException + * ? + */ + public static String replaceObjectReferences(String code, String id) throws CompilerException { + JavaParser p = new JavaParser(new StringReader(code + ";")); + p.Expression(); + jaxx.compiler.java.parser.SimpleNode node = p.popNode(); + scanNode(node, id); + return node.getText(); + } + + public static void scanNode(SimpleNode node, String id) { + if (node.getId() == JavaParserTreeConstants.JJTNAME) { + String name = node.getText(); + if (name.equals("object") || (name.indexOf(".") != -1 && name.substring(0, name.indexOf(".")).trim().equals("object"))) { + node.firstToken.image = id; + } + } else { + int count = node.jjtGetNumChildren(); + for (int i = 0; i < count; i++) { + scanNode(node.getChild(i), id); + } + } + } + + @Override + protected String getInitDataBindingCode(JAXXCompiler compiler, DataSource dataSource, boolean isBinding) { + // nothing to init + return null; + } + + @Override + protected String getProcessDataBindingCode(JAXXCompiler compiler, DataSource dataSource, boolean isBinding) { + if (!isBinding) { + return null; + } + + String eol = JAXXCompiler.getLineSeparator(); + + StringBuilder buffer = new StringBuilder(); + + String realSource = invert ? invert(getSource()) : getSource(); + buffer.append("if (").append(realSource).append(") {").append(eol); + buffer.append(JavaFileGenerator.indent(getAssignment(), 4, false, eol)).append(eol); + buffer.append("}"); + return buffer.toString(); + } + + protected String invert(String javaCode) { + javaCode = javaCode.trim(); + return javaCode.startsWith("!") ? javaCode.substring(1) : "!(" + javaCode + ")"; + } +} \ No newline at end of file Property changes on: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/binding/PseudoClassDataBinding.java ___________________________________________________________________ Added: svn:keywords + "Author Date Id Revision HeadURL Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/css/StylesheetHelper.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/css/StylesheetHelper.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/css/StylesheetHelper.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -20,29 +20,25 @@ */ package jaxx.compiler.css; -import jaxx.compiler.binding.DataSource; +import jaxx.compiler.CompiledObject; +import jaxx.compiler.CompilerException; +import jaxx.compiler.JAXXCompiler; import jaxx.compiler.binding.DataBinding; -import jaxx.compiler.*; -import jaxx.runtime.css.Selector; -import jaxx.runtime.css.Rule; -import jaxx.runtime.css.Stylesheet; -import jaxx.compiler.java.parser.JavaParser; -import jaxx.compiler.java.parser.JavaParserTreeConstants; -import jaxx.compiler.java.parser.SimpleNode; +import jaxx.compiler.binding.DataBindingHelper; +import jaxx.compiler.binding.PseudoClassDataBinding; import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.reflect.MethodDescriptor; import jaxx.compiler.tags.DefaultObjectHandler; import jaxx.compiler.tags.TagManager; +import jaxx.compiler.types.TypeManager; +import jaxx.runtime.css.Rule; +import jaxx.runtime.css.Selector; +import jaxx.runtime.css.Stylesheet; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * A helper class to compute {@link Stylesheet}, {@link Rule} and {@link Selector} @@ -54,6 +50,96 @@ */ public class StylesheetHelper { + public enum MouseEventEnum { + + mouseover("mouseEntered", "mouseExited"), + mouseout("mouseExited", "mouseReleased"), + mousedown("mousePressed", "mousePressed"), + mouseup("mouseReleased", "mousePressed"); + + final String addMethod; + final String removeMethod; + +// ClassDescriptor mouseListenerDescriptor; +// ClassDescriptor mouseEventDescriptor; + + MouseEventEnum(String addMethod, String removeMethod) { + this.removeMethod = removeMethod; + this.addMethod = addMethod; + } + + public String getProperty(int i) { + return i == 0 ? addMethod : removeMethod; + } + +// public ClassDescriptor getMouseEventDescriptor() { +// if (mouseEventDescriptor == null) { +// mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); +// } +// return mouseEventDescriptor; +// } +// +// public ClassDescriptor getMouseListenerDescriptor() { +// if (mouseListenerDescriptor == null) { +// mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); +// } +// return mouseListenerDescriptor; +// } +// +// public MethodDescriptor getAddMouseListenerMethod(CompiledObject object) { +// try { +// MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", getMouseListenerDescriptor()); +// return addMouseListener; +// } catch (NoSuchMethodException e) { +// throw new CompilerException("could not find addMouseListener for object " + object); +// } +// } +// +// public MethodDescriptor getMouseListenerMethod(CompiledObject object, String property) { +// try { +// MethodDescriptor methodDescriptor = getMouseListenerDescriptor().getMethodDescriptor(property, getMouseEventDescriptor()); +// return methodDescriptor; +// } catch (NoSuchMethodException e) { +// throw new CompilerException("could not find " + property + " for object " + object); +// } +// } + } + + static ClassDescriptor mouseListenerDescriptor; + static ClassDescriptor mouseEventDescriptor; + + public static ClassDescriptor getMouseEventDescriptor() { + if (mouseEventDescriptor == null) { + mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); + } + return mouseEventDescriptor; + } + + public static ClassDescriptor getMouseListenerDescriptor() { + if (mouseListenerDescriptor == null) { + mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); + } + return mouseListenerDescriptor; + } + + public static MethodDescriptor getAddMouseListenerMethod(CompiledObject object) { + try { + MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", getMouseListenerDescriptor()); + return addMouseListener; + } catch (NoSuchMethodException e) { + throw new CompilerException("could not find addMouseListener for object " + object); + } + } + + public static MethodDescriptor getMouseListenerMethod(CompiledObject object, String property) { + try { + MethodDescriptor methodDescriptor = getMouseListenerDescriptor().getMethodDescriptor(property, getMouseEventDescriptor()); + return methodDescriptor; + } catch (NoSuchMethodException e) { + throw new CompilerException("could not find " + property + " for object " + object); + } + } + public static void applyTo(CompiledObject object, JAXXCompiler compiler, Stylesheet stylesheet, Stylesheet overrides) throws CompilerException { Map<String, String> overriddenProperties; if (overrides != null) { @@ -105,158 +191,185 @@ } } - /** - * Replaces all references to the variable "object" with the actual object ID. - * - * @param code ? - * @param id ? - * @return ? - * @throws CompilerException ? - */ - public static String replaceObjectReferences(String code, String id) throws CompilerException { - JavaParser p = new JavaParser(new StringReader(code + ";")); - p.Expression(); - jaxx.compiler.java.parser.SimpleNode node = p.popNode(); - scanNode(node, id); - return node.getText(); - } +// /** +// * Replaces all references to the variable "object" with the actual object ID. +// * +// * @param code ? +// * @param id ? +// * @return ? +// * @throws CompilerException ? +// */ +// public static String replaceObjectReferences(String code, String id) throws CompilerException { +// JavaParser p = new JavaParser(new StringReader(code + ";")); +// p.Expression(); +// jaxx.compiler.java.parser.SimpleNode node = p.popNode(); +// scanNode(node, id); +// return node.getText(); +// } +// +// public static void scanNode(SimpleNode node, String id) { +// if (node.getId() == JavaParserTreeConstants.JJTNAME) { +// String name = node.getText(); +// if (name.equals("object") || (name.indexOf(".") != -1 && name.substring(0, name.indexOf(".")).trim().equals("object"))) { +// node.firstToken.image = id; +// } +// } else { +// int count = node.jjtGetNumChildren(); +// for (int i = 0; i < count; i++) { +// scanNode(node.getChild(i), id); +// } +// } +// } - public static void scanNode(SimpleNode node, String id) { - if (node.getId() == JavaParserTreeConstants.JJTNAME) { - String name = node.getText(); - if (name.equals("object") || (name.indexOf(".") != -1 && name.substring(0, name.indexOf(".")).trim().equals("object"))) { - node.firstToken.image = id; - } - } else { - int count = node.jjtGetNumChildren(); - for (int i = 0; i < count; i++) { - scanNode(node.getChild(i), id); - } - } - } +// public static void compilePseudoClassAdd(String pseudoClass, CompiledObject object, String propertyCode, JAXXCompiler compiler) throws CompilerException { +// +// if (pseudoClass.startsWith("{")) { +// pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); +// pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); +// String dest = object.getId() + ".style." + pseudoClass + ".add"; +// String destCode = TypeManager.getJavaCode(dest); +// DataBindingHelper bindingHelper = compiler.getBindingHelper(); +// if (bindingHelper.hasProcessDataBinding()) { +// bindingHelper.appendProcessDataBinding("else "); +// } +// bindingHelper.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + pseudoClass + ") { " + propertyCode + "} }"); +// new DataSource(dest, pseudoClass, compiler).compile("new DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); +// bindingHelper.appendInitDataBindings("applyDataBinding(" + destCode + ");"); +// return; +// } +// +// MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); +// +// String property = null; +// switch (constant) { +// case mousedown: +// property = "mousePressed"; +// break; +// case mouseout: +// property = "mouseExited"; +// break; +// case mouseover: +// property = "mouseEntered"; +// break; +// case mouseup: +// property = "mouseReleased"; +// break; +// } +// +// ClassDescriptor mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); +// ClassDescriptor mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); +// +// try { +// MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", mouseListenerDescriptor); +// MethodDescriptor methodDescriptor = mouseListenerDescriptor.getMethodDescriptor(property, mouseEventDescriptor); +// object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, methodDescriptor, propertyCode, compiler); +// +// } catch (NoSuchMethodException e) { +// compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); +// } +// } - public static void compilePseudoClassAdd(String pseudoClass, CompiledObject object, String propertyCode, JAXXCompiler compiler) throws CompilerException { +// public static void compilePseudoClassRemove(String pseudoClass, CompiledObject object, String propertyCode, JAXXCompiler compiler) throws CompilerException { +// if (pseudoClass.startsWith("{")) { +// pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); +// pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); +// String dest = object.getId() + ".style." + pseudoClass + ".remove"; +// String destCode = TypeManager.getJavaCode(dest); +// DataBindingHelper bindingHelper = compiler.getBindingHelper(); +// if (bindingHelper.hasProcessDataBinding()) { +// bindingHelper.appendProcessDataBinding("else "); +// } +// bindingHelper.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + invert(pseudoClass) + ") { " + propertyCode + "} }"); +// new DataSource(dest, pseudoClass, compiler).compile("new DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); +// bindingHelper.appendInitDataBindings("applyDataBinding(" + destCode + ");"); +// return; +// } +// +// MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); +// +// String property = null; +// switch (constant) { +// case mousedown: +// property = "mousePressed"; +// break; +// case mouseout: +// property = "mouseReleased"; +// break; +// case mouseover: +// property = "mouseExited"; +// break; +// case mouseup: +// property = "mousePressed"; +// break; +// } +// +// ClassDescriptor mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); +// ClassDescriptor mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); +// +// try { +// MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", mouseListenerDescriptor); +// MethodDescriptor methodDescriptor = mouseListenerDescriptor.getMethodDescriptor(property, mouseEventDescriptor); +// object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, methodDescriptor, propertyCode, compiler); +// +// } catch (NoSuchMethodException e) { +// compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); +// } +// } +// +// public static String invert(String javaCode) { +// javaCode = javaCode.trim(); +// return javaCode.startsWith("!") ? javaCode.substring(1) : "!(" + javaCode + ")"; +// } - if (pseudoClass.startsWith("{")) { - pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); - pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); - String dest = object.getId() + ".style." + pseudoClass + ".add"; - String destCode = compiler.getJavaCode(dest); - if (compiler.hasProcessDataBinding()) { - compiler.appendProcessDataBinding("else "); - } - compiler.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + pseudoClass + ") { " + propertyCode + "} }"); - new DataSource(dest, pseudoClass, compiler).compile("new DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); - compiler.appendInitDataBindings("applyDataBinding(" + destCode + ");"); - return; - } - - MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); - - String property = null; - switch (constant) { - case mousedown: - property = "mousePressed"; - break; - case mouseout: - property = "mouseExited"; - break; - case mouseover: - property = "mouseEntered"; - break; - case mouseup: - property = "mouseReleased"; - break; - } - - ClassDescriptor mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); - ClassDescriptor mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); - - try { - MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", mouseListenerDescriptor); - MethodDescriptor methodDescriptor = mouseListenerDescriptor.getMethodDescriptor(property, mouseEventDescriptor); - object.addEventHandler("style." + pseudoClass + ".add", addMouseListener, methodDescriptor, propertyCode, compiler); - - } catch (NoSuchMethodException e) { - compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); - } - } - - public static void compilePseudoClassRemove(String pseudoClass, CompiledObject object, String propertyCode, JAXXCompiler compiler) throws CompilerException { - if (pseudoClass.startsWith("{")) { - pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); - pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); - String dest = object.getId() + ".style." + pseudoClass + ".remove"; - String destCode = compiler.getJavaCode(dest); - if (compiler.hasProcessDataBinding()) { - compiler.appendProcessDataBinding("else "); - } - compiler.appendProcessDataBinding("if ($dest.equals(" + destCode + ")) { if (" + invert(pseudoClass) + ") { " + propertyCode + "} }"); - new DataSource(dest, pseudoClass, compiler).compile("new DataBindingListener(" + compiler.getRootObject().getJavaCode() + ", " + destCode + ")"); - compiler.appendInitDataBindings("applyDataBinding(" + destCode + ");"); - return; - } - - MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); - - String property = null; - switch (constant) { - case mousedown: - property = "mousePressed"; - break; - case mouseout: - property = "mouseReleased"; - break; - case mouseover: - property = "mouseExited"; - break; - case mouseup: - property = "mousePressed"; - break; - } - - ClassDescriptor mouseListenerDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseListener.class); - ClassDescriptor mouseEventDescriptor = ClassDescriptorLoader.getClassDescriptor(MouseEvent.class); - - try { - MethodDescriptor addMouseListener = object.getObjectClass().getMethodDescriptor("addMouseListener", mouseListenerDescriptor); - MethodDescriptor methodDescriptor = mouseListenerDescriptor.getMethodDescriptor(property, mouseEventDescriptor); - object.addEventHandler("style." + pseudoClass + ".remove", addMouseListener, methodDescriptor, propertyCode, compiler); - - } catch (NoSuchMethodException e) { - compiler.reportError("mouseover pseudoclass cannot be applied to object " + object.getObjectClass().getName() + " (no addMouseListener method)"); - } - } - - public static String invert(String javaCode) { - javaCode = javaCode.trim(); - return javaCode.startsWith("!") ? javaCode.substring(1) : "!(" + javaCode + ")"; - } - public static String unwrap(ClassDescriptor type, String valueCode) { if (type == ClassDescriptorLoader.getClassDescriptor(boolean.class)) { return "((java.lang.Boolean) " + valueCode + ").booleanValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(byte.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(byte.class)) { return "((java.lang.Byte) " + valueCode + ").byteValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(short.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(short.class)) { return "((java.lang.Short) " + valueCode + ").shortValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(int.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(int.class)) { return "((java.lang.Integer) " + valueCode + ").intValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(long.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(long.class)) { return "((java.lang.Long) " + valueCode + ").longValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(float.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(float.class)) { return "((java.lang.Float) " + valueCode + ").floatValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(double.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(double.class)) { return "((java.lang.Double) " + valueCode + ").doubleValue()"; - } else if (type == ClassDescriptorLoader.getClassDescriptor(char.class)) { + } + if (type == ClassDescriptorLoader.getClassDescriptor(char.class)) { return "((java.lang.Character) " + valueCode + ").charValue()"; - } else { - return valueCode; } + return valueCode; } + public enum PseudoClassEnum { + focused("{ object.hasFocus() }"), + unfocused("{ !object.hasFocus() }"), + enabled("{ object.isEnabled() }"), + disabled("{ !object.isEnabled() }"), + selected("{ object.isSelected() }"), + deselected("{ !object.isSelected() }"); + + final String code; + + PseudoClassEnum(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + } + public static void applyPseudoClass(String pseudoClass, Map<String, String> properties, - CompiledObject object, JAXXCompiler compiler, int priority) throws CompilerException { + CompiledObject object, JAXXCompiler compiler, int priority) throws CompilerException { if (pseudoClass.indexOf("[") != -1) { pseudoClass = pseudoClass.substring(0, pseudoClass.indexOf("[")); } @@ -265,19 +378,25 @@ DefaultObjectHandler handler = TagManager.getTagHandler(object.getObjectClass()); boolean valueDeclared = false; String eol = JAXXCompiler.getLineSeparator(); + DataBindingHelper bindingHelper = compiler.getBindingHelper(); for (Map.Entry<String, String> e : properties.entrySet()) { String property = e.getKey(); ClassDescriptor type = handler.getPropertyType(object, property, compiler); - String dataBinding = compiler.processDataBindings(e.getValue()); + String dataBindingCode = DataBindingHelper.processDataBindings(e.getValue()); String valueCode; - if (dataBinding != null) { - valueCode = "new jaxx.runtime.css.DataBinding(" + compiler.getJavaCode(object.getId() + "." + property + "." + priority) + ")"; - DataBinding dataBinding1 = new DataBinding(dataBinding, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBinding, compiler)); - dataBinding1.compile(compiler, false); + if (dataBindingCode != null) { + valueCode = "new jaxx.runtime.css.DataBinding(" + TypeManager.getJavaCode(object.getId() + "." + property + "." + priority) + ")"; + DataBinding binding = new DataBinding(object.getId() + "." + property + "." + priority, dataBindingCode, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode, compiler), false); + bindingHelper.registerDataBinding(binding); +// DataBinding binding = new DataBinding(dataBindingCode, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode, compiler), false); +// DataBinding dataBinding1 = new DataBinding(dataBinding, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBinding, compiler)); +// DataBinding dataBinding1 = new DataBinding(dataBinding, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBinding, compiler)); +// binding.compile(compiler); +// dataBinding1.compile(compiler, false); } else { try { Class<?> typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; - valueCode = compiler.getJavaCode(compiler.convertFromString(e.getValue(), typeClass)); + valueCode = TypeManager.getJavaCode(TypeManager.convertFromString(e.getValue(), typeClass)); } catch (ClassNotFoundException ex) { compiler.reportError("could not find class " + type.getName()); return; @@ -287,45 +406,58 @@ buffer.append("java.lang.Object "); valueDeclared = true; } - buffer.append("value = jaxx.runtime.css.Pseudoclasses.applyProperty(").append(compiler.getOutputClassName()).append(".this, ").append(object.getJavaCode()).append(", ").append(compiler.getJavaCode(property)).append(", ").append(valueCode).append(", jaxx.runtime.css.Pseudoclasses.wrap(").append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler)).append("), ").append(priority).append(");").append(eol); + buffer.append("value = jaxx.runtime.css.Pseudoclasses.applyProperty(").append(compiler.getOutputClassName()).append(".this, ").append(object.getJavaCode()).append(", ").append(TypeManager.getJavaCode(property)).append(", ").append(valueCode).append(", jaxx.runtime.css.Pseudoclasses.wrap(").append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler)).append("), ").append(priority).append(");").append(eol); buffer.append("if (!(value instanceof jaxx.runtime.css.DataBinding)) {").append(eol); String unwrappedValue = unwrap(type, "value"); - buffer.append(" ").append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + - ") " + unwrappedValue, compiler)).append(eol); + buffer.append(" ").append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + unwrappedValue, compiler)).append(eol); buffer.append("}").append(eol); } - if (pseudoClass.equals("focused")) { - pseudoClass = "{ object.hasFocus() }"; - } else if (pseudoClass.equals("unfocused")) { - pseudoClass = "{ !object.hasFocus() }"; - } else if (pseudoClass.equals("enabled")) { - pseudoClass = "{ object.isEnabled() }"; - } else if (pseudoClass.equals("disabled")) { - pseudoClass = "{ !object.isEnabled() }"; - } else if (pseudoClass.equals("selected")) { - pseudoClass = "{ object.isSelected() }"; - } else if (pseudoClass.equals("deselected")) { - pseudoClass = "{ !object.isSelected() }"; + try { + PseudoClassEnum classEnum = PseudoClassEnum.valueOf(pseudoClass); + pseudoClass = classEnum.getCode(); + } catch (IllegalArgumentException e) { + // should never happens ? +// throw new RuntimeException("could not find " + PseudoClassEnum.class + " with pseudoClass " + pseudoClass, e); } - compilePseudoClassAdd(pseudoClass, object, buffer.toString(), compiler); +// if (pseudoClass.equals("focused")) { +// pseudoClass = "{ object.hasFocus() }"; +// } else if (pseudoClass.equals("unfocused")) { +// pseudoClass = "{ !object.hasFocus() }"; +// } else if (pseudoClass.equals("enabled")) { +// pseudoClass = "{ object.isEnabled() }"; +// } else if (pseudoClass.equals("disabled")) { +// pseudoClass = "{ !object.isEnabled() }"; +// } else if (pseudoClass.equals("selected")) { +// pseudoClass = "{ object.isSelected() }"; +// } else if (pseudoClass.equals("deselected")) { +// pseudoClass = "{ !object.isSelected() }"; +// } +// compilePseudoClassAdd(pseudoClass, object, buffer.toString(), compiler); + compilePseudoClass(pseudoClass, object, buffer.toString(), 0, "add", compiler, false); + buffer.setLength(0); valueDeclared = false; for (Map.Entry<String, String> e : properties.entrySet()) { String property = e.getKey(); ClassDescriptor type = handler.getPropertyType(object, property, compiler); - String dataBinding = compiler.processDataBindings(e.getValue()); + String dataBindingCode = DataBindingHelper.processDataBindings(e.getValue()); String valueCode; - if (dataBinding != null) { - valueCode = "new jaxx.runtime.css.DataBinding(" + compiler.getJavaCode(object.getId() + "." + property + "." + priority) + ")"; - DataBinding dataBinding1 = new DataBinding(dataBinding, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBinding, compiler)); - dataBinding1.compile(compiler, false); + if (dataBindingCode != null) { + valueCode = "new jaxx.runtime.css.DataBinding(" + TypeManager.getJavaCode(object.getId() + "." + property + "." + priority) + ")"; + DataBinding binding = new DataBinding(object.getId() + "." + property + "." + priority, dataBindingCode, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode, compiler), false); +// DataBinding binding = new DataBinding(dataBindingCode, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode, compiler), false); +// DataBinding binding = new DataBinding(dataBindingCode, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode, compiler)); +// DataBinding binding = new DataBinding(dataBindingCode, object.getId() + "." + property + "." + priority, handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode, compiler)); + bindingHelper.registerDataBinding(binding); +// binding.compile(compiler); +// binding.compile(compiler, false); } else { try { Class<?> typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; - valueCode = compiler.getJavaCode(compiler.convertFromString(e.getValue(), typeClass)); + valueCode = TypeManager.getJavaCode(TypeManager.convertFromString(e.getValue(), typeClass)); } catch (ClassNotFoundException ex) { compiler.reportError("could not find class " + type.getName()); return; @@ -335,16 +467,39 @@ buffer.append("java.lang.Object "); valueDeclared = true; } - buffer.append("value = jaxx.runtime.css.Pseudoclasses.removeProperty(").append(compiler.getOutputClassName()).append(".this, ").append(object.getJavaCode()).append(", ").append(compiler.getJavaCode(property)).append(", ").append(valueCode).append(", jaxx.runtime.css.Pseudoclasses.wrap(").append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler)).append("), ").append(priority).append(");").append(eol); + buffer.append("value = jaxx.runtime.css.Pseudoclasses.removeProperty(").append(compiler.getOutputClassName()).append(".this, ").append(object.getJavaCode()).append(", ").append(TypeManager.getJavaCode(property)).append(", ").append(valueCode).append(", jaxx.runtime.css.Pseudoclasses.wrap(").append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler)).append("), ").append(priority).append(");").append(eol); buffer.append("if (!(value instanceof jaxx.runtime.css.DataBinding)) {").append(eol); String unwrappedValue = unwrap(type, "value"); - buffer.append(" ").append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + - ") " + unwrappedValue, compiler)).append(eol); + buffer.append(" ").append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + JAXXCompiler.getCanonicalName(type) + ") " + unwrappedValue, compiler)).append(eol); buffer.append("}").append(eol); } - compilePseudoClassRemove(pseudoClass, object, buffer.toString(), compiler); +// compilePseudoClassRemove(pseudoClass, object, buffer.toString(), compiler); + compilePseudoClass(pseudoClass, object, buffer.toString(), 1, "remove", compiler, true); } + + public static void compilePseudoClass(String pseudoClass, CompiledObject object, String propertyCode, int pos, String methodName, JAXXCompiler compiler, boolean invertTest) throws CompilerException { + PseudoClassDataBinding binding = PseudoClassDataBinding.newPseudoClassDataBinding(pseudoClass, object, propertyCode, methodName, invertTest); + if (binding != null) { + compiler.getBindingHelper().registerDataBinding(binding); + return; + } +// if (pseudoClass.startsWith("{")) { +// pseudoClass = pseudoClass.substring(1, pseudoClass.length() - 1).trim(); +// pseudoClass = replaceObjectReferences(pseudoClass, object.getJavaCode()); +// String id = object.getId() + ".style." + pseudoClass + "." + methodName; +// PseudoClassDataBinding binding = new PseudoClassDataBinding(id, pseudoClass, propertyCode, invertTest); +// compiler.getBindingHelper().registerDataBinding(binding); +//// binding.compile(compiler); +// return; +// } + MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass); + String property = constant.getProperty(pos); + MethodDescriptor addMouseListener = getAddMouseListenerMethod(object); + MethodDescriptor methodDescriptor = getMouseListenerMethod(object, property); + object.addEventHandler("style." + pseudoClass + "." + methodName, addMouseListener, methodDescriptor, propertyCode, compiler); + } + public static Map<String, String> getApplicableProperties(Stylesheet s, CompiledObject object) throws CompilerException { DefaultObjectHandler handler = TagManager.getTagHandler(object.getObjectClass()); Map<String, String> result = null; @@ -437,11 +592,4 @@ return Selector.NEVER_APPLIES; } - public enum MouseEventEnum { - - mouseover, - mouseout, - mousedown, - mouseup - } } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/decorators/DefaultCompiledObjectDecorator.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -27,6 +27,7 @@ import jaxx.compiler.java.JavaFile; import jaxx.compiler.java.JavaFileGenerator; import jaxx.compiler.script.ScriptInitializer; +import jaxx.compiler.types.TypeManager; import java.lang.reflect.Modifier; import java.util.Map.Entry; @@ -94,7 +95,7 @@ init += ")"; } result.append(eol); - result.append("$objectMap.put(").append(compiler.getJavaCode(object.getId())).append(", ").append(init).append(");"); + result.append("$objectMap.put(").append(TypeManager.getJavaCode(object.getId())).append(", ").append(init).append(");"); } result.append(eol); String initCode = object.getInitializationCode(compiler); @@ -109,7 +110,8 @@ } @Override - public String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings) { + public String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile) { +// public String createCompleteSetupMethod(JAXXCompiler compiler, CompiledObject object, JavaFile javaFile, StringBuffer initDataBindings) { StringBuffer code = new StringBuffer(); String eol = JAXXCompiler.getLineSeparator(); //TC-20091025 generate client properties at creation time (not at setup time) Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/finalizers/DefaultFinalizer.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -22,20 +22,20 @@ import jaxx.compiler.*; import jaxx.compiler.binding.DataBinding; -import jaxx.compiler.java.JavaArgument; -import jaxx.compiler.java.JavaField; -import jaxx.compiler.java.JavaFile; +import jaxx.compiler.java.*; import static jaxx.compiler.java.JavaFileGenerator.newField; import static jaxx.compiler.java.JavaFileGenerator.newMethod; -import jaxx.compiler.java.JavaMethod; import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.reflect.FieldDescriptor; import jaxx.compiler.reflect.MethodDescriptor; +import jaxx.compiler.types.TypeManager; import jaxx.runtime.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.io.IOException; import static java.lang.reflect.Modifier.*; import java.util.Iterator; @@ -70,12 +70,12 @@ * */ protected static final JavaField BINDING_SOURCES_FIELD = newField(PROTECTED, - "java.util.Map<String,Object>", "$bindingSources", false, "new HashMap<String,Object>()"); + "Map<String, Object>", "$bindingSources", false, "new HashMap<String, Object>()"); /** * */ protected static final JavaField OBJECT_MAP_FIELD = newField(PROTECTED, - "Map<String,Object>", "$objectMap", true, "new HashMap<String,Object>()"); + "Map<String, Object>", "$objectMap", true, "new HashMap<String, Object>()"); /** * */ @@ -90,12 +90,17 @@ * */ protected static final JavaField PREVIOUS_VALUES_FIELD = newField(PROTECTED, - "java.util.Map<?,?>", "$previousValues", false, "new java.util.HashMap<Object,Object>()"); + "Map<?,?>", "$previousValues", false, "new java.util.HashMap<Object, Object>()"); /** * */ + protected static final JavaField BINDINGS_FIELD = newField(PRIVATE | FINAL, + "Map<String, JAXXBinding>", "$bindings", false, "new java.util.TreeMap<String, JAXXBinding>()"); + /** + * + */ protected static final JavaField PROPERTY_CHANGE_SUPPORT_FIELD = newField(0, - "java.beans.PropertyChangeSupport", "$propertyChangeSupport", false); + "PropertyChangeSupport", "$propertyChangeSupport", false); /** * */ @@ -136,31 +141,36 @@ * */ protected static final JavaMethod GET_PARENT_CONTAINER_MORE_METHOD = newMethod(PUBLIC, "<O extends Container> O", "getParentContainer", - "return Util.getParentContainer(source, clazz);", true, + "return SwingUtil.getParentContainer(source, clazz);", true, new JavaArgument("Object", "source"), new JavaArgument("Class<O>", "clazz")); /** * */ protected static final JavaMethod GET_PARENT_CONTAINER_METHOD = newMethod(PUBLIC, "<O extends Container> O", "getParentContainer", - "return Util.getParentContainer(this, clazz);", true, + "return SwingUtil.getParentContainer(this, clazz);", true, new JavaArgument("Class<O>", "clazz")); /** * */ - protected static final JavaMethod GET_OBJECT_BY_ID_METHOD = newMethod(PUBLIC, "java.lang.Object", "getObjectById", + protected static final JavaMethod GET_OBJECT_BY_ID_METHOD = newMethod(PUBLIC, "Object", "getObjectById", "return $objectMap.get(id);", true, new JavaArgument("String", "id")); /** * */ - protected static final JavaMethod GET_JAXX_OBJECT_DESCRIPTOR_METHOD = newMethod(PUBLIC | STATIC, "jaxx.runtime.JAXXObjectDescriptor", "$getJAXXObjectDescriptor", - "return jaxx.runtime.Util.decodeCompressedJAXXObjectDescriptor($jaxxObjectDescriptor);", false); + protected static final JavaMethod GET_JAXX_OBJECT_DESCRIPTOR_METHOD = newMethod(PUBLIC | STATIC, "JAXXObjectDescriptor", "$getJAXXObjectDescriptor", + "return Util.decodeCompressedJAXXObjectDescriptor($jaxxObjectDescriptor);", false); /** * */ protected static final JavaMethod PROCESS_DATA_BINDING_METHOD = newMethod(PUBLIC, "void", "processDataBinding", - "processDataBinding(dest, false);", true, - new JavaArgument("String", "dest")); + "processDataBinding(binding, false);", true, + new JavaArgument("String", "binding")); + + protected static final JavaMethod REGISTER_DATA_BINDING_METHOD = newMethod(PRIVATE, "void", "registerDataBinding", + "$bindings.put(binding.getId(), binding);\n" + "applyDataBinding(binding.getId());", + false, + new JavaArgument(JAXXBinding.class.getSimpleName(), "binding")); /** * */ @@ -176,34 +186,34 @@ /** * */ - protected static final JavaMethod GET_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(0, "java.beans.PropertyChangeSupport", "$getPropertyChangeSupport", + protected static final JavaMethod GET_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(0, "PropertyChangeSupport", "$getPropertyChangeSupport", "if ($propertyChangeSupport == null)\n" + - " $propertyChangeSupport = new PropertyChangeSupport(this);\n" + - "return $propertyChangeSupport;", false); + " $propertyChangeSupport = new PropertyChangeSupport(this);\n" + + "return $propertyChangeSupport;", false); /** * */ protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(PUBLIC, "void", "addPropertyChangeListener", "$getPropertyChangeSupport().addPropertyChangeListener(listener);", true, - new JavaArgument("java.beans.PropertyChangeListener", "listener")); + new JavaArgument("PropertyChangeListener", "listener")); /** * */ protected static final JavaMethod ADD_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod(PUBLIC, "void", "addPropertyChangeListener", "$getPropertyChangeSupport().addPropertyChangeListener(property, listener);", true, - new JavaArgument("String", "property"), new JavaArgument("java.beans.PropertyChangeListener", "listener")); + new JavaArgument("String", "property"), new JavaArgument("PropertyChangeListener", "listener")); /** * */ protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_METHOD = newMethod(PUBLIC, "void", "removePropertyChangeListener", "$getPropertyChangeSupport().removePropertyChangeListener(listener);", true, - new JavaArgument("java.beans.PropertyChangeListener", "listener")); + new JavaArgument("PropertyChangeListener", "listener")); /** * */ protected static final JavaMethod REMOVE_PROPERTY_CHANGE_SUPPORT_NAMED_METHOD = newMethod(PUBLIC, "void", "removePropertyChangeListener", "$getPropertyChangeSupport().removePropertyChangeListener(property, listener);", true, - new JavaArgument("String", "property"), new JavaArgument("java.beans.PropertyChangeListener", "listener")); + new JavaArgument("String", "property"), new JavaArgument("PropertyChangeListener", "listener")); @Override public void finalizeCompiler(CompiledObject root, JAXXCompiler compiler, JavaFile javaFile, String packageName, String className) { @@ -230,10 +240,11 @@ decorator.finalizeCompiler(compiler, root, object, javaFile, packageName, className, fullClassName); } - finalizeBindings(compiler, superclassIsJAXXObject); + // compile bindings and fill the initDataBindings field of binding helper + compiler.getBindingHelper().finalizeBindings(); if (!superclassIsJAXXObject) { - javaFile.addInterface(JAXXCompiler.getCanonicalName(JAXXObject.class)); + javaFile.addInterface(JAXXObject.class.getSimpleName()); } } @@ -245,21 +256,27 @@ String jaxxContextImplementorClass = compiler.getConfiguration().getJaxxContextClass().getName(); boolean superclassIsJAXXObject = javaFile.isSuperclassIsJAXXObject(); if (!superclassIsJAXXObject) { + javaFile.addImport(JAXXObject.class); + } + javaFile.addImport(JAXXContext.class); + javaFile.addImport(JAXXObjectDescriptor.class); + + if (!superclassIsJAXXObject) { // add logger if (compiler.getConfiguration().isAddLogger()) { javaFile.addImport(Log.class); javaFile.addImport(LogFactory.class); - javaFile.addSimpleField(newField(PUBLIC | STATIC | FINAL, "Log", "log", false, "LogFactory.getLog(" + fullClassName + ".class)")); + //TC-20091127 : let the logger stays protected + javaFile.addSimpleField(newField(PROTECTED | STATIC | FINAL, "Log", "log", false, "LogFactory.getLog(" + fullClassName + ".class)")); } // JAXXObject javaFile.addField(OBJECT_MAP_FIELD); javaFile.addMethod(GET_OBJECT_BY_ID_METHOD); - javaFile.addField(BINDING_SOURCES_FIELD); - javaFile.addField(ACTIVE_BINDINGS_FIELD); - + javaFile.addSimpleField(BINDING_SOURCES_FIELD); + javaFile.addSimpleField(ACTIVE_BINDINGS_FIELD); // JAXXContext - javaFile.addField(newField(PROTECTED | FINAL, JAXXContext.class.getName(), "delegateContext", true, "new " + jaxxContextImplementorClass + "()")); + javaFile.addField(newField(PROTECTED | FINAL, JAXXContext.class.getSimpleName(), "delegateContext", true, "new " + jaxxContextImplementorClass + "()")); // javaFile.addField(newField(PROTECTED | FINAL, JAXXContext.class.getName(), "delegateContext", true, "new " + jaxxContextImplementorClass + "(this)")); javaFile.addMethod(SET_CONTEXT_VALUE_METHOD); javaFile.addMethod(SET_CONTEXT_VALUE_NAMED_METHOD); @@ -342,65 +359,86 @@ javaFile.addBodyCode(compiler.getBodyCode().toString()); - javaFile.addMethod(createCompleteSetupMethod(compiler, javaFile, compiler.getInitDataBindings())); + String dataBindingInitNode = null; + String simpleBindingInitNode = null; - javaFile.addMethod(newMethod(PUBLIC, "void", "applyDataBinding", - compiler.getApplyDataBinding().toString() + JAXXCompiler.getLineSeparator() + "processDataBinding($binding);", - true, - new JavaArgument("String", "$binding"))); + String eol = JAXXCompiler.getLineSeparator(); + JavaFileGenerator generator = new JavaFileGenerator(eol, true); - javaFile.addMethod(newMethod(PUBLIC, "void", "removeDataBinding", - compiler.getRemoveDataBinding().toString(), true, new JavaArgument("String", "$binding"))); + DataBinding[] bindings; - javaFile.addMethod(createProcessDataBindingMethod(compiler, superclassIsJAXXObject)); + bindings = compiler.getBindingHelper().getSimpleBindings(); + if (bindings.length > 0) { - addEventHandlers(compiler, javaFile); + // get data binding register code - } + StringBuilder initCode = new StringBuilder(); - protected void finalizeBindings(JAXXCompiler compiler, boolean superclassIsJAXXObject) { - String eol = JAXXCompiler.getLineSeparator(); + for (DataBinding binding : bindings) { - if (compiler.getDataBindings() != null && !compiler.getDataBindings().isEmpty()) { - compiler.addImport(DataBindingListener.class.getName()); - } + // ce n'est pas un binding, on enregistre le code d'init (si il existe) - for (DataBinding dataBinding : compiler.getDataBindings()) { - if (dataBinding.compile(compiler, true)) { - String expression = "applyDataBinding(" + compiler.getJavaCode(dataBinding.getId()) + ");" + eol; - compiler.appendInitDataBindings(expression); + if (binding.getInitDataBinding() != null) { + initCode.append(binding.getInitDataBinding()); + } } - } - if (superclassIsJAXXObject) { - boolean hasBind = compiler.hasApplyDataBinding(); - if (hasBind) { - compiler.appendApplyDataBinding(" else {"); - compiler.appendApplyDataBinding(eol); - compiler.appendApplyDataBinding(" "); + if (initCode.length() > 0) { + simpleBindingInitNode = "// apply " + bindings.length + " property setters " + eol + initCode.toString().trim(); } - compiler.appendApplyDataBinding("super.applyDataBinding($binding);"); - compiler.appendApplyDataBinding(eol); + } - if (hasBind) { - compiler.appendApplyDataBinding(" return;"); - compiler.appendApplyDataBinding(eol); - compiler.appendApplyDataBinding("}"); - } + bindings = compiler.getBindingHelper().getDataBindings(); - hasBind = compiler.hasRemoveDataBinding(); - if (hasBind) { - compiler.appendRemoveDataBinding(" else {"); - compiler.appendRemoveDataBinding(eol); - compiler.appendRemoveDataBinding(" "); + boolean hasDataBindings = bindings.length > 0; + + if (hasDataBindings) { + + javaFile.addImport(JAXXBinding.class); + javaFile.addSimpleField(BINDINGS_FIELD); + javaFile.addMethod(REGISTER_DATA_BINDING_METHOD); + + // get data binding register code + + StringBuilder initCode = new StringBuilder(); + + for (DataBinding binding : bindings) { + + String constantId = binding.getConstantId(); + + // add the data binding constant Id + + compiler.addSimpleField(new JavaField((constantId.startsWith("BINDING_$") ? PRIVATE : PUBLIC) | FINAL | STATIC, String.class.getSimpleName(), constantId, false, TypeManager.getJavaCode(binding.getRealId()))); + + // register the binding + + List<JavaMethod> bMethods = binding.getMethods(); + + bMethods.add(0, new JavaMethod(PUBLIC, "void", "removeDataBinding", new JavaArgument[0], new String[0], binding.getRemoveListenerCode(), true)); + bMethods.add(0, new JavaMethod(PUBLIC, "void", "processDataBinding", new JavaArgument[0], new String[0], binding.getProcessDataBinding(), true)); + bMethods.add(0, new JavaMethod(PUBLIC, "void", "applyDataBinding", new JavaArgument[0], new String[0], binding.getAddListenerCode(), true)); + + initCode.append("registerDataBinding(new ").append(JAXXBinding.class.getSimpleName()).append("(").append(binding.getConstantId()).append(") {").append(eol); + for (JavaMethod m : bMethods) { + initCode.append(eol).append(JavaFileGenerator.indent(generator.generateMethod(m), 4, false, eol)).append(eol); + } + initCode.append("});").append(eol); + + if (binding.getInitDataBinding() != null) { + initCode.append(binding.getInitDataBinding()); + } } - compiler.appendRemoveDataBinding("super.removeDataBinding($binding);"); - compiler.appendRemoveDataBinding(eol); - if (hasBind) { - compiler.appendRemoveDataBinding("}"); - } + dataBindingInitNode = "// registers " + bindings.length + " data bindings" + eol + initCode.toString().trim(); } + + javaFile.addMethod(createCompleteSetupMethod(compiler, javaFile, simpleBindingInitNode, dataBindingInitNode)); + + javaFile.addMethod(createApplyDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); + javaFile.addMethod(createProcessDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); + javaFile.addMethod(createRemoveDataBindingMethod(superclassIsJAXXObject, hasDataBindings)); + + addEventHandlers(compiler, javaFile); } /*---------------------------------------------------------------------------------*/ @@ -424,13 +462,13 @@ int sizeLimit = 65000; // constant strings are limited to 64K, and I'm not brave enough to push right up to the limit if (data.length() < sizeLimit) { - return newField(PRIVATE | STATIC, "String", "$jaxxObjectDescriptor", false, compiler.getJavaCode(data)); + return newField(PRIVATE | STATIC | FINAL, "String", "$jaxxObjectDescriptor", false, TypeManager.getJavaCode(data)); } else { StringBuffer initializer = new StringBuffer(); for (int i = 0; i < data.length(); i += sizeLimit) { String name = "$jaxxObjectDescriptor" + i; javaFile.addField(new JavaField(PRIVATE | STATIC, "String", name, false, - compiler.getJavaCode(data.substring(i, Math.min(i + sizeLimit, data.length()))))); + TypeManager.getJavaCode(data.substring(i, Math.min(i + sizeLimit, data.length()))))); if (initializer.length() > 0) { initializer.append(" + "); } @@ -470,6 +508,9 @@ javaFile.addMethod(FIRE_PROPERTY_CHANGE_METHOD); } else { // either no support at all or firePropertyChange isn't accessible + javaFile.addImport(PropertyChangeListener.class); + javaFile.addImport(PropertyChangeSupport.class); + javaFile.addField(PROPERTY_CHANGE_SUPPORT_FIELD); javaFile.addMethod(GET_PROPERTY_CHANGE_SUPPORT_METHOD); javaFile.addMethod(ADD_PROPERTY_CHANGE_SUPPORT_METHOD); @@ -532,12 +573,12 @@ } } if (!superclassIsJAXXObject) { - code.append(Util.class.getName()).append(".initContext(this, parentContext);"); + code.append(Util.class.getSimpleName()).append(".initContext(this, parentContext);"); code.append(eol); } code.append("$initialize();"); code.append(eol); - return newMethod(PUBLIC, null, className, code.toString(), false, new JavaArgument(JAXXContext.class.getName(), "parentContext")); + return newMethod(PUBLIC, null, className, code.toString(), false, new JavaArgument(JAXXContext.class.getSimpleName(), "parentContext")); } public JavaMethod createInitializer(JAXXCompiler compiler) throws CompilerException { @@ -551,7 +592,7 @@ code.append("}"); code.append(eol); //TODO-TC20091025 we should remove this if no used anywhere - code.append("$objectMap.put(").append(compiler.getJavaCode(root.getId())).append(", this);"); + code.append("$objectMap.put(").append(TypeManager.getJavaCode(root.getId())).append(", this);"); code.append(eol); Iterator<CompiledObject> i = compiler.getObjectCreationOrder(); @@ -575,18 +616,24 @@ return newMethod(PRIVATE, "void", "$initialize", code.toString(), false); } - protected JavaMethod createCompleteSetupMethod(JAXXCompiler compiler, JavaFile javaFile, StringBuffer initDataBindings) { + protected JavaMethod createCompleteSetupMethod(JAXXCompiler compiler, JavaFile javaFile, String simpleBindingInitNode, String dataBindingInitNode) { StringBuffer code = new StringBuffer(); code.append("allComponentsCreated = true;"); String eol = JAXXCompiler.getLineSeparator(); code.append(eol); for (CompiledObject object : compiler.getObjects().values()) { CompiledObjectDecorator decorator = object.getDecorator(); - code.append(decorator.createCompleteSetupMethod(compiler, object, javaFile, initDataBindings)); + code.append(decorator.createCompleteSetupMethod(compiler, object, javaFile)); } - code.append("// init data bindings").append(eol); - code.append(initDataBindings); + if (simpleBindingInitNode != null && !simpleBindingInitNode.isEmpty()) { + code.append(simpleBindingInitNode).append(eol); + } + + if (dataBindingInitNode != null && !dataBindingInitNode.isEmpty()) { + code.append(dataBindingInitNode).append(eol); + } + if (compiler.getLateInitializer().length() > 0) { code.append("// late initializer").append(eol); code.append(compiler.getLateInitializer()).append(eol); @@ -599,34 +646,102 @@ return newMethod(PRIVATE, "void", "$completeSetup", code.toString(), false); } - protected JavaMethod createProcessDataBindingMethod(JAXXCompiler compiler, boolean superclassIsJAXXObject) { + protected JavaMethod createApplyDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { + StringBuilder buffer = new StringBuilder(); + String eol = JAXXCompiler.getLineSeparator(); + + if (haveBinding) { + if (superclassIsJAXXObject) + buffer.append("if (allComponentsCreated && $bindings.containsKey($binding)) {").append(eol); + else { + buffer.append("if ($bindings.containsKey($binding)) {").append(eol); + } + buffer.append(" $bindings.get($binding).applyDataBinding();").append(eol); + buffer.append("}"); + + } + if (superclassIsJAXXObject) { + + if (haveBinding) { + buffer.append(" else {").append(eol).append(" "); + } + buffer.append("super.applyDataBinding($binding);").append(eol); + + if (haveBinding) { + buffer.append(" return;").append(eol).append("}"); + } + + } + buffer.append(eol).append("processDataBinding($binding);"); + return newMethod(PUBLIC, "void", "applyDataBinding", buffer.toString(), true, + new JavaArgument("String", "$binding")); + } + + protected JavaMethod createRemoveDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { + StringBuilder buffer = new StringBuilder(); + String eol = JAXXCompiler.getLineSeparator(); + + if (haveBinding) { + + if (superclassIsJAXXObject) { + buffer.append("if (allComponentsCreated && $bindings.containsKey($binding)) {").append(eol); + } else { + buffer.append("if ($bindings.containsKey($binding)) {").append(eol); + } + buffer.append(" $bindings.get($binding).removeDataBinding();").append(eol); + buffer.append("}"); + + + } + if (superclassIsJAXXObject) { + + if (haveBinding) { + buffer.append(" else {").append(eol).append(" "); + } + buffer.append("super.removeDataBinding($binding);").append(eol); + + if (haveBinding) { + buffer.append("}"); + } + } + return newMethod(PUBLIC, "void", "removeDataBinding", buffer.toString(), true, + new JavaArgument("String", "$binding")); + } + + protected JavaMethod createProcessDataBindingMethod(boolean superclassIsJAXXObject, boolean haveBinding) { StringBuffer code = new StringBuffer(); String eol = JAXXCompiler.getLineSeparator(); //boolean superclassIsJAXXObject = ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(compiler.getRootObject().getObjectClass()); // the force parameter forces the update to happen even if it is already in activeBindings. This // is used on superclass invocations b/c by the time the call gets to the superclass, it is already // marked active and would otherwise be skipped - if (compiler.getProcessDataBinding().length() > 0) { - code.append(" if (!$force && $activeBindings.contains($dest)) { "); + if (haveBinding) { + code.append(" if (!$force && $activeBindings.contains($binding)) { "); code.append(eol); code.append(" return;").append(eol); code.append("}").append(eol); - code.append("$activeBindings.add($dest);").append(eol); + code.append("$activeBindings.add($binding);").append(eol); code.append("try {").append(eol); - code.append(compiler.getProcessDataBinding().toString()); if (superclassIsJAXXObject) { + code.append(" if (allComponentsCreated && $bindings.containsKey($binding)) {").append(eol); + } else { + code.append(" if ($bindings.containsKey($binding)) {").append(eol); + } + code.append(" $bindings.get($binding).processDataBinding();").append(eol); + code.append(" }"); + if (superclassIsJAXXObject) { code.append(" else {").append(eol); - code.append(" super.processDataBinding($dest, true);").append(eol); + code.append(" super.processDataBinding($binding, true);").append(eol); code.append(" }"); } code.append(eol); code.append("} finally {").append(eol); - code.append(" $activeBindings.remove($dest);").append(eol); + code.append(" $activeBindings.remove($binding);").append(eol); code.append("}").append(eol); } else if (superclassIsJAXXObject) { - code.append("super.processDataBinding($dest, true);").append(eol); + code.append("super.processDataBinding($binding, true);").append(eol); } return newMethod(PUBLIC, "void", "processDataBinding", code.toString(), superclassIsJAXXObject, - new JavaArgument("String", "$dest"), new JavaArgument("boolean", "$force")); + new JavaArgument("String", "$binding"), new JavaArgument("boolean", "$force")); } } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/DefaultObjectHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/DefaultObjectHandler.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/DefaultObjectHandler.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -20,18 +20,13 @@ */ package jaxx.compiler.tags; -import jaxx.compiler.CompilerException; -import jaxx.compiler.UnsupportedAttributeException; -import jaxx.compiler.CompiledObject; -import jaxx.compiler.CompiledObjectDecorator; -import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.*; import jaxx.compiler.beans.JAXXBeanInfo; import jaxx.compiler.beans.JAXXEventSetDescriptor; import jaxx.compiler.beans.JAXXIntrospector; import jaxx.compiler.beans.JAXXPropertyDescriptor; +import jaxx.compiler.binding.DataBindingHelper; import jaxx.compiler.css.StylesheetHelper; -import jaxx.compiler.java.JavaArgument; -import jaxx.compiler.java.JavaMethod; import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.reflect.FieldDescriptor; @@ -40,30 +35,15 @@ import jaxx.runtime.ComponentDescriptor; import jaxx.runtime.JAXXObject; import jaxx.runtime.JAXXObjectDescriptor; -import jaxx.runtime.Util; import jaxx.runtime.css.Stylesheet; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; +import org.w3c.dom.*; import java.beans.IntrospectionException; import java.beans.Introspector; -import java.beans.PropertyChangeListener; import java.io.IOException; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.WeakHashMap; +import java.util.*; -import org.apache.commons.lang.StringUtils; - /** * Default handler for class tags. Class tags are tags which represent instances of Java classes, * such as <code><JButton label='Close'/></code>. <code>DefaultObjectHandler</code> @@ -117,13 +97,17 @@ */ protected static Map<Element, CompiledObject> objectMap = new WeakHashMap<Element, CompiledObject>(); + public ProxyEventInfo getEventInfo(String memberName) { + return eventInfos != null ? eventInfos.get(memberName) : null; + } + /** * Encapsulates information about a "proxy event handler", which is an event handler that * fires PropertyChangeEvents when it is triggered. ProxyEventInfos simplify the data binding * system by allowing all dependencies to fire the same kind of event even if they would * normally throw something else, like <code>DocumentEvent</code>. */ - private class ProxyEventInfo { + public static class ProxyEventInfo { /** * The name of the method or field being proxied, e.g. "getText". @@ -150,6 +134,26 @@ * The name of the method used to remove the "native" event listener, e.g. "removeDocumentListener". */ String removeMethod; + + public String getAddMethod() { + return addMethod; + } + + public ClassDescriptor getListenerClass() { + return listenerClass; + } + + public String getMemberName() { + return memberName; + } + + public String getModelName() { + return modelName; + } + + public String getRemoveMethod() { + return removeMethod; + } } /** @@ -282,7 +286,7 @@ } } - private static ClassDescriptor getEventClass(ClassDescriptor listenerClass) { + public static ClassDescriptor getEventClass(ClassDescriptor listenerClass) { return listenerClass.getMethodDescriptors()[0].getParameterTypes()[0]; } @@ -297,157 +301,160 @@ // return eventInfo == null ? null : new String[]{eventInfo.modelName}; // } - /** - * Returns a snippet of Java code which will cause a <code>PropertyChangeListener</code> to be notified - * when the member's value changes. The <code>PropertyChangeListener</code> is provided in the form - * of a Java code snippet that evaluates to a listener object. - * <p/> - * For ordinary bound JavaBeans properties, the Java code returned is a simple call to - * <code>addPropertyChangeListener</code>. Fields and methods which do not actually fire - * <code>PropertyChangeEvents</code> when they change necessitate more complex code. - * - * @param objectCode Java code which evaluates to the object to which to add the listener - * *@param dataBinding the name of the data binding this listener is a part of - * @param dataBinding databinding - * @param memberName the name of the field or method to listen to - * @param propertyChangeListenerCode Java code which evaluates to a <code>PropertyChangeListener</code> - * @param compiler the current <code>JAXXCompiler</code> - * @return Java code snippet which causes the listener to be added to the object - */ - public String getAddMemberListenerCode(String objectCode, String dataBinding, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { - if ("getClass".equals(memberName)) { - return null; - } +// /** +// * Returns a snippet of Java code which will cause a <code>PropertyChangeListener</code> to be notified +// * when the member's value changes. The <code>PropertyChangeListener</code> is provided in the form +// * of a Java code snippet that evaluates to a listener object. +// * <p/> +// * For ordinary bound JavaBeans properties, the Java code returned is a simple call to +// * <code>addPropertyChangeListener</code>. Fields and methods which do not actually fire +// * <code>PropertyChangeEvents</code> when they change necessitate more complex code. +// * +// * @param objectCode Java code which evaluates to the object to which to add the listener +// * *@param dataBinding the name of the data binding this listener is a part of +// * @param dataBinding databinding +// * @param memberName the name of the field or method to listen to +// * @param propertyChangeListenerCode Java code which evaluates to a <code>PropertyChangeListener</code> +// * @param compiler the current <code>JAXXCompiler</code> +// * @return Java code snippet which causes the listener to be added to the object +// */ +// public String getAddMemberListenerCode(String objectCode, String dataBinding, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { +// if ("getClass".equals(memberName)) { +// return null; +// } +// +// ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; +// if (eventInfo != null) { +// // a "proxied" event is one that doesn't fire PropertyChangeEvent, so we need to convert its native event type into PropertyChangeEvents +// StringBuffer result = new StringBuffer(); +// String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); +// boolean methodExists = compiler.hasMethod(methodName); +// ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); +// if (!methodExists) { +// compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, +// new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, +// propertyChangeListenerCode + ".propertyChange(null);", false)); +// } +// String code = objectCode + (eventInfo.modelName != null ? ".get" + StringUtils.capitalize(eventInfo.modelName) + "()" : ""); +// result.append("$bindingSources.put(\"").append(code).append("\", ").append(code).append(");").append(JAXXCompiler.getLineSeparator()); +// //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name +// result.append(code).append('.').append(eventInfo.addMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));"); +// result.append(JAXXCompiler.getLineSeparator()); +// if (eventInfo.modelName != null) { +// result.append(getAddMemberListenerCode(objectCode, dataBinding, "get" + StringUtils.capitalize(eventInfo.modelName), +// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , " + dataBinding + ")", +//// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , \"" + dataBinding + "\")", +// compiler)); +// } +// return result.toString(); +// } else { +// String propertyName = null; +// if (memberName.startsWith("get")) { +// propertyName = Introspector.decapitalize(memberName.substring("get".length())); +// } else if (memberName.startsWith("is")) { +// propertyName = Introspector.decapitalize(memberName.substring("is".length())); +// } else { +// try { +// getBeanClass().getFieldDescriptor(memberName); +// propertyName = memberName; +// } catch (NoSuchFieldException e) { +// // ignore ? +// } +// } +// if (propertyName != null) { +// //TC-20091026 when on root object, do not prefix with objectCode +// String prefix = objectCode.trim() + "."; +// if (objectCode.equals(compiler.getRootObject().getJavaCode())) { +// prefix = ""; +// } +// try { +// // check for property-specific addPropertyChangeListener method +// getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), +// ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); +// return prefix + "addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; +// } catch (NoSuchMethodException e) { +// // no property-specific method, use general one +// return prefix + "addPropertyChangeListener(" + propertyChangeListenerCode + ");\n"; +// } +// } +// return null; +// } +// } +// +// public String getRemoveMemberListenerCode(String objectCode, String dataBinding, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { +// if ("getClass".equals(memberName)) { +// return null; +// } +// +// ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; +// if (eventInfo != null) { +// // a "proxied" event is one that doesn't fire PropertyChangeEvent, +// // so we need to convert its native event type into PropertyChangeEvents +// StringBuffer result = new StringBuffer(); +// String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); +// boolean methodExists = compiler.hasMethod(methodName); +// if (!methodExists) { +// ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); +// compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, +// new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, +// propertyChangeListenerCode + ".propertyChange(null);", false)); +// } +// try { +// String modelMemberName = eventInfo.modelName != null ? "get" + StringUtils.capitalize(eventInfo.modelName) : null; +// String modelClassName = modelMemberName != null ? getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(getBeanClass()); +// String code = objectCode + (eventInfo.modelName != null ? "." + modelMemberName + "()" : ""); +// String eol = JAXXCompiler.getLineSeparator(); +// result.append(modelClassName).append(" $target = ((").append(modelClassName).append(") $bindingSources.remove(\"").append(code).append("\"));").append(eol); +// //TC-20091105 test if $target is not null +// result.append("if ($target != null) {").append(eol); +// //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name +// result.append(" $target.").append(eventInfo.removeMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(TypeManager.getJavaCode(methodName)).append("));").append(eol); +// result.append("}").append(eol); +// if (eventInfo.modelName != null) { +//// String bi = dataBinding.startsWith("this.") ? dataBinding : ("\"" + dataBinding + "\""); +// result.append(getRemoveMemberListenerCode(objectCode, dataBinding, "get" + StringUtils.capitalize(eventInfo.modelName), +// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this, " + dataBinding + ")", +//// Util.class.getSimpleName() + ".getDataBindingUpdateListener(this, \"" + dataBinding + "\")", +// compiler)); +// } +// return result.toString(); +// } catch (NoSuchMethodException e) { +// throw new CompilerException("Internal error: " + e); +// } +// } else { +// String propertyName = null; +// if (memberName.startsWith("get")) { +// propertyName = Introspector.decapitalize(memberName.substring("get".length())); +// } else if (memberName.startsWith("is")) { +// propertyName = Introspector.decapitalize(memberName.substring("is".length())); +// } else { +// try { +// getBeanClass().getFieldDescriptor(memberName); +// propertyName = memberName; +// } catch (NoSuchFieldException e) { +// // ignore ? +// } +// } +// if (propertyName != null) { +// //TC-20091026 when on root object, do not prefix with objectCode +// String prefix = objectCode.trim() + "."; +// if (objectCode.equals(compiler.getRootObject().getJavaCode())) { +// prefix = ""; +// } +// try { +// // check for property-specific removePropertyChangeListener method +// getBeanClass().getMethodDescriptor("removePropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), +// ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); +// return prefix + "removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; +// } catch (NoSuchMethodException e) { +// // no property-specific method, use general one +// return prefix + "removePropertyChangeListener(" + propertyChangeListenerCode + ");\n"; +// } +// } +// return null; +// } +// } - ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; - if (eventInfo != null) { - // a "proxied" event is one that doesn't fire PropertyChangeEvent, so we need to convert its native event type into PropertyChangeEvents - StringBuffer result = new StringBuffer(); - String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); - boolean methodExists = compiler.hasMethod(methodName); - ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); - if (!methodExists) { - compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, - new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, - propertyChangeListenerCode + ".propertyChange(null);", false)); - } - String code = objectCode + (eventInfo.modelName != null ? ".get" + StringUtils.capitalize(eventInfo.modelName) + "()" : ""); - result.append("$bindingSources.put(\"").append(code).append("\", ").append(code).append(");").append(JAXXCompiler.getLineSeparator()); - //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name - result.append(code).append('.').append(eventInfo.addMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(compiler.getJavaCode(methodName)).append("));"); - result.append(JAXXCompiler.getLineSeparator()); - if (eventInfo.modelName != null) { - result.append(getAddMemberListenerCode(objectCode, dataBinding, "get" + StringUtils.capitalize(eventInfo.modelName), - Util.class.getSimpleName() + ".getDataBindingUpdateListener(this , \"" + dataBinding + "\")", - compiler)); - } - return result.toString(); - } else { - String propertyName = null; - if (memberName.startsWith("get")) { - propertyName = Introspector.decapitalize(memberName.substring("get".length())); - } else if (memberName.startsWith("is")) { - propertyName = Introspector.decapitalize(memberName.substring("is".length())); - } else { - try { - getBeanClass().getFieldDescriptor(memberName); - propertyName = memberName; - } catch (NoSuchFieldException e) { - // ignore ? - } - } - if (propertyName != null) { - //TC-20091026 when on root object, do not prefix with objectCode - String prefix = objectCode.trim() + "."; - if (objectCode.equals(compiler.getRootObject().getJavaCode())) { - prefix = ""; - } - try { - // check for property-specific addPropertyChangeListener method - getBeanClass().getMethodDescriptor("addPropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), - ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); - return prefix + "addPropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; - } catch (NoSuchMethodException e) { - // no property-specific method, use general one - return prefix + "addPropertyChangeListener(" + propertyChangeListenerCode + ");\n"; - } - } - return null; - } - } - - public String getRemoveMemberListenerCode(String objectCode, String dataBinding, String memberName, String propertyChangeListenerCode, JAXXCompiler compiler) { - if ("getClass".equals(memberName)) { - return null; - } - - ProxyEventInfo eventInfo = eventInfos != null ? eventInfos.get(memberName) : null; - if (eventInfo != null) { - // a "proxied" event is one that doesn't fire PropertyChangeEvent, - // so we need to convert its native event type into PropertyChangeEvents - StringBuffer result = new StringBuffer(); - String methodName = "$pr" + compiler.getUniqueId(propertyChangeListenerCode); - boolean methodExists = compiler.hasMethod(methodName); - if (!methodExists) { - ClassDescriptor eventClass = getEventClass(eventInfo.listenerClass); - compiler.getJavaFile().addMethod(new JavaMethod(Modifier.PUBLIC, "void", methodName, - new JavaArgument[]{new JavaArgument(JAXXCompiler.getCanonicalName(eventClass), "event")}, null, - propertyChangeListenerCode + ".propertyChange(null);", false)); - } - try { - String modelMemberName = eventInfo.modelName != null ? "get" + StringUtils.capitalize(eventInfo.modelName) : null; - String modelClassName = modelMemberName != null ? getBeanClass().getMethodDescriptor(modelMemberName).getReturnType().getName() : JAXXCompiler.getCanonicalName(getBeanClass()); - String code = objectCode + (eventInfo.modelName != null ? "." + modelMemberName + "()" : ""); - String eol = JAXXCompiler.getLineSeparator(); - result.append(modelClassName).append(" $target = ((").append(modelClassName).append(") $bindingSources.remove(\"").append(code).append("\"));").append(eol); - //TC-20091105 test if $target is not null - result.append("if ($target != null) {").append(eol); - //TC-20091105 Util.getEventListener is generic, no more need cast and use simple listener name - result.append(" $target.").append(eventInfo.removeMethod).append("( Util.getEventListener(").append(eventInfo.listenerClass.getSimpleName()).append(".class, ").append(compiler.getRootObject().getJavaCode()).append(", ").append(compiler.getJavaCode(methodName)).append("));").append(eol); - result.append("}").append(eol); - if (eventInfo.modelName != null) { - result.append(getRemoveMemberListenerCode(objectCode, dataBinding, "get" + StringUtils.capitalize(eventInfo.modelName), - Util.class.getSimpleName() + ".getDataBindingUpdateListener(this, \"" + dataBinding + "\")", - compiler)); - } - return result.toString(); - } catch (NoSuchMethodException e) { - throw new CompilerException("Internal error: " + e); - } - } else { - String propertyName = null; - if (memberName.startsWith("get")) { - propertyName = Introspector.decapitalize(memberName.substring("get".length())); - } else if (memberName.startsWith("is")) { - propertyName = Introspector.decapitalize(memberName.substring("is".length())); - } else { - try { - getBeanClass().getFieldDescriptor(memberName); - propertyName = memberName; - } catch (NoSuchFieldException e) { - // ignore ? - } - } - if (propertyName != null) { - //TC-20091026 when on root object, do not prefix with objectCode - String prefix = objectCode.trim() + "."; - if (objectCode.equals(compiler.getRootObject().getJavaCode())) { - prefix = ""; - } - try { - // check for property-specific removePropertyChangeListener method - getBeanClass().getMethodDescriptor("removePropertyChangeListener", ClassDescriptorLoader.getClassDescriptor(String.class), - ClassDescriptorLoader.getClassDescriptor(PropertyChangeListener.class)); - return prefix + "removePropertyChangeListener(\"" + propertyName + "\", " + propertyChangeListenerCode + ");\n"; - } catch (NoSuchMethodException e) { - // no property-specific method, use general one - return prefix + "removePropertyChangeListener(" + propertyChangeListenerCode + ");\n"; - } - } - return null; - } - } - /** * Configures the event handling for members which do not fire <code>PropertyChangeEvent</code> when * modified. The default implementation does nothing. Subclasses should override this method to call @@ -586,7 +593,8 @@ public void registerCompiledObject(Element tag, JAXXCompiler compiler) { String id = tag.getAttribute(ID_ATTRIBUTE); if (id == null || id.length() == 0) { - id = compiler.getAutoId(getBeanClass()); + id = compiler.getAutoId(getBeanClass().getSimpleName()); +// id = compiler.getAutoId(getBeanClass()); } CompiledObject object = createCompiledObject(id, compiler); objectMap.put(tag, object); @@ -849,41 +857,50 @@ */ public void setAttribute(CompiledObject object, String propertyName, String stringValue, boolean inline, JAXXCompiler compiler) { try { + //--------------------------------------------------------------------- + // BE WARE, Test if removing this code hurts..., anyway we have a bug on it: + // For some component (example : jaxx.runtime.swing.editor.NumberEditor) we do not have one component + // This is disturbing, must find how why... And this happens only on a mvn clean install on all project + // Everything is fine otherwise... + // + // With new binding design, we will know if there is a binding on the property + // of the jaxxObject, and could add it only if required... + //--------------------------------------------------------------------- //FIXME TC-20091105 we should to this later when all binding are compiled // because we don't know yet if this is a databinding - if (ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(object.getObjectClass())) { - // check for data binding & remove if found - JAXXObjectDescriptor jaxxObjectDescriptor = object.getObjectClass().getJAXXObjectDescriptor(); - ComponentDescriptor root = jaxxObjectDescriptor.getComponentDescriptors()[0]; - //TC-20091026 do not prefix binding by object id if on root object - String prefix; - if (object == compiler.getRootObject()) { - prefix = ""; - } else { - prefix = object.getJavaCode() + "."; - } - object.appendInitializationCode(prefix + "removeDataBinding(" + compiler.getJavaCode(root.getId() + "." + propertyName) + ");"); - } +// if (ClassDescriptorLoader.getClassDescriptor(JAXXObject.class).isAssignableFrom(object.getObjectClass())) { +// // check for data binding & remove if found +// JAXXObjectDescriptor jaxxObjectDescriptor = object.getObjectClass().getJAXXObjectDescriptor(); +// if (jaxxObjectDescriptor.getComponentDescriptors().length == 0) { +// compiler.reportWarning("JAXXObject component " + object.getObjectClass() + " should have at least one component!"); +//// throw new IllegalStateException("JAXXObject component " + object.getObjectClass() + " should have at least one component!"); +// } else { +// ComponentDescriptor root = jaxxObjectDescriptor.getComponentDescriptors()[0]; +// //TC-20091026 do not prefix binding by object id if on root object +// String prefix; +// if (object == compiler.getRootObject()) { +// prefix = ""; +// } else { +// prefix = object.getJavaCode() + "."; +// } +// object.appendInitializationCode(prefix + "removeDataBinding(" + compiler.getJavaCode(root.getId() + "." + propertyName) + ");"); +// } +// } object.addProperty(propertyName, stringValue); ClassDescriptor type = getPropertyType(object, propertyName, compiler); - String binding = compiler.processDataBindings(stringValue); + String binding = DataBindingHelper.processDataBindings(stringValue); + boolean withBinding = binding != null; + if (inline) { - compiler.addInlineStyle(object, propertyName, binding != null); + compiler.addInlineStyle(object, propertyName, withBinding); } - if (binding != null) { - String setPropertyCode = getSetPropertyCode(object.getJavaCode(), propertyName, binding, compiler); - if (propertyName.equals(LAYOUT_ATTRIBUTE)) { - // handle containerDelegate (e.g. contentPane on JFrame) - // have to set layout early, before children are added - object.appendInitializationCode(setPropertyCode); - } - compiler.registerDataBinding(binding, object.getId() + "." + propertyName, setPropertyCode); - } else { + if (!withBinding) { // no bindings, convert from string try { Class<?> typeClass = type != null ? ClassDescriptorLoader.getClass(type.getName(), type.getClassLoader()) : null; Object value = convertFromString(propertyName, stringValue, typeClass); setProperty(object, propertyName, value, compiler); + return; } catch (NumberFormatException e) { compiler.reportError("could not convert literal string '" + stringValue + "' to type " + type.getName()); } catch (IllegalArgumentException e) { @@ -892,6 +909,14 @@ compiler.reportError("could not find class " + type.getName()); } } + String setPropertyCode = getSetPropertyCode(object.getJavaCode(), propertyName, binding, compiler); + if (propertyName.equals(LAYOUT_ATTRIBUTE)) { + // handle containerDelegate (e.g. contentPane on JFrame) + // have to set layout early, before children are added + object.appendInitializationCode(setPropertyCode); + } + compiler.getBindingHelper().registerDataBinding(object.getId() + "." + propertyName, binding, setPropertyCode); +// compiler.getBindingHelper().registerDataBinding(binding, object.getId() + "." + propertyName, setPropertyCode); } catch (UnsupportedAttributeException e) { compiler.reportError("class " + object.getObjectClass().getName() + " does not support attribute '" + propertyName + "'"); } @@ -918,7 +943,7 @@ String id = isRoot ? object.getId() + ' ' + descriptor.getId() : "( " + object.getId() + " ) " + descriptor.getId(); CompiledObject child = new CompiledObject(id, "((" + JAXXCompiler.getCanonicalName(classDescriptor) + ") " + - object.getJavaCode() + ".getObjectById(" + compiler.getJavaCode(descriptor.getId()) + "))", + object.getJavaCode() + ".getObjectById(" + TypeManager.getJavaCode(descriptor.getId()) + "))", classDescriptor, compiler, true); @@ -1059,7 +1084,7 @@ * @throws CompilerException if a compilation error occurs */ public void setProperty(CompiledObject object, String name, Object value, JAXXCompiler compiler) { - object.appendInitializationCode(getSetPropertyCode(object.getJavaCodeForProperty(name), name, compiler.getJavaCode(value), compiler)); + object.appendInitializationCode(getSetPropertyCode(object.getJavaCodeForProperty(name), name, TypeManager.getJavaCode(value), compiler)); } /** Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/ItemHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/ItemHandler.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/ItemHandler.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -23,7 +23,7 @@ import jaxx.compiler.CompilerException; import jaxx.compiler.UnsupportedAttributeException; import jaxx.compiler.JAXXCompiler; -import jaxx.compiler.reflect.ClassDescriptorLoader; +import jaxx.compiler.binding.DataBindingHelper; import jaxx.compiler.tags.TagHandler; import jaxx.compiler.types.TypeManager; import jaxx.runtime.swing.Item; @@ -50,7 +50,8 @@ public void compileSecondPass(Element tag, JAXXCompiler compiler) throws CompilerException, IOException { String id = tag.getAttribute("id"); if (id == null || id.length() == 0) { - id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(Item.class)); + id = compiler.getAutoId(Item.class.getSimpleName()); +// id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(Item.class)); } String label = null; String value = null; @@ -65,29 +66,33 @@ // already handled continue; } + DataBindingHelper bindingHelper = compiler.getBindingHelper(); if (name.equals(Item.LABEL_PROPERTY)) { - String labelBinding = compiler.processDataBindings(attrValue); + String labelBinding = DataBindingHelper.processDataBindings(attrValue); if (labelBinding != null) { - compiler.registerDataBinding(labelBinding, id + ".label", id + ".setLabel(" + labelBinding + ");"); + bindingHelper.registerDataBinding(id + ".label", labelBinding, id + ".setLabel(" + labelBinding + ");"); +// bindingHelper.registerDataBinding(labelBinding, id + ".label", id + ".setLabel(" + labelBinding + ");"); } else { label = attrValue; } continue; } if (name.equals(Item.VALUE_PROPERTY)) { - String valueBinding = compiler.processDataBindings(attrValue); + String valueBinding = DataBindingHelper.processDataBindings(attrValue); if (valueBinding != null) { value = DATA_BINDING; - compiler.registerDataBinding(valueBinding, id + ".value", id + ".setValue(" + valueBinding + ");"); + bindingHelper.registerDataBinding(id + ".value", valueBinding, id + ".setValue(" + valueBinding + ");"); +// bindingHelper.registerDataBinding(valueBinding, id + ".value", id + ".setValue(" + valueBinding + ");"); } else { value = attrValue; } continue; } if (name.equals(Item.SELECTED_PROPERTY)) { - String selectedBinding = compiler.processDataBindings(attrValue); + String selectedBinding = DataBindingHelper.processDataBindings(attrValue); if (selectedBinding != null) { - compiler.registerDataBinding(selectedBinding, id + ".selected", id + ".setSelected(" + selectedBinding + ");"); + bindingHelper.registerDataBinding(id + ".selected", selectedBinding, id + ".setSelected(" + selectedBinding + ");"); +// bindingHelper.registerDataBinding(selectedBinding, id + ".selected", id + ".setSelected(" + selectedBinding + ");"); } else { selected = (Boolean) TypeManager.convertFromString(attrValue, Boolean.class); } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/JAXXComboBoxHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/JAXXComboBoxHandler.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/JAXXComboBoxHandler.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -26,6 +26,7 @@ import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.tags.DefaultComponentHandler; +import jaxx.compiler.types.TypeManager; import jaxx.runtime.swing.JAXXComboBox; import jaxx.runtime.swing.Item; import org.w3c.dom.Element; @@ -64,7 +65,7 @@ for (Item item : items) { String id = item.getId(); CompiledObject compiledItem = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(Item.class), compiler); - compiledItem.setConstructorParams(compiler.getJavaCode(id) + ", " + compiler.getJavaCode(item.getLabel()) + ", " + compiler.getJavaCode(item.getValue()) + ", " + item.isSelected()); + compiledItem.setConstructorParams(TypeManager.getJavaCode(id) + ", " + TypeManager.getJavaCode(item.getLabel()) + ", " + TypeManager.getJavaCode(item.getValue()) + ", " + item.isSelected()); compiler.registerCompiledObject(compiledItem); list.appendAdditionCode(listName + ".add(" + id + ");"); } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/TabHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/TabHandler.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/swing/TabHandler.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -24,9 +24,12 @@ import jaxx.compiler.CompiledObject; import jaxx.compiler.I18nHelper; import jaxx.compiler.JAXXCompiler; +import jaxx.compiler.binding.DataBindingHelper; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.tags.TagHandler; +import jaxx.compiler.types.TypeManager; import jaxx.runtime.swing.TabInfo; +import org.apache.commons.lang.StringUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -57,7 +60,8 @@ String id = tag.getAttribute("id"); if (id == null || id.length() == 0) { - id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(TabInfo.class)); + id = compiler.getAutoId(TabInfo.class.getSimpleName()); +// id = compiler.getAutoId(ClassDescriptorLoader.getClassDescriptor(TabInfo.class)); } TabInfo tabInfo = new TabInfo(id); CompiledObject compiledTabInfo = new CompiledObject(id, ClassDescriptorLoader.getClassDescriptor(TabInfo.class), compiler); @@ -73,20 +77,22 @@ value = value.trim(); TabInfo tabInfo = tabs.tabInfo; String id = tabInfo.getId(); - String binding = compiler.processDataBindings(value); + String binding = DataBindingHelper.processDataBindings(value); if (binding != null) { - compiler.registerDataBinding(binding, id + "." + name, id + ".set" + org.apache.commons.lang.StringUtils.capitalize(name) + "(" + binding + ");"); + compiler.getBindingHelper().registerDataBinding(id + "." + name, binding, id + ".set" + StringUtils.capitalize(name) + "(" + binding + ");"); +// compiler.getBindingHelper().registerDataBinding(binding, id + "." + name, id + ".set" + StringUtils.capitalize(name) + "(" + binding + ");"); return; } - String valueCode = compiler.getJavaCode(value); + String valueCode = TypeManager.getJavaCode(value); // add i18n support if (I18nHelper.isI18nableAttribute(name, compiler)) { value = valueCode = I18nHelper.addI18nInvocation(id, name, valueCode, compiler); } - - if (name.equals("title")) { + if (name.equals("id")) { + // ignore, already handled + } else if (name.equals("title")) { tabInfo.setTitle(value); compiledTabInfo.appendInitializationCode(id + ".setTitle(" + valueCode + ");"); //compiledTabInfo.appendInitializationCode(id + ".setTitle(" + TypeManager.getJavaCode(value) + ");"); @@ -95,35 +101,33 @@ compiledTabInfo.appendInitializationCode(id + ".setToolTipText(" + valueCode + ");"); //compiledTabInfo.appendInitializationCode(id + ".setToolTipText(" + TypeManager.getJavaCode(value) + ");"); } else if (name.equals("icon")) { - Icon icon = (Icon) compiler.convertFromString(value, Icon.class); + Icon icon = (Icon) TypeManager.convertFromString(value, Icon.class); tabInfo.setIcon(icon); - compiledTabInfo.appendInitializationCode(id + ".setIcon(" + compiler.getJavaCode(icon) + ");"); + compiledTabInfo.appendInitializationCode(id + ".setIcon(" + TypeManager.getJavaCode(icon) + ");"); } else if (name.equals("enabled")) { - boolean enabled = (Boolean) compiler.convertFromString(value, Boolean.class); + boolean enabled = (Boolean) TypeManager.convertFromString(value, Boolean.class); tabInfo.setEnabled(enabled); compiledTabInfo.appendInitializationCode(id + ".setEnabled(" + enabled + ");"); } else if (name.equals("disabledIcon")) { - Icon disabledIcon = (Icon) compiler.convertFromString(value, Icon.class); + Icon disabledIcon = (Icon) TypeManager.convertFromString(value, Icon.class); tabInfo.setDisabledIcon(disabledIcon); - compiledTabInfo.appendInitializationCode(id + ".setDisabledIcon(" + compiler.getJavaCode(disabledIcon) + ");"); + compiledTabInfo.appendInitializationCode(id + ".setDisabledIcon(" + TypeManager.getJavaCode(disabledIcon) + ");"); } else if (name.equals("mnemonic")) { - int mnemonic = (Character) compiler.convertFromString(value, char.class); + int mnemonic = (Character) TypeManager.convertFromString(value, char.class); tabInfo.setMnemonic(mnemonic); compiledTabInfo.appendInitializationCode(id + ".setMnemonic(" + mnemonic + ");"); } else if (name.equals("displayedMnemonicIndex")) { - int displayedMnemonicIndex = (Integer) compiler.convertFromString(value, int.class); + int displayedMnemonicIndex = (Integer) TypeManager.convertFromString(value, int.class); tabInfo.setDisplayedMnemonicIndex(displayedMnemonicIndex); compiledTabInfo.appendInitializationCode(id + ".setDisplayedMnemonicIndex(" + displayedMnemonicIndex + ");"); } else if (name.equals("foreground")) { - Color foreground = (Color) compiler.convertFromString(value, Color.class); + Color foreground = (Color) TypeManager.convertFromString(value, Color.class); tabInfo.setForeground(foreground); - compiledTabInfo.appendInitializationCode(id + ".setForeground(" + compiler.getJavaCode(foreground) + ");"); + compiledTabInfo.appendInitializationCode(id + ".setForeground(" + TypeManager.getJavaCode(foreground) + ");"); } else if (name.equals("background")) { - Color background = (Color) compiler.convertFromString(value, Color.class); + Color background = (Color) TypeManager.convertFromString(value, Color.class); tabInfo.setBackground(background); - compiledTabInfo.appendInitializationCode(id + ".setBackground(" + compiler.getJavaCode(background) + ");"); - } else if (name.equals("id")) { - // ignore, already handled + compiledTabInfo.appendInitializationCode(id + ".setBackground(" + TypeManager.getJavaCode(background) + ");"); } else { compiler.reportError("The <tab> tag does not support the attribute '" + name + "'"); } Modified: branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java =================================================================== --- branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/jaxx-compiler/src/main/java/jaxx/compiler/tags/validator/BeanValidatorHandler.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -25,6 +25,7 @@ import jaxx.compiler.JAXXCompiler; import jaxx.compiler.beans.JAXXBeanInfo; import jaxx.compiler.beans.JAXXPropertyDescriptor; +import jaxx.compiler.binding.DataBindingHelper; import jaxx.compiler.reflect.ClassDescriptor; import jaxx.compiler.reflect.ClassDescriptorLoader; import jaxx.compiler.tags.DefaultObjectHandler; @@ -67,7 +68,9 @@ public static final String CONTEXT_NAME_ATTRIBUTE = "contextName"; //public static final String SCOPE_ATTRIBUTE = "scope"; public static final String PARENT_VALIDATOR_ATTRIBUTE = "parentValidator"; - /** to use log facility, just put in your code: log.info(\"...\"); */ + /** + * to use log facility, just put in your code: log.info(\"...\"); + */ static Log log = LogFactory.getLog(BeanValidatorHandler.class); protected static Map<JAXXCompiler, List<CompiledBeanValidator>> validators = new HashMap<JAXXCompiler, List<CompiledBeanValidator>>(); protected static Map<JAXXCompiler, List<String>> validatedComponents = new HashMap<JAXXCompiler, List<String>>(); @@ -528,9 +531,13 @@ if (bean.startsWith("{") && bean.endsWith("}")) { - // just has an intializer - beanInitializer = bean.substring(1, bean.length() - 1); - // this is not a real bean, so delete it + String labelBinding = DataBindingHelper.processDataBindings(bean); + if (labelBinding != null) { + compiler.getBindingHelper().registerDataBinding(getId() + ".bean", labelBinding, getId() + ".setBean(" + labelBinding + ");"); + } +// // just has an intializer +// beanInitializer = bean.substring(1, bean.length() - 1); +// // this is not a real bean, so delete it bean = null; } else { @@ -558,7 +565,7 @@ String beanClassName = beanInfo.getJAXXBeanDescriptor().getClassDescriptor().getName(); // contextName must be in constructor to able to init validator with his correct contextName - setConstructorParams(beanClassName + ".class, " + compiler.getJavaCode(contextName)); + setConstructorParams(beanClassName + ".class, " + TypeManager.getJavaCode(contextName)); // add generic type to validator setGenericTypes(new String[]{beanClassName}); @@ -606,7 +613,7 @@ // editor component not find on ui continue; } - String keyCode = compiler.getJavaCode(propertyName); + String keyCode = TypeManager.getJavaCode(propertyName); appendAdditionCode(getJavaCode() + ".setFieldRepresentation(" + keyCode + ", " + component + ");"); } } Modified: branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/DataBindingTest.java =================================================================== --- branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/DataBindingTest.java 2009-12-02 12:47:13 UTC (rev 1670) +++ branches/jaxx-2.X/maven-jaxx-plugin/src/test/java/org/nuiton/jaxx/plugin/DataBindingTest.java 2009-12-02 12:56:47 UTC (rev 1671) @@ -38,16 +38,17 @@ assertNumberJaxxFiles(1); // no bindings - checkPattern(mojo, "new DataBindingListener(this, \"nobinding1.text\");", false); - checkPattern(mojo, "new DataBindingListener(this, \"nobinding2.text\");", false); + checkPattern(mojo, "BINDING_NOBINDING1_TEXT", false); + checkPattern(mojo, "BINDING_NOBINDING2_TEXT", false); // with bindings - checkBinding(mojo, "binding8.text"); + checkBinding(mojo, "BINDING_BINDING8_TEXT"); } protected void checkBinding(GenerateMojo mojo, String... bindings) throws IOException { for (String b : bindings) { - checkPattern(mojo, "new DataBindingListener(this, \"" + b + "\");", true); + checkPattern(mojo, "public static final String " + b + " = ", true); +// checkPattern(mojo, "new DataBindingListener(this, " + b + ");", true); } } }
participants (1)
-
tchemit@users.nuiton.org