Source Code Cross Referenced for NodeModel.java in  » Ajax » Laszlo-4.0.10 » org » openlaszlo » compiler » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Ajax » Laszlo 4.0.10 » org.openlaszlo.compiler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* -*- mode: Java; c-basic-offset: 4; -*- */
0002:        /* ***************************************************************************
0003:         * NodeModel.java
0004:         * ***************************************************************************/
0005:
0006:        /* J_LZ_COPYRIGHT_BEGIN *******************************************************
0007:         * Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.              *
0008:         * Use is subject to license terms.                                            *
0009:         * J_LZ_COPYRIGHT_END *********************************************************/
0010:
0011:        package org.openlaszlo.compiler;
0012:
0013:        import java.io.*;
0014:        import java.text.ChoiceFormat;
0015:        import java.util.*;
0016:        import java.util.regex.*;
0017:
0018:        import org.openlaszlo.compiler.ViewSchema.ColorFormatException;
0019:        import org.openlaszlo.css.CSSParser;
0020:        import org.openlaszlo.sc.Function;
0021:        import org.openlaszlo.sc.ScriptCompiler;
0022:        import org.openlaszlo.server.*;
0023:        import org.openlaszlo.utils.ChainedException;
0024:        import org.openlaszlo.utils.ListFormat;
0025:        import org.openlaszlo.utils.ComparisonMap;
0026:        import org.openlaszlo.xml.internal.MissingAttributeException;
0027:        import org.openlaszlo.xml.internal.Schema;
0028:        import org.openlaszlo.xml.internal.XMLUtils;
0029:        import org.apache.commons.collections.CollectionUtils;
0030:        import org.jdom.Attribute;
0031:        import org.jdom.Element;
0032:        import org.jdom.Text;
0033:        import org.jdom.Content;
0034:        import org.jdom.Namespace;
0035:
0036:        /** Models a runtime LzNode. */
0037:        public class NodeModel implements  Cloneable {
0038:
0039:            public static final String FONTSTYLE_ATTRIBUTE = "fontstyle";
0040:            public static final String WHEN_IMMEDIATELY = "immediately";
0041:            public static final String WHEN_ONCE = "once";
0042:            public static final String WHEN_ALWAYS = "always";
0043:            public static final String WHEN_PATH = "path";
0044:            public static final String WHEN_STYLE = "style";
0045:            private static final String SOURCE_LOCATION_ATTRIBUTE_NAME = "__LZsourceLocation";
0046:
0047:            protected final ViewSchema schema;
0048:            protected final Element element;
0049:            protected String className;
0050:            protected String id = null;
0051:            protected ComparisonMap attrs = new ComparisonMap();
0052:            protected List children = new Vector();
0053:            /** A set {eventName: String -> True) of names of event handlers
0054:             * declared with <method event="xxx"/>. */
0055:            protected ComparisonMap delegates = new ComparisonMap();
0056:            /* Unused */
0057:            protected ComparisonMap events = new ComparisonMap();
0058:            protected ComparisonMap references = new ComparisonMap();
0059:            /* Unused */
0060:            protected ComparisonMap paths = new ComparisonMap();
0061:            protected ComparisonMap setters = new ComparisonMap();
0062:            protected ComparisonMap styles = new ComparisonMap();
0063:
0064:            protected NodeModel datapath = null;
0065:
0066:            /** [eventName: String, methodName: String, Function] */
0067:            protected List delegateList = new Vector();
0068:            protected ClassModel parentClassModel;
0069:            protected String initstage = null;
0070:            protected int totalSubnodes = 1;
0071:            protected final CompilationEnvironment env;
0072:
0073:            public Object clone() {
0074:                NodeModel copy;
0075:                try {
0076:                    copy = (NodeModel) super .clone();
0077:                } catch (CloneNotSupportedException e) {
0078:                    throw new RuntimeException(e);
0079:                }
0080:                copy.attrs = new ComparisonMap(copy.attrs);
0081:                copy.delegates = new ComparisonMap(copy.delegates);
0082:                copy.events = new ComparisonMap(copy.events);
0083:                copy.references = new ComparisonMap(copy.references);
0084:                copy.paths = new ComparisonMap(copy.paths);
0085:                copy.setters = new ComparisonMap(copy.setters);
0086:                copy.styles = new ComparisonMap(copy.styles);
0087:                copy.delegateList = new Vector(copy.delegateList);
0088:                copy.children = new Vector();
0089:                for (Iterator iter = children.iterator(); iter.hasNext();) {
0090:                    copy.children.add(((NodeModel) iter.next()).clone());
0091:                }
0092:                return copy;
0093:            }
0094:
0095:            private boolean caseSensitive = true;
0096:
0097:            NodeModel(Element element, ViewSchema schema,
0098:                    CompilationEnvironment env) {
0099:                this .element = element;
0100:                this .schema = schema;
0101:                this .env = env;
0102:
0103:                if ("swf6".equals(env.getRuntime())) {
0104:                    this .caseSensitive = false;
0105:                }
0106:                this .className = element.getName();
0107:                // Cache ClassModel for parent
0108:                this .parentClassModel = this .getParentClassModel();
0109:                this .initstage = this .element.getAttributeValue("initstage");
0110:                if (this .initstage != null) {
0111:                    this .initstage = this .initstage.intern();
0112:                }
0113:
0114:                // Get initial node count from superclass
0115:                // TODO: [2003-05-04] Extend this mechanism to cache/model
0116:                // all relevant superclass info
0117:                // TODO: [2003-05-04 ptw] How can we get this info for
0118:                // instances of built-in classes?
0119:                if (this .parentClassModel != null) {
0120:                    ElementWithLocationInfo parentElement = (ElementWithLocationInfo) this .parentClassModel.definition;
0121:                    // TODO: [2003-05-04 ptw] As above, but a class
0122:                    // that extends a built-in class
0123:                    if (parentElement != null) {
0124:                        // TODO: [2003-05-04 ptw] An instantiation of
0125:                        // a class that has not been modelled yet --
0126:                        // do enough modelling to get what is needed.
0127:                        if (parentElement.model != null) {
0128:                            this .totalSubnodes = parentElement.model
0129:                                    .classSubnodes();
0130:                            if (this .initstage == null) {
0131:                                this .initstage = parentElement.model.initstage;
0132:                            }
0133:                        }
0134:                    }
0135:                }
0136:            }
0137:
0138:            private static final String DEPRECATED_METHODS_PROPERTY_FILE = (LPS
0139:                    .getMiscDirectory()
0140:                    + File.separator + "lzx-deprecated-methods.properties");
0141:            private static final Properties sDeprecatedMethods = new Properties();
0142:
0143:            static {
0144:                try {
0145:                    InputStream is = new FileInputStream(
0146:                            DEPRECATED_METHODS_PROPERTY_FILE);
0147:                    try {
0148:                        sDeprecatedMethods.load(is);
0149:                    } finally {
0150:                        is.close();
0151:                    }
0152:                } catch (java.io.IOException e) {
0153:                    throw new ChainedException(e);
0154:                }
0155:            }
0156:
0157:            /* List of flash builtins to warn about if the user tries to redefine them */
0158:            private static final String FLASH6_BUILTINS_PROPERTY_FILE = (LPS
0159:                    .getMiscDirectory()
0160:                    + File.separator + "flash6-builtins.properties");
0161:
0162:            private static final String FLASH7_BUILTINS_PROPERTY_FILE = (LPS
0163:                    .getMiscDirectory()
0164:                    + File.separator + "flash7-builtins.properties");
0165:
0166:            public static final Properties sFlash6Builtins = new Properties();
0167:            public static final Properties sFlash7Builtins = new Properties();
0168:
0169:            static {
0170:                try {
0171:                    InputStream is6 = new FileInputStream(
0172:                            FLASH6_BUILTINS_PROPERTY_FILE);
0173:                    try {
0174:                        sFlash6Builtins.load(is6);
0175:                    } finally {
0176:                        is6.close();
0177:                    }
0178:
0179:                    InputStream is7 = new FileInputStream(
0180:                            FLASH7_BUILTINS_PROPERTY_FILE);
0181:                    try {
0182:                        sFlash7Builtins.load(is7);
0183:                    } finally {
0184:                        is7.close();
0185:                    }
0186:                } catch (java.io.IOException e) {
0187:                    throw new ChainedException(e);
0188:                }
0189:            }
0190:
0191:            static class CompiledAttribute {
0192:                static final int ATTRIBUTE = 0;
0193:                static final int EVENT = 1;
0194:                static final int REFERENCE = 2;
0195:                static final int PATH = 3;
0196:                static final int STYLE = 4;
0197:
0198:                final int type;
0199:                final Object value;
0200:
0201:                CompiledAttribute(int type, Object value) {
0202:                    this .type = type;
0203:                    this .value = value;
0204:                }
0205:
0206:                CompiledAttribute(Object value) {
0207:                    this (ATTRIBUTE, value);
0208:                }
0209:            }
0210:
0211:            public String toString() {
0212:                StringBuffer buffer = new StringBuffer();
0213:                buffer.append("{NodeModel class=" + className);
0214:                if (!attrs.isEmpty())
0215:                    buffer.append(" attrs=" + attrs.keySet());
0216:                if (!delegates.isEmpty())
0217:                    buffer.append(" delegates=" + delegates.keySet());
0218:                if (!events.isEmpty())
0219:                    buffer.append(" events=" + events.keySet());
0220:                if (!references.isEmpty())
0221:                    buffer.append(" references=" + references.keySet());
0222:                if (!paths.isEmpty())
0223:                    buffer.append(" paths=" + paths.keySet());
0224:                if (!setters.isEmpty())
0225:                    buffer.append(" setters=" + setters.keySet());
0226:                if (!styles.isEmpty())
0227:                    buffer.append(" styles=" + styles.keySet());
0228:                if (!delegateList.isEmpty())
0229:                    buffer.append(" delegateList=" + delegateList);
0230:                if (!children.isEmpty())
0231:                    buffer.append(" children=" + children);
0232:                buffer.append("}");
0233:                return buffer.toString();
0234:            }
0235:
0236:            List getChildren() {
0237:                return children;
0238:            }
0239:
0240:            public static boolean isPropertyElement(Element elt) {
0241:                String name = elt.getName();
0242:                return name.equals("attribute") || name.equals("method")
0243:                        || name.equals("handler") || name.equals("event");
0244:            }
0245:
0246:            /** Returns a name that is used to report this element in warning
0247:             * messages. */
0248:            String getMessageName() {
0249:                return "element " + element.getName();
0250:            }
0251:
0252:            /**
0253:             * Returns a script that creates a runtime representation of a
0254:             * model.  The format of this representation is specified <a
0255:             * href="../../../../doc/compiler/views.html">here</a>.
0256:             *
0257:             */
0258:            public String asJavascript() {
0259:                try {
0260:                    java.io.Writer writer = new java.io.StringWriter();
0261:                    ScriptCompiler.writeObject(this .asMap(), writer);
0262:                    return writer.toString();
0263:                } catch (java.io.IOException e) {
0264:                    throw new ChainedException(e);
0265:                }
0266:            }
0267:
0268:            /** Returns true iff clickable should default to true. */
0269:            private static boolean computeDefaultClickable(ViewSchema schema,
0270:                    Map attrs, Map events, Map delegates) {
0271:                if ("true".equals(attrs.get("cursor"))) {
0272:                    return true;
0273:                }
0274:                for (Iterator iter = events.keySet().iterator(); iter.hasNext();) {
0275:                    String eventName = (String) iter.next();
0276:                    if (schema.isMouseEventAttribute(eventName)) {
0277:                        return true;
0278:                    }
0279:                }
0280:                for (Iterator iter = delegates.keySet().iterator(); iter
0281:                        .hasNext();) {
0282:                    String eventName = (String) iter.next();
0283:                    if (schema.isMouseEventAttribute(eventName)) {
0284:                        return true;
0285:                    }
0286:                }
0287:                return false;
0288:            }
0289:
0290:            /**
0291:             * Returns a NodeModel that represents an Element, including the
0292:             * element's children
0293:             *
0294:             * @param elt an element
0295:             * @param schema a schema, used to encode attribute values
0296:             * @param env the CompilationEnvironment
0297:             */
0298:            public static NodeModel elementAsModel(Element elt,
0299:                    ViewSchema schema, CompilationEnvironment env) {
0300:                return elementAsModelInternal(elt, schema, true, env);
0301:            }
0302:
0303:            /**
0304:             * Returns a NodeModel that represents an Element, excluding the
0305:             * element's children
0306:             *
0307:             * @param elt an element
0308:             * @param schema a schema, used to encode attribute values
0309:             * @param env the CompilationEnvironment
0310:             */
0311:            public static NodeModel elementOnlyAsModel(Element elt,
0312:                    ViewSchema schema, CompilationEnvironment env) {
0313:                return elementAsModelInternal(elt, schema, false, env);
0314:            }
0315:
0316:            /** Returns a NodeModel that represents an Element
0317:             *
0318:             * @param elt an element
0319:             * @param schema a schema, used to encode attribute values
0320:             * @param includeChildren whether or not to include children
0321:             * @param env the CompilationEnvironment
0322:             */
0323:            private static NodeModel elementAsModelInternal(Element elt,
0324:                    ViewSchema schema, boolean includeChildren,
0325:                    CompilationEnvironment env) {
0326:                NodeModel model = new NodeModel(elt, schema, env);
0327:                ComparisonMap attrs = model.attrs;
0328:                Map events = model.events;
0329:                Map delegates = model.delegates;
0330:                model.addAttributes(env);
0331:
0332:                // This emits a local dataset node, so only process
0333:                // <dataset> tags that are not top level datasets.
0334:
0335:                if (elt.getName().equals("dataset")) {
0336:                    boolean contentIsLiteralXMLData = true;
0337:                    String datafromchild = elt
0338:                            .getAttributeValue("datafromchild");
0339:                    String src = elt.getAttributeValue("src");
0340:                    String type = elt.getAttributeValue("type");
0341:
0342:                    if ((type != null && (type.equals("soap") || type
0343:                            .equals("http")))
0344:                            || (src != null && XMLUtils.isURL(src))
0345:                            || "true".equals(datafromchild)) {
0346:                        contentIsLiteralXMLData = false;
0347:                    }
0348:
0349:                    if (contentIsLiteralXMLData) {
0350:                        // Default to legacy behavior, treat all children as XML literal data.
0351:                        attrs.put("initialdata", getDatasetContent(elt, env));
0352:                        includeChildren = false;
0353:                    }
0354:                }
0355:
0356:                if (includeChildren) {
0357:                    model.addChildren(env);
0358:                    model.addText();
0359:                    if (!attrs.containsKey("clickable")
0360:                            && computeDefaultClickable(schema, attrs, events,
0361:                                    delegates)) {
0362:                        attrs.put("clickable", "true");
0363:                    }
0364:                }
0365:                // Record the model in the element for classes
0366:                ((ElementWithLocationInfo) elt).model = model;
0367:                return model;
0368:            }
0369:
0370:            // Calculate how many nodes this object will put on the
0371:            // instantiation queue.
0372:            int totalSubnodes() {
0373:                // A class does not instantiate its subnodes.
0374:                // States override LzNode.thaw to delay subnodes.
0375:                // FIXME [2004-06-3 ows]: This won't work for subclasses
0376:                // of state.
0377:                if (ClassCompiler.isElement(element)
0378:                        || className.equals("state")) {
0379:                    return 1;
0380:                }
0381:                // initstage late, defer delay subnodes
0382:                if (this .initstage != null
0383:                        && (this .initstage == "late" || this .initstage == "defer")) {
0384:                    return 0;
0385:                }
0386:                return this .totalSubnodes;
0387:            }
0388:
0389:            // How many nodes will be inherited from this class
0390:            int classSubnodes() {
0391:                if (ClassCompiler.isElement(element)) {
0392:                    return this .totalSubnodes;
0393:                }
0394:                return 0;
0395:            }
0396:
0397:            ClassModel getClassModel() {
0398:                return schema.getClassModel(this .className);
0399:            }
0400:
0401:            /** Gets the ClassModel for this element's parent class.  If this
0402:             * element is a <class> definition, the superclass; otherwise the
0403:             * class of the tag of this element. */
0404:            ClassModel getParentClassModel() {
0405:                String parentName = this .className;
0406:                return parentName.equals("class") ? schema
0407:                        .getClassModel(element.getAttributeValue("extends"))
0408:                        : schema.getClassModel(parentName);
0409:            }
0410:
0411:            void setClassName(String name) {
0412:                this .className = name;
0413:                this .parentClassModel = getParentClassModel();
0414:            }
0415:
0416:            ViewSchema.Type getAttributeTypeInfoFromParent(Element elt,
0417:                    String attrname) throws UnknownAttributeException {
0418:                Element parent = elt.getParentElement();
0419:                return schema.getAttributeType(parent, attrname);
0420:            }
0421:
0422:            // Should only be called on a <class> definition element.
0423:            ViewSchema.Type getAttributeTypeInfoFromSuperclass(
0424:                    Element classDefElement, String attrname)
0425:                    throws UnknownAttributeException {
0426:                String super classname = classDefElement.getAttributeValue(
0427:                        "extends", ClassCompiler.DEFAULT_SUPERCLASS_NAME);
0428:                ClassModel super classModel = schema
0429:                        .getClassModel(super classname);
0430:
0431:                if (super classModel == null) {
0432:                    throw new CompilationError(
0433:                    /* (non-Javadoc)
0434:                     * @i18n.test
0435:                     * @org-mes="Could not find superclass info for class " + p[0]
0436:                     */
0437:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
0438:                            NodeModel.class.getName(), "051018-411",
0439:                            new Object[] { super classname, classDefElement }));
0440:                }
0441:
0442:                // Check if this attribute is defined on the parent class, if
0443:                // so, return that type
0444:                AttributeSpec attr = super classModel.getAttribute(attrname);
0445:                if (attr != null) {
0446:                    return attr.type;
0447:                }
0448:                // Otherwise, check if it's defined on the "class" element
0449:                // (e.g., 'name' or 'extends')
0450:                super classModel = schema.getClassModel("class");
0451:                return super classModel.getAttributeTypeOrException(attrname);
0452:            }
0453:
0454:            // Get an attribute value, defaulting to the
0455:            // inherited value, or ultimately the supplied default
0456:            String getAttributeValueDefault(String attribute, String name,
0457:                    String defaultValue) {
0458:                // Look for an inherited value
0459:                if (this .parentClassModel != null) {
0460:                    AttributeSpec attrSpec = this .parentClassModel
0461:                            .getAttribute(attribute);
0462:                    if (attrSpec != null) {
0463:                        Element source = attrSpec.source;
0464:                        if (source != null) {
0465:                            return XMLUtils.getAttributeValue(source, name,
0466:                                    defaultValue);
0467:                        }
0468:                    }
0469:                }
0470:
0471:                return defaultValue;
0472:            }
0473:
0474:            /** Is this element a direct child of the canvas? */
0475:            // FIXME [2004-06-03 ows]: Use CompilerUtils.isTopLevel instead.
0476:            // This implementation misses children of <library> and <switch>.
0477:            // Since it's only used for compiler warnings about duplicate
0478:            // names this doesn't break program compilation.
0479:            boolean topLevelDeclaration() {
0480:                Element parent = element.getParentElement();
0481:                if (parent == null) {
0482:                    return false;
0483:                }
0484:                return ("canvas".equals(parent.getName()));
0485:            }
0486:
0487:            void addAttributes(CompilationEnvironment env) {
0488:                // Add source locators, if requested.  Added here because it
0489:                // is not in the schema
0490:                if (env.getBooleanProperty(env.SOURCELOCATOR_PROPERTY)) {
0491:                    String location = "document("
0492:                            + ScriptCompiler.quote(Parser
0493:                                    .getSourceMessagePathname(element)) + ")"
0494:                            + XMLUtils.getXPathTo(element);
0495:                    CompiledAttribute cattr = compileAttribute(element,
0496:                            SOURCE_LOCATION_ATTRIBUTE_NAME, location,
0497:                            ViewSchema.STRING_TYPE, WHEN_IMMEDIATELY);
0498:                    addAttribute(cattr, SOURCE_LOCATION_ATTRIBUTE_NAME, attrs,
0499:                            events, references, paths, styles);
0500:                }
0501:
0502:                // Add file/line information if debugging
0503:                if (env.getBooleanProperty(env.DEBUG_PROPERTY)) {
0504:                    // File/line stored separately for string sharing
0505:                    String name = "_dbg_filename";
0506:                    String filename = Parser.getSourceMessagePathname(element);
0507:                    CompiledAttribute cattr = compileAttribute(element, name,
0508:                            filename, ViewSchema.STRING_TYPE, WHEN_IMMEDIATELY);
0509:                    addAttribute(cattr, name, attrs, events, references, paths,
0510:                            styles);
0511:                    name = "_dbg_lineno";
0512:                    Integer lineno = Parser.getSourceLocation(element,
0513:                            Parser.LINENO);
0514:                    cattr = compileAttribute(element, name, lineno.toString(),
0515:                            ViewSchema.NUMBER_TYPE, WHEN_IMMEDIATELY);
0516:                    addAttribute(cattr, name, attrs, events, references, paths,
0517:                            styles);
0518:                }
0519:
0520:                ClassModel classModel = getClassModel();
0521:                if (classModel == null) {
0522:                    throw new CompilationError(
0523:                            "Could not find class definition for tag `"
0524:                                    + className + "`", element);
0525:                }
0526:                // Encode the attributes
0527:                for (Iterator iter = element.getAttributes().iterator(); iter
0528:                        .hasNext();) {
0529:                    Attribute attr = (Attribute) iter.next();
0530:                    Namespace ns = attr.getNamespace();
0531:                    String name = attr.getName();
0532:                    String value = element.getAttributeValue(name, ns);
0533:
0534:                    if (name.equals(FONTSTYLE_ATTRIBUTE)) {
0535:                        // "bold italic", "italic bold" -> "bolditalic"
0536:                        value = FontInfo.normalizeStyleString(value, false);
0537:                    }
0538:
0539:                    if (name.toLowerCase().equals("defaultplacement")) {
0540:                        if (value != null
0541:                                && value.matches("\\s*['\"]\\S*['\"]\\s*")) {
0542:                            String oldValue = value;
0543:                            // strip off start and ending quotes;
0544:                            value = value.trim();
0545:                            value = value.substring(1, value.length() - 1);
0546:                            env.warn(
0547:                            /* (non-Javadoc)
0548:                             * @i18n.test
0549:                             * @org-mes="Replacing defaultPlacement=\"" + p[0] + "\" by \"" + p[1] + "\".  For future compatibility" + ", you should make this change to your source code."
0550:                             */
0551:                            org.openlaszlo.i18n.LaszloMessages.getMessage(
0552:                                    NodeModel.class.getName(), "051018-513",
0553:                                    new Object[] { oldValue, value }), element);
0554:                        }
0555:                    }
0556:
0557:                    // Warn for redefine of a flash builtin
0558:                    // TODO: [2006-01-23 ptw] What about colliding with DHTML globals?
0559:                    if ((name.equals("id") || name.equals("name"))
0560:                            && (value != null
0561:                                    && (env.getRuntime().indexOf("swf") == 0) && ("swf6"
0562:                                    .equals(env.getRuntime()) ? sFlash6Builtins
0563:                                    .containsKey(value.toLowerCase())
0564:                                    : sFlash7Builtins.containsKey(value)))) {
0565:                        env.warn(
0566:                        /* (non-Javadoc)
0567:                         * @i18n.test
0568:                         * @org-mes="You have given the " + p[0] + " an attribute " + p[1] + "=\"" + p[2] + "\", " + "which may overwrite the Flash builtin class named \"" + p[3] + "\"."
0569:                         */
0570:                        org.openlaszlo.i18n.LaszloMessages.getMessage(
0571:                                NodeModel.class.getName(), "051018-532",
0572:                                new Object[] { getMessageName(), name, value,
0573:                                        value }), element);
0574:
0575:                    }
0576:
0577:                    // Catch duplicated id/name attributes which may shadow
0578:                    // each other or overwrite each other.  An id/name will be
0579:                    // global there is "id='foo'" or if "name='foo'" at the
0580:                    // top level (immediate child of the canvas).
0581:                    //
0582:                    if ((name.equals("id"))
0583:                            || (name.equals("name") && topLevelDeclaration() && !className
0584:                                    .equals("class"))) {
0585:
0586:                        ClassModel super classModel = schema
0587:                                .getClassModel(value);
0588:                        if (super classModel != null
0589:                                && !super classModel.isBuiltin()) {
0590:                            env.warn(
0591:                            /* (non-Javadoc)
0592:                             * @i18n.test
0593:                             * @org-mes="You have given the " + p[0] + " an attribute " + p[1] + "=\"" + p[2] + "\", " + "which may overwrite the class \"" + p[3] + "\"."
0594:                             */
0595:                            org.openlaszlo.i18n.LaszloMessages.getMessage(
0596:                                    NodeModel.class.getName(), "051018-559",
0597:                                    new Object[] { getMessageName(), name,
0598:                                            value, value }), element);
0599:                        } else {
0600:                            ElementWithLocationInfo dup = (ElementWithLocationInfo) env
0601:                                    .getId(value);
0602:                            // we don't want to give a warning in the case
0603:                            // where the id and name are on the same element,
0604:                            // i.e., <view id="foo" name="foo"/>
0605:                            if (dup != null && dup != element) {
0606:                                String locstring = CompilerUtils
0607:                                        .sourceLocationPrettyString(dup);
0608:                                env.warn(
0609:                                /* (non-Javadoc)
0610:                                 * @i18n.test
0611:                                 * @org-mes="Duplicate id attribute \"" + p[0] + "\" at " + p[1]
0612:                                 */
0613:                                org.openlaszlo.i18n.LaszloMessages.getMessage(
0614:                                        NodeModel.class.getName(),
0615:                                        "051018-576", new Object[] { value,
0616:                                                locstring }), element);
0617:                            } else {
0618:                                // TODO: [07-18-03 hqm] We will canonicalize
0619:                                // all id's to lowercase, because actionscript
0620:                                // is not case sensitive.  but in the future,
0621:                                // we should preserve case.
0622:                                env.addId(value, element);
0623:                            }
0624:                        }
0625:                    }
0626:
0627:                    Schema.Type type;
0628:                    try {
0629:                        if (className.equals("class")) {
0630:                            // Special case, if we are compiling a "class"
0631:                            // tag, then get the type of attributes from the
0632:                            // superclass.
0633:                            type = getAttributeTypeInfoFromSuperclass(element,
0634:                                    name);
0635:                        } else if (className.equals("state")) {
0636:                            // Special case for "state", it can have any attribute
0637:                            // which belongs to the parent. 
0638:                            try {
0639:                                type = schema.getAttributeType(element, name);
0640:                            } catch (UnknownAttributeException e) {
0641:                                type = getAttributeTypeInfoFromParent(element,
0642:                                        name);
0643:                            }
0644:                        } else {
0645:                            // NOTE [2007-06-14 ptw]: Querying the classModel
0646:                            // directly will NOT work, because the schema
0647:                            // method has some special kludges in it for canvas
0648:                            // width and height!
0649:                            type = schema.getAttributeType(element, name);
0650:                        }
0651:
0652:                    } catch (UnknownAttributeException e) {
0653:                        String solution;
0654:                        AttributeSpec alt = schema.findSimilarAttribute(
0655:                                className, name);
0656:                        if (alt != null) {
0657:                            String classmessage = "";
0658:                            if (alt.source != null) {
0659:                                classmessage = " on class "
0660:                                        + alt.source.getName() + "\"";
0661:                            } else {
0662:                                classmessage = " on class " + getMessageName();
0663:                            }
0664:                            solution =
0665:                            /* (non-Javadoc)
0666:                             * @i18n.test
0667:                             * @org-mes="found an unknown attribute named \"" + p[0] + "\" on " + p[1] + ", however there is an attribute named \"" + p[2] + "\"" + p[3] + ", did you mean to use that?"
0668:                             */
0669:                            org.openlaszlo.i18n.LaszloMessages.getMessage(
0670:                                    NodeModel.class.getName(), "051018-616",
0671:                                    new Object[] { name, getMessageName(),
0672:                                            alt.name, classmessage });
0673:                        } else {
0674:                            solution =
0675:                            /* (non-Javadoc)
0676:                             * @i18n.test
0677:                             * @org-mes="found an unknown attribute named \"" + p[0] + "\" on " + p[1] + ", check the spelling of this attribute name"
0678:                             */
0679:                            org.openlaszlo.i18n.LaszloMessages.getMessage(
0680:                                    NodeModel.class.getName(), "051018-624",
0681:                                    new Object[] { name, getMessageName() });
0682:                        }
0683:                        env.warn(solution, element);
0684:                        type = ViewSchema.EXPRESSION_TYPE;
0685:                    }
0686:
0687:                    if (type == schema.ID_TYPE) {
0688:                        this .id = value;
0689:                    } else if (type == schema.EVENT_HANDLER_TYPE) {
0690:                        addHandlerFromAttribute(element, name, value);
0691:                    } else {
0692:                        String when = this .getAttributeValueDefault(name,
0693:                                "when", WHEN_IMMEDIATELY);
0694:                        try {
0695:                            CompiledAttribute cattr = compileAttribute(element,
0696:                                    name, value, type, when);
0697:                            addAttribute(cattr, name, attrs, events,
0698:                                    references, paths, styles);
0699:                            // Check if we are aliasing another 'name'
0700:                            // attribute of a sibling
0701:                            if (name.equals("name")) {
0702:                                Element parent = element.getParentElement();
0703:                                if (parent != null) {
0704:                                    for (Iterator iter2 = parent.getChildren()
0705:                                            .iterator(); iter2.hasNext();) {
0706:                                        Element e = (Element) iter2.next();
0707:                                        if (!e.getName().equals("resource")
0708:                                                && !e.getName().equals("font")
0709:                                                && e != element
0710:                                                && value
0711:                                                        .equals(e
0712:                                                                .getAttributeValue("name"))) {
0713:                                            String dup_location = CompilerUtils
0714:                                                    .sourceLocationPrettyString(e);
0715:                                            env
0716:                                                    .warn(
0717:                                                            /* (non-Javadoc)
0718:                                                             * @i18n.test
0719:                                                             * @org-mes=p[0] + " has the same name=\"" + p[1] + "\" attribute as a sibling element at " + p[2]
0720:                                                             */
0721:                                                            org.openlaszlo.i18n.LaszloMessages
0722:                                                                    .getMessage(
0723:                                                                            NodeModel.class
0724:                                                                                    .getName(),
0725:                                                                            "051018-658",
0726:                                                                            new Object[] {
0727:                                                                                    getMessageName(),
0728:                                                                                    value,
0729:                                                                                    dup_location }),
0730:                                                            element);
0731:                                        }
0732:                                    }
0733:                                }
0734:                            }
0735:                        } catch (CompilationError e) {
0736:                            env.warn(e);
0737:                        }
0738:                    }
0739:                }
0740:            }
0741:
0742:            void addAttribute(CompiledAttribute cattr, String name,
0743:                    ComparisonMap attrs, ComparisonMap events,
0744:                    ComparisonMap references, ComparisonMap paths,
0745:                    ComparisonMap styles) {
0746:                if (cattr.type == cattr.ATTRIBUTE || cattr.type == cattr.EVENT) {
0747:                    if (attrs.containsKey(name, caseSensitive)) {
0748:                        env.warn(
0749:                        /* (non-Javadoc)
0750:                         * @i18n.test
0751:                         * @org-mes="an attribute or method named '" + p[0] + "' already is defined on " + p[1]
0752:                         */
0753:                        org.openlaszlo.i18n.LaszloMessages.getMessage(
0754:                                NodeModel.class.getName(), "051018-682",
0755:                                new Object[] { name, getMessageName() }),
0756:                                element);
0757:                    }
0758:                    attrs.put(name, cattr.value);
0759:                } else if ((cattr.type == cattr.REFERENCE)
0760:                        || (cattr.type == cattr.PATH)) {
0761:                    if (references.containsKey(name, caseSensitive)) {
0762:                        env.warn(
0763:                        /* (non-Javadoc)
0764:                         * @i18n.test
0765:                         * @org-mes="redefining reference '" + p[0] + "' which has already been defined on " + p[1]
0766:                         */
0767:                        org.openlaszlo.i18n.LaszloMessages.getMessage(
0768:                                NodeModel.class.getName(), "051018-706",
0769:                                new Object[] { name, getMessageName() }),
0770:                                element);
0771:                    }
0772:                    references.put(name, cattr.value);
0773:                } else if (cattr.type == cattr.STYLE) {
0774:                    if (styles.containsKey(name, caseSensitive)) {
0775:                        env.warn(
0776:                        // TODO [2006-08-22 ptw] i18n this
0777:                                "duplicate $style binding for '" + name
0778:                                        + "' in " + getMessageName(), element);
0779:                    }
0780:                    styles.put(name, cattr.value);
0781:                }
0782:            }
0783:
0784:            static String getDatasetContent(Element element,
0785:                    CompilationEnvironment env) {
0786:                return getDatasetContent(element, env, false);
0787:            }
0788:
0789:            // For a dataset (well really for any Element), writes out the
0790:            // child literal content as an escaped string, which could be used
0791:            // to initialize the dataset at runtime.
0792:            static String getDatasetContent(Element element,
0793:                    CompilationEnvironment env, boolean trimwhitespace) {
0794:                String srcloc = CompilerUtils.sourceLocationDirective(element,
0795:                        true);
0796:
0797:                // If type='http' or the path starts with http: or https:,
0798:                // then don't attempt to include the data at compile
0799:                // time. The runtime will have to recognize it as runtime
0800:                // loaded URL data.
0801:
0802:                if ("http".equals(element.getAttributeValue("type"))) {
0803:                    return "null";
0804:                }
0805:
0806:                boolean nsprefix = false;
0807:                if ("true".equals(element.getAttributeValue("nsprefix"))) {
0808:                    nsprefix = true;
0809:                }
0810:
0811:                Element content = new Element("data");
0812:
0813:                String src = element.getAttributeValue("src");
0814:                // If 'src' attribute is a URL or null, don't try to expand it now,
0815:                // just return. The LFC will have to interpret it as a runtime
0816:                // loadable data URL.
0817:                if ((src != null)
0818:                        && (src.startsWith("http:") || src.startsWith("https:"))) {
0819:                    return "null";
0820:                } else if (src != null) {
0821:                    // Expands the src file content inline
0822:                    File file = env.resolveReference(element);
0823:                    try {
0824:                        Element literaldata = new org.jdom.input.SAXBuilder(
0825:                                false).build(file).getRootElement();
0826:                        if (literaldata == null) {
0827:                            return "null";
0828:                        }
0829:                        literaldata.detach();
0830:                        // add the expanded file contents as child node
0831:                        content.addContent(literaldata);
0832:                    } catch (org.jdom.JDOMException e) {
0833:                        throw new CompilationError(e);
0834:                    } catch (IOException e) {
0835:                        throw new CompilationError(e);
0836:                    } catch (java.lang.OutOfMemoryError e) {
0837:                        // The runtime gc is necessary in order for subsequent
0838:                        // compiles to succeed.  The System gc is for good
0839:                        // luck.
0840:                        throw new CompilationError(
0841:                        /* (non-Javadoc)
0842:                         * @i18n.test
0843:                         * @org-mes="out of memory"
0844:                         */
0845:                        org.openlaszlo.i18n.LaszloMessages.getMessage(
0846:                                NodeModel.class.getName(), "051018-761"),
0847:                                element);
0848:                    }
0849:                } else {
0850:                    // no 'src' attribute, use element inline content
0851:                    content.addContent(element.cloneContent());
0852:                }
0853:
0854:                // Serialize the child elements, as the local data
0855:                org.jdom.output.XMLOutputter xmloutputter = new org.jdom.output.XMLOutputter();
0856:                // strip the <dataset> wrapper
0857:
0858:                // If nsprefix is false, remove namespace from elements before
0859:                // serializing, or XMLOutputter puts a "xmlns" attribute on
0860:                // the top element in the serialized string.
0861:
0862:                if (!nsprefix) {
0863:                    removeNamespaces(content);
0864:                }
0865:
0866:                if (trimwhitespace) {
0867:                    trimWhitespace(content);
0868:                }
0869:
0870:                String body = null;
0871:                if (content != null) {
0872:                    body = xmloutputter.outputString(content);
0873:                    return ScriptCompiler.quote(body);
0874:                } else {
0875:                    return "null";
0876:                }
0877:
0878:            }
0879:
0880:            // Recursively null out the namespace on elt and children
0881:            static void removeNamespaces(Element elt) {
0882:                elt.setNamespace(null);
0883:                for (Iterator iter = elt.getChildren().iterator(); iter
0884:                        .hasNext();) {
0885:                    Element child = (Element) iter.next();
0886:                    removeNamespaces(child);
0887:                }
0888:            }
0889:
0890:            // Recursively trim out the whitespace on text nodes
0891:            static void trimWhitespace(Content elt) {
0892:                if (elt instanceof  Text) {
0893:                    ((Text) elt).setText(((Text) elt).getTextTrim());
0894:                } else if (elt instanceof  Element) {
0895:                    for (Iterator iter = ((Element) elt).getContent()
0896:                            .iterator(); iter.hasNext();) {
0897:                        Content child = (Content) iter.next();
0898:                        trimWhitespace(child);
0899:                    }
0900:                }
0901:            }
0902:
0903:            boolean isDatapathElement(Element child) {
0904:                return (child.getName().equals("datapath"));
0905:            }
0906:
0907:            /** Warn if named child tag conflicts with a declared attribute in the parent class.
0908:             */
0909:            void checkChildNameConflict(String parentName, Element child,
0910:                    CompilationEnvironment env) {
0911:                String attrName = child.getAttributeValue("name");
0912:                if (attrName != null) {
0913:                    AttributeSpec attrSpec = schema.getClassAttribute(
0914:                            parentName, attrName);
0915:                    // Only warn if the attribute we are shadowing has a declared initial value.
0916:                    if (attrSpec != null && attrSpec.defaultValue != null) {
0917:                        // TODO [2007-09-26 hqm] i18n this
0918:                        env.warn("Child tag '" + child.getName()
0919:                                + "' with attribute '" + attrName
0920:                                + "' conflicts with attribute named '"
0921:                                + attrName + "' of type '" + attrSpec.type
0922:                                + "' on parent tag '" + element.getName()
0923:                                + "'.", element);
0924:                    }
0925:                }
0926:            }
0927:
0928:            void addChildren(CompilationEnvironment env) {
0929:                // Encode the children
0930:                for (Iterator iter = element.getChildren().iterator(); iter
0931:                        .hasNext();) {
0932:                    ElementWithLocationInfo child = (ElementWithLocationInfo) iter
0933:                            .next();
0934:                    if (!schema.canContainElement(element.getName(), child
0935:                            .getName())) {
0936:                        // If this element is allowed to contain  HTML content, then
0937:                        // we don't want to warn about encountering an HTML child element.
0938:                        if (!(schema.hasTextContent(element) && schema
0939:                                .isHTMLElement(child))) {
0940:                            env.warn(
0941:                            // TODO [2007-09-26 hqm] i18n this
0942:                                    "The tag '" + child.getName()
0943:                                            + "' cannot be used as a child of "
0944:                                            + element.getName(), element);
0945:                        }
0946:                    }
0947:                    try {
0948:                        if (child.getName().equals("data")) {
0949:                            checkChildNameConflict(element.getName(), child,
0950:                                    env);
0951:                            // literal data
0952:                            addLiteralDataElement(child);
0953:                        } else if (isPropertyElement(child)) {
0954:                            addPropertyElement(child);
0955:                        } else if (schema.isHTMLElement(child)) {
0956:                            ; // ignore; the text compiler wiil handle this
0957:                        } else if (schema.isDocElement(child)) {
0958:                            ; // ignore doc nodes.
0959:                        } else if (isDatapathElement(child)) {
0960:                            checkChildNameConflict(element.getName(), child,
0961:                                    env);
0962:                            NodeModel dpnode = elementAsModel(child, schema,
0963:                                    env);
0964:                            this .datapath = dpnode;
0965:                        } else {
0966:                            checkChildNameConflict(element.getName(), child,
0967:                                    env);
0968:                            NodeModel childModel = elementAsModel(child,
0969:                                    schema, env);
0970:                            children.add(childModel);
0971:                            totalSubnodes += childModel.totalSubnodes();
0972:                        }
0973:                    } catch (CompilationError e) {
0974:                        env.warn(e);
0975:                    }
0976:                }
0977:            }
0978:
0979:            void addPropertyElement(Element element) {
0980:                String tagName = element.getName();
0981:                if (tagName.equals("method")) {
0982:                    addMethodElement(element);
0983:                } else if (tagName.equals("handler")) {
0984:                    addHandlerElement(element);
0985:                } else if (tagName.equals("event")) {
0986:                    addEventElement(element);
0987:                } else if (tagName.equals("attribute")) {
0988:                    addAttributeElement(element);
0989:                }
0990:            }
0991:
0992:            /** Defines an event handler.
0993:             *
0994:             * <handler name="eventname" [method="methodname"]>
0995:             *   [function body]
0996:             * </handler>
0997:             *
0998:             * This can do a compile time check to see if eventname is declared or
0999:             * if there is an attribute FOO such that name="onFOO".
1000:             */
1001:
1002:            void addHandlerElement(Element element) {
1003:                String srcloc = CompilerUtils.sourceLocationDirective(element,
1004:                        true);
1005:                String method = element.getAttributeValue("method");
1006:                // event name
1007:                String event = element.getAttributeValue("name");
1008:                String args = CompilerUtils.attributeLocationDirective(element,
1009:                        "args")
1010:                        + XMLUtils.getAttributeValue(element, "args", "");
1011:                if ((event == null || !ScriptCompiler.isIdentifier(event))) {
1012:                    env.warn("handler needs a non-null name attribute");
1013:                    return;
1014:                }
1015:
1016:                String parent_name = element.getParentElement()
1017:                        .getAttributeValue("id");
1018:                String name_loc = CompilerUtils.attributeLocationDirective(
1019:                        element, "event");
1020:                if (parent_name == null) {
1021:                    parent_name = CompilerUtils.attributeUniqueName(element,
1022:                            "event");
1023:                }
1024:                // Names have to be unique across binary libraries, so append
1025:                // parent name
1026:                String name = env.methodNameGenerator.next() + "_"
1027:                        + parent_name + "_reference";
1028:                String reference = element.getAttributeValue("reference");
1029:                Object referencefn = "null";
1030:                if (reference != null) {
1031:                    String ref_loc = CompilerUtils.attributeLocationDirective(
1032:                            element, "reference");
1033:                    referencefn = new Function(name, args,
1034:                            "\n#pragma 'withThis'\n" + "return ("
1035:                                    + "#beginAttribute\n" + ref_loc + reference
1036:                                    + "\n#endAttribute\n)", ref_loc);
1037:                }
1038:
1039:                // delegates is only used to determine whether to
1040:                // default clickable to true.  Clickable should only
1041:                // default to true if the event handler is attached to
1042:                // this view.
1043:                if (reference == null) {
1044:                    delegates.put(event, Boolean.TRUE);
1045:                }
1046:                delegateList.add(ScriptCompiler.quote(event));
1047:                if (method != null) {
1048:                    delegateList.add(ScriptCompiler.quote(method));
1049:                } else {
1050:                    delegateList.add(ScriptCompiler.quote(name));
1051:                }
1052:                delegateList.add(referencefn);
1053:
1054:                String body = element.getText();
1055:
1056:                String childcontentloc = CompilerUtils.sourceLocationDirective(
1057:                        element, true);
1058:
1059:                if (attrs.containsKey(name, caseSensitive)) {
1060:                    env.warn("an attribute or method named '" + name
1061:                            + "' already is defined on " + getMessageName(),
1062:                            element);
1063:                }
1064:
1065:                // If non-empty body AND method name are specified, flag an error
1066:                // If non-empty body, pack it up as a function definition
1067:                if (body != null && body.trim().length() > 0) {
1068:                    if (method != null) {
1069:                        env
1070:                                .warn(
1071:                                        "you cannot declare both a 'method' attribute "
1072:                                                + "*and* a function body on a handler element",
1073:                                        element);
1074:                    }
1075:                }
1076:                Function fndef = new Function(name,
1077:                //"#beginAttribute\n" +
1078:                        CompilerUtils.attributeLocationDirective(element,
1079:                                "args")
1080:                                + args, "\n#beginContent\n"
1081:                                + "\n#pragma 'methodName=" + name + "'\n"
1082:                                + "\n#pragma 'withThis'\n" + childcontentloc
1083:                                + body + "\n#endContent", name_loc);
1084:
1085:                attrs.put(name, fndef);
1086:            }
1087:
1088:            void addHandlerFromAttribute(Element element, String event,
1089:                    String body) {
1090:                String srcloc = CompilerUtils.sourceLocationDirective(element,
1091:                        true);
1092:                String parent_name = element.getAttributeValue("id");
1093:                if (parent_name == null) {
1094:                    parent_name = CompilerUtils.attributeUniqueName(element,
1095:                            "event");
1096:                }
1097:                String name = env.methodNameGenerator.next();
1098:                Object referencefn = "null";
1099:
1100:                // delegates is only used to determine whether to
1101:                // default clickable to true.  Clickable should only
1102:                // default to true if the event handler is attached to
1103:                // this view.
1104:                delegates.put(event, Boolean.TRUE);
1105:                delegateList.add(ScriptCompiler.quote(event));
1106:                delegateList.add(ScriptCompiler.quote(name));
1107:                delegateList.add(referencefn);
1108:
1109:                String childcontentloc = CompilerUtils.sourceLocationDirective(
1110:                        element, true);
1111:
1112:                Function fndef = new
1113:                // Use "mangled" name, so it will be unique
1114:                Function(srcloc + parent_name + "_" + name,
1115:                //"#beginAttribute\n" +
1116:                        "", "\n#beginContent\n" + "\n#pragma 'methodName="
1117:                                + name + "'\n" + "\n#pragma 'withThis'\n"
1118:                                + childcontentloc + body + "\n#endContent");
1119:
1120:                attrs.put(name, fndef);
1121:            }
1122:
1123:            void addMethodElement(Element element) {
1124:                String srcloc = CompilerUtils.sourceLocationDirective(element,
1125:                        true);
1126:                String name = element.getAttributeValue("name");
1127:                String event = element.getAttributeValue("event");
1128:                String args = XMLUtils.getAttributeValue(element, "args", "");
1129:                String override = element.getAttributeValue("override");
1130:
1131:                if ((name == null || !ScriptCompiler.isIdentifier(name))
1132:                        && (event == null || !ScriptCompiler
1133:                                .isIdentifier(event))) {
1134:                    env.warn(
1135:                    /* (non-Javadoc)
1136:                     * @i18n.test
1137:                     * @org-mes="method needs a non-null name or event attribute"
1138:                     */
1139:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1140:                            NodeModel.class.getName(), "051018-832"));
1141:                    return;
1142:                }
1143:                if (name != null && sDeprecatedMethods.containsKey(name)) {
1144:                    String oldName = name;
1145:                    String newName = (String) sDeprecatedMethods.get(name);
1146:                    name = newName;
1147:                    env.warn(
1148:                    /* (non-Javadoc)
1149:                     * @i18n.test
1150:                     * @org-mes=p[0] + " is deprecated.  " + "This method will be compiled as <method name='" + p[1] + "' instead.  " + "Please update your sources."
1151:                     */
1152:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1153:                            NodeModel.class.getName(), "051018-846",
1154:                            new Object[] { oldName, newName }), element);
1155:                }
1156:
1157:                String parent_name = element.getParentElement()
1158:                        .getAttributeValue("id");
1159:                String name_loc = (name == null ? CompilerUtils
1160:                        .attributeLocationDirective(element, "event")
1161:                        : CompilerUtils.attributeLocationDirective(element,
1162:                                "name"));
1163:                if (parent_name == null) {
1164:                    parent_name = (name == null ? CompilerUtils
1165:                            .attributeUniqueName(element, "event")
1166:                            : CompilerUtils
1167:                                    .attributeUniqueName(element, "name"));
1168:                }
1169:                if (event != null) {
1170:                    if (name == null) {
1171:                        // Names have to be unique across binary libraries, so
1172:                        // append parent name
1173:                        name = env.methodNameGenerator.next() + "_"
1174:                                + parent_name + "_reference";
1175:                    }
1176:                    String reference = element.getAttributeValue("reference");
1177:                    Object referencefn = "null";
1178:                    if (reference != null) {
1179:                        String ref_loc = CompilerUtils
1180:                                .attributeLocationDirective(element,
1181:                                        "reference");
1182:                        referencefn = new Function(name, CompilerUtils
1183:                                .attributeLocationDirective(element, "args")
1184:                                + args, "\n#pragma 'withThis'\n" + "return ("
1185:                                + "#beginAttribute\n" + ref_loc + reference
1186:                                + "\n#endAttribute\n)", ref_loc);
1187:                    }
1188:                    // delegates is only used to determine whether to
1189:                    // default clickable to true.  Clickable should only
1190:                    // default to true if the event handler is attached to
1191:                    // this view.
1192:                    if (reference == null)
1193:                        delegates.put(event, Boolean.TRUE);
1194:                    delegateList.add(ScriptCompiler.quote(event));
1195:                    delegateList.add(ScriptCompiler.quote(name));
1196:                    delegateList.add(referencefn);
1197:                }
1198:                String body = element.getText();
1199:
1200:                String childcontentloc = CompilerUtils.sourceLocationDirective(
1201:                        element, true);
1202:                Function fndef = new Function(name,
1203:                //"#beginAttribute\n" +
1204:                        CompilerUtils.attributeLocationDirective(element,
1205:                                "args")
1206:                                + args, "\n#beginContent\n"
1207:                                + "\n#pragma 'methodName=" + name + "'\n"
1208:                                + "\n#pragma 'withThis'\n" + childcontentloc
1209:                                + body + "\n#endContent", name_loc);
1210:
1211:                if (attrs.containsKey(name, caseSensitive)) {
1212:                    env.warn(
1213:                    /* (non-Javadoc)
1214:                     * @i18n.test
1215:                     * @org-mes="an attribute or method named '" + p[0] + "' already is defined on " + p[1]
1216:                     */
1217:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1218:                            NodeModel.class.getName(), "051018-922",
1219:                            new Object[] { name, getMessageName() }), element);
1220:                }
1221:
1222:                if (!("true".equals(override))) {
1223:                    String classname = element.getParentElement().getName();
1224:                    // Just check method declarations on regular node.
1225:                    // Method declarations inside of class definitions will be already checked elsewhere,
1226:                    // in the call from ClassCompiler.updateSchema to schema.addElement
1227:                    if (!"class".equals(classname)) {
1228:                        schema.checkInstanceMethodDeclaration(element,
1229:                                classname, name, env);
1230:                    }
1231:                }
1232:
1233:                attrs.put(name, fndef);
1234:            }
1235:
1236:            // Pattern matcher for '$once{...}' style constraints
1237:            Pattern constraintPat = Pattern
1238:                    .compile("^\\s*\\$(\\w*)\\s*\\{(.*)\\}\\s*");
1239:
1240:            CompiledAttribute compileAttribute(Element source, String name,
1241:                    String value, Schema.Type type, String when) {
1242:
1243:                String srcloc = CompilerUtils.sourceLocationDirective(source,
1244:                        true);
1245:                String parent_name = source.getAttributeValue("id");
1246:                if (parent_name == null) {
1247:                    parent_name = CompilerUtils.attributeUniqueName(source,
1248:                            name);
1249:                }
1250:                // Some values are not canonicalized to String
1251:                Object canonicalValue = null;
1252:                boolean warnOnDeprecatedConstraints = true;
1253:
1254:                if (value == null) {
1255:                    throw new RuntimeException(
1256:                    /* (non-Javadoc)
1257:                     * @i18n.test
1258:                     * @org-mes="value is null in " + p[0]
1259:                     */
1260:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1261:                            NodeModel.class.getName(), "051018-956",
1262:                            new Object[] { source }));
1263:                }
1264:
1265:                Matcher m = constraintPat.matcher(value);
1266:                // value.matches("\\s*['\"]\\S*['\"]\\s*")
1267:                if (value.matches("\\s*\\$\\s*\\(")) {
1268:                    env
1269:                            .warn(
1270:                                    "The syntax '$(...)' is not valid, "
1271:                                            + "you probably meant to use curly-braces instead '${...}'",
1272:                                    source);
1273:                } else if (m.matches()) {
1274:                    // extract out $when{value}
1275:                    when = m.group(1);
1276:                    value = m.group(2);
1277:                    // Expressions override any when value, default is
1278:                    // constraint
1279:                    if (when.equals("")) {
1280:                        when = WHEN_ALWAYS;
1281:                    }
1282:                } else if (type == ViewSchema.XML_LITERAL) {
1283:                    value = "LzDataNode.stringToLzData(" + value + ")";
1284:                } else if (type == ViewSchema.COLOR_TYPE) {
1285:                    if (when.equals(WHEN_IMMEDIATELY)) {
1286:                        try {
1287:                            value = "0x"
1288:                                    + Integer.toHexString(ViewSchema
1289:                                            .parseColor(value));
1290:                        } catch (ColorFormatException e) {
1291:                            // Or just set when to WHEN_ONCE and fall
1292:                            // through to TODO?
1293:                            throw new CompilationError(source, name, e);
1294:                        }
1295:                    }
1296:                    // TODO: [2003-05-02 ptw] Wrap non-constant colors in
1297:                    // runtime parser
1298:                } else if (type == ViewSchema.CSS_TYPE) {
1299:                    if (when.equals(WHEN_IMMEDIATELY)) {
1300:                        try {
1301:                            Map cssProperties = new CSSParser(
1302:                                    new AttributeStream(source, name, value))
1303:                                    .Parse();
1304:                            for (Iterator i2 = cssProperties.entrySet()
1305:                                    .iterator(); i2.hasNext();) {
1306:                                Map.Entry entry = (Map.Entry) i2.next();
1307:                                Object mv = entry.getValue();
1308:                                if (mv instanceof  String) {
1309:                                    entry.setValue(ScriptCompiler
1310:                                            .quote((String) mv));
1311:                                }
1312:                            }
1313:                            canonicalValue = cssProperties;
1314:                        } catch (org.openlaszlo.css.ParseException e) {
1315:                            // Or just set when to WHEN_ONCE and fall
1316:                            // through to TODO?
1317:                            throw new CompilationError(e);
1318:                        } catch (org.openlaszlo.css.TokenMgrError e) {
1319:                            // Or just set when to WHEN_ONCE and fall
1320:                            // through to TODO?
1321:                            throw new CompilationError(e);
1322:                        }
1323:                    }
1324:                    // TODO: [2003-05-02 ptw] Wrap non-constant styles in
1325:                    // runtime parser
1326:                } else if (type == ViewSchema.STRING_TYPE
1327:                        || type == ViewSchema.TOKEN_TYPE
1328:                        || type == ViewSchema.ID_TYPE) {
1329:                    // Immediate string attributes are auto-quoted
1330:                    if (when.equals(WHEN_IMMEDIATELY)) {
1331:                        value = ScriptCompiler.quote(value);
1332:                    }
1333:                } else if ((type == ViewSchema.EXPRESSION_TYPE)
1334:                        || (type == ViewSchema.BOOLEAN_TYPE)) {
1335:                    // No change currently, possibly analyze expressions
1336:                    // and default non-constant to when="once" in the
1337:                    // future
1338:                } else if (type == ViewSchema.INHERITABLE_BOOLEAN_TYPE) {
1339:                    // change "inherit" to null and pass true/false through as expression
1340:                    if ("inherit".equals(value)) {
1341:                        value = "null";
1342:                    } else if ("true".equals(value)) {
1343:                        value = "true";
1344:                    } else if ("false".equals(value)) {
1345:                        value = "false";
1346:                    } else {
1347:                        // TODO [hqm 2007-0] i8nalize this message
1348:                        env
1349:                                .warn(
1350:                                        "attribute '"
1351:                                                + name
1352:                                                + "' must have the value 'true', 'false', or 'inherit'",
1353:                                        element);
1354:                    }
1355:                } else if (type == ViewSchema.NUMBER_TYPE) {
1356:                    // No change currently, possibly analyze expressions
1357:                    // and default non-constant to when="once" in the
1358:                    // future
1359:                } else if (type == ViewSchema.NUMBER_EXPRESSION_TYPE
1360:                        || type == ViewSchema.SIZE_EXPRESSION_TYPE) {
1361:                    // if it's a number that ends in percent:
1362:                    if (value.trim().endsWith("%")) {
1363:                        String numstr = value.trim();
1364:                        numstr = numstr.substring(0, numstr.length() - 1);
1365:                        try {
1366:                            double scale = new Float(numstr).floatValue() / 100.0;
1367:                            warnOnDeprecatedConstraints = false;
1368:                            String referenceAttribute = name;
1369:                            if (name.equals("x")) {
1370:                                referenceAttribute = "width";
1371:                            } else if (name.equals("y")) {
1372:                                referenceAttribute = "height";
1373:                            }
1374:                            value = "immediateparent." + referenceAttribute;
1375:                            if (scale != 1.0) {
1376:                                // This special case doesn't change the
1377:                                // semantics, but it generates shorter (since
1378:                                // the sc doesn't fold constants) and more
1379:                                // debuggable code
1380:                                value += "\n * " + scale;
1381:                            }
1382:                            // fall through to the reference case
1383:                        } catch (NumberFormatException e) {
1384:                            // fall through
1385:                        }
1386:                    }
1387:                    // if it's a literal, treat it the same as a number
1388:                    try {
1389:                        new Float(value); // for effect, to generate the exception
1390:                        when = WHEN_IMMEDIATELY;
1391:                    } catch (NumberFormatException e) {
1392:                        // It's not a constant, unless when has been
1393:                        // specified, default to a constraint
1394:                        if (when.equals(WHEN_IMMEDIATELY)) {
1395:                            if (warnOnDeprecatedConstraints) {
1396:                                env.warn("Use " + name + "=\"${" + value
1397:                                        + "}\" instead.", element);
1398:                            }
1399:                            when = WHEN_ALWAYS;
1400:                        }
1401:                    }
1402:                } else if (type == ViewSchema.EVENT_HANDLER_TYPE) {
1403:                    // Someone said <attribute name="..." ... /> instead of
1404:                    // <event name="..." />
1405:                    throw new CompilationError(
1406:                            element,
1407:                            name,
1408:                            new Throwable(
1409:                                    "'"
1410:                                            + name
1411:                                            + "' is an event and may not be redeclared as an attribute"));
1412:                } else if (type == ViewSchema.REFERENCE_TYPE) {
1413:                    // type="reference" is defined to imply when="once"
1414:                    // since reference expressions are unlikely to
1415:                    // evaluate correctly at when="immediate" time
1416:                    if (when.equals(WHEN_IMMEDIATELY)) {
1417:                        when = WHEN_ONCE;
1418:                    }
1419:                } else if (type == ViewSchema.METHOD_TYPE) {
1420:                    // methods are emitted elsewhere
1421:                } else {
1422:                    throw new RuntimeException("unknown schema datatype "
1423:                            + type);
1424:                }
1425:
1426:                if (canonicalValue == null)
1427:                    canonicalValue = value;
1428:
1429:                // Handle when cases
1430:                // N.B., $path and $style are not really when values, but
1431:                // there you go...
1432:                if (when.equals(WHEN_PATH)) {
1433:                    return new CompiledAttribute(CompiledAttribute.PATH, srcloc
1434:                            + ScriptCompiler.quote(value) + "\n");
1435:                } else if (when.equals(WHEN_STYLE)) {
1436:                    return new CompiledAttribute(CompiledAttribute.STYLE,
1437:                            srcloc + value + "\n");
1438:                } else if (when.equals(WHEN_ONCE)) {
1439:                    return new CompiledAttribute(CompiledAttribute.REFERENCE,
1440:                            "function "
1441:                                    + parent_name
1442:                                    + "_"
1443:                                    + name
1444:                                    + "_once"
1445:                                    + " () {"
1446:                                    + "\n#pragma 'withThis'\n"
1447:                                    +
1448:                                    // Use this.setAttribute so that the compiler
1449:                                    // will recognize it for inlining.
1450:                                    "this.setAttribute("
1451:                                    + ScriptCompiler.quote(name) + " , "
1452:                                    + "\n#beginAttribute\n" + srcloc
1453:                                    + canonicalValue + "\n#endAttribute\n)}");
1454:                } else if (when.equals(WHEN_ALWAYS)) {
1455:                    return new CompiledAttribute(CompiledAttribute.REFERENCE,
1456:                            "function "
1457:                                    + parent_name
1458:                                    + "_"
1459:                                    + name
1460:                                    + "_always"
1461:                                    + " () {"
1462:                                    + "\n#pragma 'constraintFunction'\n"
1463:                                    + "\n#pragma 'withThis'\n"
1464:                                    +
1465:                                    // Use this.setAttribute so that the compiler
1466:                                    // will recognize it for inlining.
1467:                                    "this.setAttribute("
1468:                                    + ScriptCompiler.quote(name) + ", "
1469:                                    + "\n#beginAttribute\n" + srcloc
1470:                                    + canonicalValue + "\n#endAttribute\n)}");
1471:                } else if (when.equals(WHEN_IMMEDIATELY)) {
1472:                    if ((CanvasCompiler.isElement(source) && ("width"
1473:                            .equals(name) || "height".equals(name)))
1474:                            || canonicalValue instanceof  Map) {
1475:                        // The Canvas compiler depends on seeing width/height
1476:                        // unadulterated <sigh />.  Or, if it's already an
1477:                        // object, e.g., compiled from a CSS list, we
1478:                        // don't want to mess it up.
1479:                        //
1480:                        // TODO: [2007-05-05 ptw] (LPP-3949) The
1481:                        // #beginAttribute directives for the parser should
1482:                        // be added when the attribute is written, not
1483:                        // here...
1484:                        return new CompiledAttribute(canonicalValue);
1485:                    } else {
1486:                        return new CompiledAttribute("\n#beginAttribute\n"
1487:                                + srcloc + canonicalValue + "\n#endAttribute\n");
1488:                    }
1489:                } else {
1490:                    throw new CompilationError("invalid when value '" + when
1491:                            + "'", source);
1492:                }
1493:            }
1494:
1495:            /* Handle the <event> tag
1496:             * example: <event name="onfoobar"/>
1497:             */
1498:            void addEventElement(Element element) {
1499:                String name;
1500:                try {
1501:                    name = ElementCompiler.requireIdentifierAttributeValue(
1502:                            element, "name");
1503:                } catch (MissingAttributeException e) {
1504:                    throw new CompilationError(
1505:                    /* (non-Javadoc)
1506:                     * @i18n.test
1507:                     * @org-mes="'name' is a required attribute of <" + p[0] + "> and must be a valid identifier"
1508:                     */
1509:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1510:                            NodeModel.class.getName(), "051018-1157",
1511:                            new Object[] { element.getName() }), element);
1512:                }
1513:
1514:                if (events.containsKey(name, caseSensitive)) {
1515:                    env.warn(
1516:                    /* (non-Javadoc)
1517:                     * @i18n.test
1518:                     * @org-mes="redefining event '" + p[0] + "' which has already been defined on " + p[1]
1519:                     */
1520:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1521:                            NodeModel.class.getName(), "051018-694",
1522:                            new Object[] { name, getMessageName() }), element);
1523:                }
1524:
1525:                // An event is really just an attribute with an implicit
1526:                // default (sentinal) value
1527:                CompiledAttribute cattr = new CompiledAttribute(
1528:                        CompiledAttribute.EVENT, "LzDeclaredEvent");
1529:                addAttribute(cattr, name, attrs, events, references, paths,
1530:                        styles);
1531:            }
1532:
1533:            void addAttributeElement(Element element) {
1534:                String name;
1535:                try {
1536:                    name = ElementCompiler.requireIdentifierAttributeValue(
1537:                            element, "name");
1538:                } catch (MissingAttributeException e) {
1539:                    throw new CompilationError(
1540:                    /* (non-Javadoc)
1541:                     * @i18n.test
1542:                     * @org-mes="'name' is a required attribute of <" + p[0] + "> and must be a valid identifier"
1543:                     */
1544:                    org.openlaszlo.i18n.LaszloMessages.getMessage(
1545:                            NodeModel.class.getName(), "051018-1157",
1546:                            new Object[] { element.getName() }), element);
1547:                }
1548:
1549:                String value = element.getAttributeValue("value");
1550:                String when = element.getAttributeValue("when");
1551:                String typestr = element.getAttributeValue("type");
1552:                Element parent = element.getParentElement();
1553:                String parent_name = parent.getAttributeValue("id");
1554:
1555:                if (parent_name == null) {
1556:                    parent_name = CompilerUtils.attributeUniqueName(element,
1557:                            name);
1558:                }
1559:
1560:                // Default when according to parent
1561:                if (when == null) {
1562:                    when = this .getAttributeValueDefault(name, "when",
1563:                            WHEN_IMMEDIATELY);
1564:                }
1565:
1566:                Schema.Type type = null;
1567:                Schema.Type parenttype = null;
1568:
1569:                AttributeSpec parentAttrSpec = schema.getAttributeSpec(parent
1570:                        .getName(), name);
1571:                boolean forceOverride = parentAttrSpec != null
1572:                        && "true".equals(parentAttrSpec.override);
1573:
1574:                try {
1575:                    if (parent.getName().equals("class")) {
1576:                        parenttype = getAttributeTypeInfoFromSuperclass(parent,
1577:                                name);
1578:                    } else {
1579:                        parenttype = schema.getAttributeType(parent, name);
1580:
1581:                    }
1582:                } catch (UnknownAttributeException e) {
1583:                    // If attribute type is not defined on parent, leave
1584:                    // parenttype null.  The user can define it however they
1585:                    // like.
1586:                }
1587:
1588:                if (typestr == null) {
1589:                    // Did user supply an explicit attribute type?
1590:                    //  No.  Default to parent type if there is one, else
1591:                    // EXPRESSION type.
1592:                    if (parenttype == null) {
1593:                        type = ViewSchema.EXPRESSION_TYPE;
1594:                    } else {
1595:                        type = parenttype;
1596:                    }
1597:                } else {
1598:                    // parse attribute type and compare to parent type
1599:                    type = schema.getTypeForName(typestr);
1600:                    if (type == null) {
1601:                        throw new CompilationError(
1602:                        /* (non-Javadoc)
1603:                         * @i18n.test
1604:                         * @org-mes="unknown attribute type: " + p[0]
1605:                         */
1606:                        org.openlaszlo.i18n.LaszloMessages.getMessage(
1607:                                NodeModel.class.getName(), "051018-1211",
1608:                                new Object[] { typestr }), element);
1609:                    }
1610:
1611:                    // If we are trying to declare the attribute with a
1612:                    // conflicting type to the parent, throw an error
1613:                    if (!forceOverride && parenttype != null
1614:                            && type != parenttype) {
1615:                        env.warn(new CompilationError(element, name,
1616:                                new Throwable(
1617:                                /* (non-Javadoc)
1618:                                 * @i18n.test
1619:                                 * @org-mes="In element '" + p[0] + "' attribute '" + p[1] + "' with type '" + p[2] + "' is overriding parent class attribute with same name but different type: " + p[3]
1620:                                 */
1621:                                org.openlaszlo.i18n.LaszloMessages.getMessage(
1622:                                        NodeModel.class.getName(),
1623:                                        "051018-1227", new Object[] {
1624:                                                parent.getName(), name,
1625:                                                type.toString(),
1626:                                                parenttype.toString() }))));
1627:                    }
1628:                }
1629:
1630:                // Warn if we are overidding a method, handler, or other function
1631:                if (!forceOverride
1632:                        && (parenttype == schema.METHOD_TYPE
1633:                                || parenttype == schema.EVENT_HANDLER_TYPE
1634:                                || parenttype == schema.SETTER_TYPE || parenttype == schema.REFERENCE_TYPE)) {
1635:                    env
1636:                            .warn(
1637:                                    "In element '"
1638:                                            + parent.getName()
1639:                                            + "' attribute '"
1640:                                            + name
1641:                                            + "' is overriding parent class attribute which has the same name but type: "
1642:                                            + parenttype.toString(), element);
1643:                }
1644:
1645:                // Don't initialize an attribute that is only declared.
1646:                if (value != null) {
1647:                    CompiledAttribute cattr = compileAttribute(element, name,
1648:                            value, type, when);
1649:                    addAttribute(cattr, name, attrs, events, references, paths,
1650:                            styles);
1651:                }
1652:
1653:                // Add entry for attribute setter function
1654:                String setter = element.getAttributeValue("setter");
1655:
1656:                if (setter != null) {
1657:                    String srcloc = CompilerUtils.sourceLocationDirective(
1658:                            element, true);
1659:                    // By convention 'anonymous' setters are put in the 'lzc'
1660:                    // namespace with the name set_<property name>
1661:                    String settername = "$lzc$" + "set_" + name;
1662:                    // Maybe we need a new type for "function"?
1663:                    Function setterfn = new Function(settername,
1664:                    // the lone argument to a setter is named after
1665:                            // the attribute
1666:                            name, "\n#beginContent\n"
1667:                                    + "\n#pragma 'withThis'\n" + srcloc
1668:                                    + setter + "\n#endContent", srcloc);
1669:
1670:                    if (setters.get(name) != null) {
1671:                        env.warn(
1672:                                "a setter for attribute named '" + name
1673:                                        + "' is already defined on "
1674:                                        + getMessageName(), element);
1675:                    }
1676:
1677:                    // TODO: [2008-01-21 ptw] some day this will be coalesed
1678:                    // into just creating a method named `"set" + name`
1679:                    attrs.put(settername, setterfn);
1680:                    setters.put(name, ScriptCompiler.quote(settername));
1681:                }
1682:            }
1683:
1684:            /* Handle a <data> tag.
1685:             * If there is more than one immediate child data node at the top level, signal a warning.
1686:             */
1687:
1688:            void addLiteralDataElement(Element element) {
1689:                String name = element.getAttributeValue("name");
1690:
1691:                if (name == null) {
1692:                    name = "initialdata";
1693:                }
1694:
1695:                boolean trimWhitespace = "true".equals(element
1696:                        .getAttributeValue("trimwhitespace"));
1697:
1698:                String xmlcontent = getDatasetContent(element, env,
1699:                        trimWhitespace);
1700:
1701:                Element parent = element.getParentElement();
1702:
1703:                CompiledAttribute cattr = compileAttribute(element, name,
1704:                        xmlcontent, ViewSchema.XML_LITERAL, WHEN_IMMEDIATELY);
1705:
1706:                addAttribute(cattr, name, attrs, events, references, paths,
1707:                        styles);
1708:            }
1709:
1710:            boolean hasAttribute(String name) {
1711:                return attrs.containsKey(name);
1712:            }
1713:
1714:            void removeAttribute(String name) {
1715:                attrs.remove(name);
1716:            }
1717:
1718:            void setAttribute(String name, Object value) {
1719:                attrs.put(name, value);
1720:            }
1721:
1722:            void addText() {
1723:                if (schema.hasHTMLContent(element)) {
1724:                    String text = TextCompiler.getHTMLContent(element);
1725:                    if (text.length() != 0) {
1726:                        if (!attrs.containsKey("text")) {
1727:                            attrs.put("text", ScriptCompiler.quote(text));
1728:                        }
1729:                    }
1730:                } else if (schema.hasTextContent(element)) {
1731:                    String text;
1732:                    // The current inputtext component doesn't understand
1733:                    // HTML, but we'd like to have some way to enter
1734:                    // linebreaks in the source.
1735:                    text = TextCompiler.getInputText(element);
1736:                    if (text.length() != 0) {
1737:                        if (!attrs.containsKey("text")) {
1738:                            attrs.put("text", ScriptCompiler.quote(text));
1739:                        }
1740:                    }
1741:                }
1742:            }
1743:
1744:            void updateAttrs() {
1745:                if (!setters.isEmpty()) {
1746:                    attrs.put("$setters", setters);
1747:                }
1748:                if (!delegateList.isEmpty()) {
1749:                    attrs.put("$delegates", delegateList);
1750:                }
1751:                if (!references.isEmpty()) {
1752:                    attrs.put("$refs", references);
1753:                }
1754:                if (!paths.isEmpty()) {
1755:                    attrs.put("$paths", paths);
1756:                }
1757:                if (datapath != null) {
1758:                    attrs.put("$datapath", datapath.asMap());
1759:                    // If we've got an explicit datapath value, we have to
1760:                    // null out the "datapath" attribute with the magic
1761:                    // LzNode._ignoreAttribute value, so it doesn't get
1762:                    // overridden by an inherited value from the class.
1763:                    attrs.put("datapath", "LzNode._ignoreAttribute");
1764:                }
1765:
1766:                if (!styles.isEmpty()) {
1767:                    String styleMap;
1768:                    try {
1769:                        java.io.Writer writer = new java.io.StringWriter();
1770:                        ScriptCompiler.writeObject(styles, writer);
1771:                        styleMap = writer.toString();
1772:                    } catch (java.io.IOException e) {
1773:                        throw new ChainedException(e);
1774:                    }
1775:                    // NOTE: [2006-09-04 ptw] The $styles method _must_ create
1776:                    // a new map each time, because the sub-class or instance
1777:                    // may modify it.
1778:                    attrs.put("$styles", new Function("", "", "\n#beginContent"
1779:                            + "\n#pragma 'withThis'"
1780:                            + "\n#pragma 'methodName=$styles'"
1781:                            + "\nvar map = super.$styles() || (new Object);"
1782:                            + "\nvar s = " + styleMap + ";"
1783:                            + "\nfor (var k in s) { map[k] = s[k]; };"
1784:                            + "\nreturn map;" + "\n#endContent" + "\n"));
1785:                }
1786:            }
1787:
1788:            Map asMap() {
1789:                Map map = new LinkedHashMap();
1790:                updateAttrs();
1791:                map.put("name", ScriptCompiler.quote(className));
1792:                map.put("attrs", attrs);
1793:                if (id != null) {
1794:                    map.put("id", ScriptCompiler.quote(id));
1795:                    attrs.put("id", ScriptCompiler.quote(id));
1796:                }
1797:                if (!children.isEmpty()) {
1798:                    List childMaps = new Vector(children.size());
1799:                    for (Iterator iter = children.iterator(); iter.hasNext();)
1800:                        childMaps.add(((NodeModel) iter.next()).asMap());
1801:                    map.put("children", childMaps);
1802:                }
1803:                return map;
1804:            }
1805:
1806:            /** Expand eligible instances by replacing the instance by the
1807:             * merge of its class definition with the instance content
1808:             * (attributes and children).  An eligible instance is an instance
1809:             * of a compile-time class, that doesn't contain any merge
1810:             * stoppers.  If the class and the instance contain a member with
1811:             * the same name, this is a merge stopper.  In the future, this
1812:             * restriction may be relaxed, but will probably always include
1813:             * the case where a class and instance have a member with the same
1814:             * name and the instance name calls a superclass method. */
1815:            NodeModel expandClassDefinitions() {
1816:                NodeModel model = this ;
1817:                while (true) {
1818:                    ClassModel classModel = schema
1819:                            .getClassModel(model.className);
1820:                    if (classModel == null)
1821:                        break;
1822:                    if (classModel.getSuperclassName() == null)
1823:                        break;
1824:                    if (!classModel.getInline())
1825:                        break;
1826:                    model = classModel.applyClass(model);
1827:                    // Iterate to allow for the original classes superclass to
1828:                    // be expanded as well.
1829:                }
1830:                // Recurse. Make a copy so we can replace the child list.
1831:                // TODO [2004-0604]: As an optimization, only do this if one
1832:                // of the children changed.
1833:                model = (NodeModel) model.clone();
1834:                for (ListIterator iter = model.children.listIterator(); iter
1835:                        .hasNext();) {
1836:                    NodeModel child = (NodeModel) iter.next();
1837:                    iter.set(child.expandClassDefinitions());
1838:                }
1839:                return model;
1840:            }
1841:
1842:            /** Replace members of this with like-named members of source. */
1843:            void updateMembers(NodeModel source) {
1844:                final String OPTIONS_ATTR_NAME = "options";
1845:
1846:                // FIXME [2004-06-04]: only compare events with the same reference
1847:                if (CollectionUtils.containsAny(events.normalizedKeySet(),
1848:                        source.events.normalizedKeySet())) {
1849:                    Collection sharedEvents = CollectionUtils.intersection(
1850:                            events.normalizedKeySet(), source.events
1851:                                    .normalizedKeySet());
1852:                    throw new CompilationError(
1853:                            /* (non-Javadoc)
1854:                             * @i18n.test
1855:                             * @org-mes="Both the class and the instance or subclass define the " + p[0] + p[1]
1856:                             */
1857:                            org.openlaszlo.i18n.LaszloMessages
1858:                                    .getMessage(
1859:                                            NodeModel.class.getName(),
1860:                                            "051018-1388",
1861:                                            new Object[] {
1862:                                                    new ChoiceFormat(
1863:                                                            "1#event |1<events ")
1864:                                                            .format(sharedEvents
1865:                                                                    .size()),
1866:                                                    new ListFormat("and")
1867:                                                            .format(sharedEvents) }));
1868:
1869:                }
1870:
1871:                // Check for duplicate methods.  Collect all the keys that name
1872:                // a Function in both the source and target.
1873:                List sharedMethods = new Vector();
1874:                for (Iterator iter = attrs.normalizedKeySet().iterator(); iter
1875:                        .hasNext();) {
1876:                    String key = (String) iter.next();
1877:                    if (attrs.get(key) instanceof  Function
1878:                            && source.attrs.get(key) instanceof  Function)
1879:                        sharedMethods.add(key);
1880:                }
1881:                if (!sharedMethods.isEmpty())
1882:                    throw new CompilationError(
1883:                    /* (non-Javadoc)
1884:                     * @i18n.test
1885:                     * @org-mes="Both the class and the instance or subclass define the method" + p[0] + p[1]
1886:                     */
1887:                    org.openlaszlo.i18n.LaszloMessages
1888:                            .getMessage(NodeModel.class.getName(),
1889:                                    "051018-1409", new Object[] {
1890:                                            new ChoiceFormat("1# |1<s ")
1891:                                                    .format(sharedMethods
1892:                                                            .size()),
1893:                                            new ListFormat("and")
1894:                                                    .format(sharedMethods) }));
1895:
1896:                // Check for attributes that have a value in this and
1897:                // a setter in the source.  These can't be merged.
1898:                Collection overriddenAttributes = CollectionUtils.intersection(
1899:                        attrs.normalizedKeySet(), source.setters
1900:                                .normalizedKeySet());
1901:                if (!overriddenAttributes.isEmpty())
1902:                    throw new CompilationError(
1903:                            /* (non-Javadoc)
1904:                             * @i18n.test
1905:                             * @org-mes="A class that defines a value can't be inlined against a " + "subclass or instance that defines a setter.  The following " + p[0] + " this condition: " + p[1]
1906:                             */
1907:                            org.openlaszlo.i18n.LaszloMessages
1908:                                    .getMessage(
1909:                                            NodeModel.class.getName(),
1910:                                            "051018-1422",
1911:                                            new Object[] {
1912:                                                    new ChoiceFormat(
1913:                                                            "1#attribute violates|1<attributes violate")
1914:                                                            .format(overriddenAttributes
1915:                                                                    .size()),
1916:                                                    new ListFormat("and")
1917:                                                            .format(overriddenAttributes) }));
1918:
1919:                // Do the actual merge.
1920:                id = source.id;
1921:                if (source.initstage != null)
1922:                    initstage = source.initstage;
1923:                Object options = attrs.get(OPTIONS_ATTR_NAME);
1924:                Object sourceOptions = source.attrs.get(OPTIONS_ATTR_NAME);
1925:                attrs.putAll(source.attrs);
1926:                if (options instanceof  Map && sourceOptions instanceof  Map) {
1927:                    //             System.err.println(options);
1928:                    //             System.err.println(sourceOptions);
1929:                    Map newOptions = new HashMap((Map) options);
1930:                    newOptions.putAll((Map) sourceOptions);
1931:                    attrs.put(OPTIONS_ATTR_NAME, newOptions);
1932:                }
1933:                delegates.putAll(source.delegates);
1934:                events.putAll(source.events);
1935:                references.putAll(source.references);
1936:                paths.putAll(source.paths);
1937:                setters.putAll(source.setters);
1938:                styles.putAll(source.styles);
1939:                delegateList.addAll(source.delegateList);
1940:                // TBD: warn on children that share a name?
1941:                // TBD: update the node count
1942:                children.addAll(source.children);
1943:            }
1944:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.